From 9d32db51eaf4882fe8250a594e1506e56b4ddf16 Mon Sep 17 00:00:00 2001 From: David Simansky Date: Mon, 3 Jul 2023 12:03:56 +0200 Subject: [PATCH] [release-v1.9] Add correct version of workflow-plugin (#187) * [release-v1.9] Add correct version of workflow-plugin * Update vendor dir * Fix strange unit tests init fail * Update workflow-plugin quarkus & dev image LD flags --- go.mod | 31 +- go.sum | 568 +- hack/build.sh.d/kn-plugin-workflow.sh | 4 +- lib/test/{ => e2e}/service.go | 25 +- pkg/kn/commands/service/export_test.go | 2 +- pkg/serving/v1/gitops_test.go | 2 +- test/e2e/basic_workflow_test.go | 21 +- test/e2e/domain_mapping_test.go | 5 +- test/e2e/extra_containers_test.go | 5 +- test/e2e/ping_test.go | 5 +- test/e2e/revision_test.go | 19 +- test/e2e/route_test.go | 5 +- test/e2e/service_export_test.go | 129 +- test/e2e/service_import_test.go | 7 +- test/e2e/service_options_test.go | 65 +- test/e2e/service_test.go | 15 +- test/e2e/sinkprefix_test.go | 3 +- test/e2e/source_apiserver_test.go | 5 +- test/e2e/source_binding_test.go | 5 +- test/e2e/source_container_test.go | 5 +- test/e2e/source_list_test.go | 3 +- test/e2e/subscription_test.go | 17 +- test/e2e/traffic_split_test.go | 161 +- test/e2e/trigger_inject_broker_test.go | 5 +- test/e2e/trigger_test.go | 5 +- .../Microsoft/go-winio/.gitattributes | 1 + .../github.com/Microsoft/go-winio/.gitignore | 10 + .../Microsoft/go-winio/.golangci.yml | 149 + .../github.com/Microsoft/go-winio/CODEOWNERS | 1 + vendor/github.com/Microsoft/go-winio/LICENSE | 22 + .../github.com/Microsoft/go-winio/README.md | 89 + .../github.com/Microsoft/go-winio/SECURITY.md | 41 + .../github.com/Microsoft/go-winio/backup.go | 290 + vendor/github.com/Microsoft/go-winio/doc.go | 22 + vendor/github.com/Microsoft/go-winio/ea.go | 137 + vendor/github.com/Microsoft/go-winio/file.go | 331 + .../github.com/Microsoft/go-winio/fileinfo.go | 92 + .../github.com/Microsoft/go-winio/hvsock.go | 575 + .../Microsoft/go-winio/internal/fs/doc.go | 2 + .../Microsoft/go-winio/internal/fs/fs.go | 202 + .../go-winio/internal/fs/security.go | 12 + .../go-winio/internal/fs/zsyscall_windows.go | 64 + .../go-winio/internal/socket/rawaddr.go | 20 + .../go-winio/internal/socket/socket.go | 179 + .../internal/socket/zsyscall_windows.go | 72 + .../go-winio/internal/stringbuffer/wstring.go | 132 + vendor/github.com/Microsoft/go-winio/pipe.go | 525 + .../Microsoft/go-winio/pkg/guid/guid.go | 232 + .../go-winio/pkg/guid/guid_nonwindows.go | 16 + .../go-winio/pkg/guid/guid_windows.go | 13 + .../go-winio/pkg/guid/variant_string.go | 27 + .../Microsoft/go-winio/privilege.go | 197 + .../github.com/Microsoft/go-winio/reparse.go | 131 + vendor/github.com/Microsoft/go-winio/sd.go | 144 + .../github.com/Microsoft/go-winio/syscall.go | 5 + vendor/github.com/Microsoft/go-winio/tools.go | 5 + .../Microsoft/go-winio/zsyscall_windows.go | 419 + vendor/github.com/docker/distribution/LICENSE | 202 + .../docker/distribution/digestset/set.go | 247 + .../docker/distribution/reference/helpers.go | 42 + .../distribution/reference/normalize.go | 199 + .../distribution/reference/reference.go | 433 + .../docker/distribution/reference/regexp.go | 143 + vendor/github.com/docker/docker/AUTHORS | 2372 +++ vendor/github.com/docker/docker/LICENSE | 191 + vendor/github.com/docker/docker/NOTICE | 19 + vendor/github.com/docker/docker/api/README.md | 42 + vendor/github.com/docker/docker/api/common.go | 11 + .../docker/docker/api/common_unix.go | 7 + .../docker/docker/api/common_windows.go | 8 + .../docker/docker/api/swagger-gen.yaml | 12 + .../github.com/docker/docker/api/swagger.yaml | 12152 ++++++++++++++++ .../docker/docker/api/types/auth.go | 22 + .../docker/docker/api/types/blkiodev/blkio.go | 23 + .../docker/docker/api/types/client.go | 443 + .../docker/docker/api/types/configs.go | 67 + .../docker/api/types/container/config.go | 96 + .../api/types/container/container_changes.go | 20 + .../api/types/container/container_top.go | 22 + .../api/types/container/container_update.go | 16 + .../api/types/container/create_response.go | 19 + .../docker/api/types/container/deprecated.go | 16 + .../docker/api/types/container/host_config.go | 465 + .../api/types/container/hostconfig_unix.go | 42 + .../api/types/container/hostconfig_windows.go | 40 + .../api/types/container/wait_exit_error.go | 12 + .../api/types/container/wait_response.go | 18 + .../api/types/container/waitcondition.go | 22 + .../docker/docker/api/types/deprecated.go | 14 + .../docker/docker/api/types/error_response.go | 13 + .../docker/api/types/error_response_ext.go | 6 + .../docker/docker/api/types/events/events.go | 47 + .../docker/docker/api/types/filters/parse.go | 323 + .../docker/api/types/graph_driver_data.go | 23 + .../docker/docker/api/types/id_response.go | 13 + .../docker/api/types/image/image_history.go | 36 + .../api/types/image_delete_response_item.go | 15 + .../docker/docker/api/types/image_summary.go | 97 + .../docker/docker/api/types/mount/mount.go | 140 + .../docker/api/types/network/network.go | 126 + .../docker/docker/api/types/plugin.go | 203 + .../docker/docker/api/types/plugin_device.go | 25 + .../docker/docker/api/types/plugin_env.go | 25 + .../docker/api/types/plugin_interface_type.go | 21 + .../docker/docker/api/types/plugin_mount.go | 37 + .../docker/api/types/plugin_responses.go | 71 + .../docker/docker/api/types/port.go | 23 + .../docker/api/types/registry/authenticate.go | 21 + .../docker/api/types/registry/registry.go | 120 + .../api/types/service_update_response.go | 12 + .../docker/docker/api/types/stats.go | 181 + .../docker/api/types/strslice/strslice.go | 30 + .../docker/docker/api/types/swarm/common.go | 48 + .../docker/docker/api/types/swarm/config.go | 40 + .../docker/api/types/swarm/container.go | 80 + .../docker/docker/api/types/swarm/network.go | 121 + .../docker/docker/api/types/swarm/node.go | 139 + .../docker/docker/api/types/swarm/runtime.go | 27 + .../docker/api/types/swarm/runtime/gen.go | 3 + .../api/types/swarm/runtime/plugin.pb.go | 754 + .../api/types/swarm/runtime/plugin.proto | 21 + .../docker/docker/api/types/swarm/secret.go | 36 + .../docker/docker/api/types/swarm/service.go | 202 + .../docker/docker/api/types/swarm/swarm.go | 237 + .../docker/docker/api/types/swarm/task.go | 225 + .../docker/docker/api/types/time/timestamp.go | 131 + .../docker/docker/api/types/types.go | 809 + .../docker/api/types/versions/README.md | 14 + .../docker/api/types/versions/compare.go | 65 + .../docker/api/types/volume/cluster_volume.go | 420 + .../docker/api/types/volume/create_options.go | 29 + .../docker/api/types/volume/deprecated.go | 11 + .../docker/api/types/volume/list_response.go | 18 + .../docker/docker/api/types/volume/options.go | 8 + .../docker/docker/api/types/volume/volume.go | 75 + .../docker/api/types/volume/volume_update.go | 7 + .../github.com/docker/docker/client/README.md | 35 + .../docker/docker/client/build_cancel.go | 16 + .../docker/docker/client/build_prune.go | 45 + .../docker/docker/client/checkpoint_create.go | 14 + .../docker/docker/client/checkpoint_delete.go | 20 + .../docker/docker/client/checkpoint_list.go | 28 + .../github.com/docker/docker/client/client.go | 321 + .../docker/docker/client/client_deprecated.go | 27 + .../docker/docker/client/client_unix.go | 11 + .../docker/docker/client/client_windows.go | 8 + .../docker/docker/client/config_create.go | 25 + .../docker/docker/client/config_inspect.go | 36 + .../docker/docker/client/config_list.go | 38 + .../docker/docker/client/config_remove.go | 13 + .../docker/docker/client/config_update.go | 20 + .../docker/docker/client/container_attach.go | 59 + .../docker/docker/client/container_commit.go | 55 + .../docker/docker/client/container_copy.go | 93 + .../docker/docker/client/container_create.go | 83 + .../docker/docker/client/container_diff.go | 23 + .../docker/docker/client/container_exec.go | 66 + .../docker/docker/client/container_export.go | 19 + .../docker/docker/client/container_inspect.go | 53 + .../docker/docker/client/container_kill.go | 18 + .../docker/docker/client/container_list.go | 57 + .../docker/docker/client/container_logs.go | 80 + .../docker/docker/client/container_pause.go | 10 + .../docker/docker/client/container_prune.go | 36 + .../docker/docker/client/container_remove.go | 27 + .../docker/docker/client/container_rename.go | 15 + .../docker/docker/client/container_resize.go | 29 + .../docker/docker/client/container_restart.go | 26 + .../docker/docker/client/container_start.go | 23 + .../docker/docker/client/container_stats.go | 42 + .../docker/docker/client/container_stop.go | 30 + .../docker/docker/client/container_top.go | 28 + .../docker/docker/client/container_unpause.go | 10 + .../docker/docker/client/container_update.go | 21 + .../docker/docker/client/container_wait.go | 104 + .../docker/docker/client/disk_usage.go | 33 + .../docker/client/distribution_inspect.go | 38 + .../docker/docker/client/envvars.go | 90 + .../github.com/docker/docker/client/errors.go | 93 + .../github.com/docker/docker/client/events.go | 101 + .../github.com/docker/docker/client/hijack.go | 153 + .../docker/docker/client/image_build.go | 146 + .../docker/docker/client/image_create.go | 37 + .../docker/docker/client/image_history.go | 22 + .../docker/docker/client/image_import.go | 40 + .../docker/docker/client/image_inspect.go | 32 + .../docker/docker/client/image_list.go | 49 + .../docker/docker/client/image_load.go | 29 + .../docker/docker/client/image_prune.go | 36 + .../docker/docker/client/image_pull.go | 64 + .../docker/docker/client/image_push.go | 54 + .../docker/docker/client/image_remove.go | 31 + .../docker/docker/client/image_save.go | 21 + .../docker/docker/client/image_search.go | 53 + .../docker/docker/client/image_tag.go | 37 + .../github.com/docker/docker/client/info.go | 26 + .../docker/docker/client/interface.go | 201 + .../docker/client/interface_experimental.go | 18 + .../docker/docker/client/interface_stable.go | 10 + .../github.com/docker/docker/client/login.go | 25 + .../docker/docker/client/network_connect.go | 19 + .../docker/docker/client/network_create.go | 25 + .../docker/client/network_disconnect.go | 15 + .../docker/docker/client/network_inspect.go | 49 + .../docker/docker/client/network_list.go | 32 + .../docker/docker/client/network_prune.go | 36 + .../docker/docker/client/network_remove.go | 10 + .../docker/docker/client/node_inspect.go | 32 + .../docker/docker/client/node_list.go | 36 + .../docker/docker/client/node_remove.go | 20 + .../docker/docker/client/node_update.go | 17 + .../docker/docker/client/options.go | 210 + .../github.com/docker/docker/client/ping.go | 75 + .../docker/docker/client/plugin_create.go | 23 + .../docker/docker/client/plugin_disable.go | 19 + .../docker/docker/client/plugin_enable.go | 19 + .../docker/docker/client/plugin_inspect.go | 31 + .../docker/docker/client/plugin_install.go | 113 + .../docker/docker/client/plugin_list.go | 33 + .../docker/docker/client/plugin_push.go | 16 + .../docker/docker/client/plugin_remove.go | 20 + .../docker/docker/client/plugin_set.go | 12 + .../docker/docker/client/plugin_upgrade.go | 39 + .../docker/docker/client/request.go | 277 + .../docker/docker/client/secret_create.go | 25 + .../docker/docker/client/secret_inspect.go | 36 + .../docker/docker/client/secret_list.go | 38 + .../docker/docker/client/secret_remove.go | 13 + .../docker/docker/client/secret_update.go | 20 + .../docker/docker/client/service_create.go | 178 + .../docker/docker/client/service_inspect.go | 37 + .../docker/docker/client/service_list.go | 39 + .../docker/docker/client/service_logs.go | 52 + .../docker/docker/client/service_remove.go | 10 + .../docker/docker/client/service_update.go | 74 + .../docker/client/swarm_get_unlock_key.go | 21 + .../docker/docker/client/swarm_init.go | 21 + .../docker/docker/client/swarm_inspect.go | 21 + .../docker/docker/client/swarm_join.go | 14 + .../docker/docker/client/swarm_leave.go | 17 + .../docker/docker/client/swarm_unlock.go | 14 + .../docker/docker/client/swarm_update.go | 21 + .../docker/docker/client/task_inspect.go | 32 + .../docker/docker/client/task_list.go | 35 + .../docker/docker/client/task_logs.go | 51 + .../docker/docker/client/transport.go | 17 + .../github.com/docker/docker/client/utils.go | 34 + .../docker/docker/client/version.go | 21 + .../docker/docker/client/volume_create.go | 20 + .../docker/docker/client/volume_inspect.go | 38 + .../docker/docker/client/volume_list.go | 33 + .../docker/docker/client/volume_prune.go | 36 + .../docker/docker/client/volume_remove.go | 21 + .../docker/docker/client/volume_update.go | 24 + .../github.com/docker/docker/errdefs/defs.go | 69 + .../github.com/docker/docker/errdefs/doc.go | 8 + .../docker/docker/errdefs/helpers.go | 279 + .../docker/docker/errdefs/http_helpers.go | 46 + vendor/github.com/docker/docker/errdefs/is.go | 107 + .../github.com/docker/go-connections/LICENSE | 191 + .../docker/go-connections/nat/nat.go | 242 + .../docker/go-connections/nat/parse.go | 57 + .../docker/go-connections/nat/sort.go | 96 + .../docker/go-connections/sockets/README.md | 0 .../go-connections/sockets/inmem_socket.go | 81 + .../docker/go-connections/sockets/proxy.go | 51 + .../docker/go-connections/sockets/sockets.go | 38 + .../go-connections/sockets/sockets_unix.go | 35 + .../go-connections/sockets/sockets_windows.go | 27 + .../go-connections/sockets/tcp_socket.go | 22 + .../go-connections/sockets/unix_socket.go | 32 + .../go-connections/tlsconfig/certpool_go17.go | 18 + .../tlsconfig/certpool_other.go | 13 + .../docker/go-connections/tlsconfig/config.go | 254 + .../tlsconfig/config_client_ciphers.go | 17 + .../tlsconfig/config_legacy_client_ciphers.go | 15 + .../docker/go-units/CONTRIBUTING.md | 67 + vendor/github.com/docker/go-units/LICENSE | 191 + vendor/github.com/docker/go-units/MAINTAINERS | 46 + vendor/github.com/docker/go-units/README.md | 16 + vendor/github.com/docker/go-units/circle.yml | 11 + vendor/github.com/docker/go-units/duration.go | 35 + vendor/github.com/docker/go-units/size.go | 154 + vendor/github.com/docker/go-units/ulimit.go | 123 + vendor/github.com/dprotaso/go-yit/.gitignore | 15 + vendor/github.com/dprotaso/go-yit/LICENSE | 19 + vendor/github.com/dprotaso/go-yit/README.md | 54 + .../github.com/dprotaso/go-yit/aggregates.go | 25 + vendor/github.com/dprotaso/go-yit/iterator.go | 204 + .../github.com/dprotaso/go-yit/predicates.go | 117 + .../go-playground/locales/.gitignore | 24 + .../go-playground/locales/.travis.yml | 26 + .../github.com/go-playground/locales/LICENSE | 21 + .../go-playground/locales/README.md | 172 + .../locales/currency/currency.go | 311 + .../github.com/go-playground/locales/logo.png | Bin 0 -> 37360 bytes .../github.com/go-playground/locales/rules.go | 293 + .../universal-translator/.gitignore | 25 + .../universal-translator/.travis.yml | 27 + .../universal-translator/LICENSE | 21 + .../universal-translator/Makefile | 18 + .../universal-translator/README.md | 89 + .../universal-translator/errors.go | 148 + .../universal-translator/import_export.go | 276 + .../universal-translator/logo.png | Bin 0 -> 16598 bytes .../universal-translator/translator.go | 420 + .../universal_translator.go | 113 + .../go-playground/validator/v10/.gitignore | 30 + .../go-playground/validator/v10/LICENSE | 22 + .../validator/v10/MAINTAINERS.md | 16 + .../go-playground/validator/v10/Makefile | 18 + .../go-playground/validator/v10/README.md | 338 + .../go-playground/validator/v10/baked_in.go | 2526 ++++ .../go-playground/validator/v10/cache.go | 327 + .../validator/v10/country_codes.go | 1132 ++ .../validator/v10/currency_codes.go | 79 + .../go-playground/validator/v10/doc.go | 1401 ++ .../go-playground/validator/v10/errors.go | 275 + .../validator/v10/field_level.go | 120 + .../go-playground/validator/v10/logo.png | Bin 0 -> 13443 bytes .../validator/v10/postcode_regexes.go | 173 + .../go-playground/validator/v10/regexes.go | 131 + .../validator/v10/struct_level.go | 175 + .../validator/v10/translations.go | 11 + .../go-playground/validator/v10/util.go | 288 + .../go-playground/validator/v10/validator.go | 486 + .../validator/v10/validator_instance.go | 699 + .../kn-plugin-workflow/pkg/command/create.go | 126 +- .../kn-plugin-workflow/pkg/command/deploy.go | 140 +- .../pkg/command/deploy_undeploy_common.go | 191 + .../pkg/command/{ => quarkus}/build.go | 39 +- .../pkg/command/quarkus/convert.go | 234 + .../pkg/command/quarkus/create.go | 151 + .../pkg/command/quarkus/deploy.go | 128 + .../pkg/command/quarkus/quarkus.go | 40 + .../pkg/command/quarkus/quarkus_project.go | 56 + .../pkg/command/quarkus/run.go | 113 + .../kn-plugin-workflow/pkg/command/run.go | 134 + .../pkg/command/undeploy.go | 134 + .../kn-plugin-workflow/pkg/command/version.go | 1 - .../kn-plugin-workflow/pkg/common/afero.go | 4 +- .../kn-plugin-workflow/pkg/common/browser.go | 40 + .../kn-plugin-workflow/pkg/common/checks.go | 69 +- .../pkg/common/containers.go | 137 + .../{command => common}/create_workflow.go | 34 +- .../kn-plugin-workflow/pkg/common/exec.go | 3 +- .../kn-plugin-workflow/pkg/common/helper.go | 3 +- .../kn-plugin-workflow/pkg/common/io.go | 66 + .../kn-plugin-workflow/pkg/common/kubectl.go | 67 + .../kn-plugin-workflow/pkg/common/operator.go | 159 + .../pkg/common/readyCheck.go | 56 + .../pkg/metadata/constants.go | 40 +- .../pkg/metadata/devModeImage.go | 19 + .../pkg/metadata/quarkus.go | 3 +- .../kn-plugin-workflow/pkg/root/root.go | 13 +- .../kn-plugin-workflow/plugin/plugin.go | 2 +- .../kogito-serverless-operator/api/LICENSE | 201 + .../kogito-serverless-operator/api/Makefile | 3 + .../api/condition_types.go | 104 + .../api/metadata/annotations.go | 42 + .../api/status_types.go | 324 + .../api/v1alpha08/conversion.go | 166 + .../api/v1alpha08/groupversion_info.go | 39 + .../api/v1alpha08/sonataflow_types.go | 210 + .../api/v1alpha08/sonataflowbuild_types.go | 128 + .../api/v1alpha08/sonataflowplatform_types.go | 231 + .../sonataflowplatform_types_support.go | 164 + .../api/v1alpha08/zz_generated.deepcopy.go | 549 + .../api/zz_generated.deepcopy.go | 79 + .../workflowproj/LICENSE | 201 + .../workflowproj/Makefile | 21 + .../workflowproj/README.md | 62 + .../workflowproj/camelschema.go | 19 + .../workflowproj/io.go | 59 + .../workflowproj/operator.go | 91 + .../workflowproj/resources.go | 68 + .../workflowproj/workflowproj.go | 286 + vendor/github.com/leodido/go-urn/.gitignore | 11 + vendor/github.com/leodido/go-urn/.travis.yml | 16 + vendor/github.com/leodido/go-urn/LICENSE | 21 + vendor/github.com/leodido/go-urn/README.md | 55 + vendor/github.com/leodido/go-urn/machine.go | 1691 +++ .../github.com/leodido/go-urn/machine.go.rl | 159 + vendor/github.com/leodido/go-urn/makefile | 39 + vendor/github.com/leodido/go-urn/urn.go | 86 + .../opencontainers/image-spec/LICENSE | 191 + .../image-spec/specs-go/v1/annotations.go | 62 + .../image-spec/specs-go/v1/config.go | 114 + .../image-spec/specs-go/v1/descriptor.go | 64 + .../image-spec/specs-go/v1/index.go | 32 + .../image-spec/specs-go/v1/layout.go | 28 + .../image-spec/specs-go/v1/manifest.go | 35 + .../image-spec/specs-go/v1/mediatype.go | 57 + .../image-spec/specs-go/version.go | 32 + .../image-spec/specs-go/versioned.go | 23 + vendor/github.com/pb33f/libopenapi/LICENSE | 23 + vendor/github.com/pb33f/libopenapi/README.md | 78 + .../pb33f/libopenapi/datamodel/constants.go | 59 + .../libopenapi/datamodel/document_config.go | 41 + .../libopenapi/datamodel/high/base/base.go | 12 + .../libopenapi/datamodel/high/base/contact.go | 52 + .../datamodel/high/base/discriminator.go | 58 + .../datamodel/high/base/dynamic_value.go | 101 + .../libopenapi/datamodel/high/base/example.go | 65 + .../datamodel/high/base/external_doc.go | 61 + .../libopenapi/datamodel/high/base/info.go | 81 + .../libopenapi/datamodel/high/base/license.go | 53 + .../libopenapi/datamodel/high/base/schema.go | 484 + .../datamodel/high/base/schema_proxy.go | 177 + .../high/base/security_requirement.go | 135 + .../libopenapi/datamodel/high/base/tag.go | 74 + .../libopenapi/datamodel/high/base/xml.go | 64 + .../libopenapi/datamodel/high/node_builder.go | 655 + .../pb33f/libopenapi/datamodel/high/shared.go | 78 + .../datamodel/high/v2/definitions.go | 40 + .../libopenapi/datamodel/high/v2/examples.go | 33 + .../libopenapi/datamodel/high/v2/header.go | 106 + .../libopenapi/datamodel/high/v2/items.go | 100 + .../libopenapi/datamodel/high/v2/operation.go | 103 + .../libopenapi/datamodel/high/v2/parameter.go | 155 + .../high/v2/parameter_definitions.go | 51 + .../libopenapi/datamodel/high/v2/path_item.go | 140 + .../libopenapi/datamodel/high/v2/paths.go | 53 + .../libopenapi/datamodel/high/v2/response.go | 51 + .../libopenapi/datamodel/high/v2/responses.go | 61 + .../high/v2/responses_definitions.go | 52 + .../libopenapi/datamodel/high/v2/scopes.go | 34 + .../datamodel/high/v2/security_definitions.go | 34 + .../datamodel/high/v2/security_scheme.go | 66 + .../libopenapi/datamodel/high/v2/swagger.go | 181 + .../libopenapi/datamodel/high/v3/callback.go | 112 + .../datamodel/high/v3/components.go | 190 + .../libopenapi/datamodel/high/v3/document.go | 171 + .../libopenapi/datamodel/high/v3/encoding.go | 64 + .../libopenapi/datamodel/high/v3/header.go | 85 + .../libopenapi/datamodel/high/v3/link.go | 74 + .../datamodel/high/v3/media_type.go | 102 + .../datamodel/high/v3/oauth_flow.go | 58 + .../datamodel/high/v3/oauth_flows.go | 66 + .../libopenapi/datamodel/high/v3/operation.go | 119 + .../libopenapi/datamodel/high/v3/parameter.go | 128 + .../libopenapi/datamodel/high/v3/path_item.go | 183 + .../libopenapi/datamodel/high/v3/paths.go | 186 + .../datamodel/high/v3/request_body.go | 65 + .../libopenapi/datamodel/high/v3/response.go | 78 + .../libopenapi/datamodel/high/v3/responses.go | 213 + .../datamodel/high/v3/security_scheme.go | 72 + .../libopenapi/datamodel/high/v3/server.go | 56 + .../datamodel/high/v3/server_variable.go | 58 + .../libopenapi/datamodel/low/base/base.go | 12 + .../datamodel/low/base/constants.go | 54 + .../libopenapi/datamodel/low/base/contact.go | 45 + .../datamodel/low/base/discriminator.go | 55 + .../libopenapi/datamodel/low/base/example.go | 132 + .../datamodel/low/base/external_doc.go | 60 + .../libopenapi/datamodel/low/base/info.go | 95 + .../libopenapi/datamodel/low/base/license.go | 39 + .../libopenapi/datamodel/low/base/schema.go | 1275 ++ .../datamodel/low/base/schema_proxy.go | 150 + .../low/base/security_requirement.go | 104 + .../libopenapi/datamodel/low/base/tag.go | 94 + .../libopenapi/datamodel/low/base/xml.go | 70 + .../datamodel/low/extraction_functions.go | 689 + .../pb33f/libopenapi/datamodel/low/low.go | 14 + .../libopenapi/datamodel/low/model_builder.go | 487 + .../datamodel/low/model_interfaces.go | 124 + .../libopenapi/datamodel/low/reference.go | 375 + .../libopenapi/datamodel/low/serializing.go | 4 + .../libopenapi/datamodel/low/v2/constants.go | 25 + .../datamodel/low/v2/definitions.go | 266 + .../libopenapi/datamodel/low/v2/examples.go | 92 + .../libopenapi/datamodel/low/v2/header.go | 213 + .../libopenapi/datamodel/low/v2/items.go | 209 + .../libopenapi/datamodel/low/v2/operation.go | 216 + .../libopenapi/datamodel/low/v2/parameter.go | 282 + .../libopenapi/datamodel/low/v2/path_item.go | 230 + .../libopenapi/datamodel/low/v2/paths.go | 142 + .../libopenapi/datamodel/low/v2/response.go | 100 + .../libopenapi/datamodel/low/v2/responses.go | 118 + .../libopenapi/datamodel/low/v2/scopes.go | 84 + .../datamodel/low/v2/security_scheme.go | 87 + .../libopenapi/datamodel/low/v2/swagger.go | 297 + .../libopenapi/datamodel/low/v3/callback.go | 101 + .../libopenapi/datamodel/low/v3/components.go | 284 + .../libopenapi/datamodel/low/v3/constants.go | 140 + .../datamodel/low/v3/create_document.go | 245 + .../libopenapi/datamodel/low/v3/document.go | 125 + .../libopenapi/datamodel/low/v3/encoding.go | 74 + .../libopenapi/datamodel/low/v3/header.go | 192 + .../pb33f/libopenapi/datamodel/low/v3/link.go | 104 + .../libopenapi/datamodel/low/v3/media_type.go | 153 + .../datamodel/low/v3/oauth_flows.go | 151 + .../libopenapi/datamodel/low/v3/operation.go | 268 + .../libopenapi/datamodel/low/v3/parameter.go | 217 + .../libopenapi/datamodel/low/v3/path_item.go | 313 + .../libopenapi/datamodel/low/v3/paths.go | 176 + .../datamodel/low/v3/request_body.go | 84 + .../libopenapi/datamodel/low/v3/response.go | 139 + .../libopenapi/datamodel/low/v3/responses.go | 138 + .../datamodel/low/v3/security_scheme.go | 100 + .../libopenapi/datamodel/low/v3/server.go | 92 + .../datamodel/low/v3/server_variable.go | 43 + .../datamodel/schemas/oas3-schema.json | 1662 +++ .../datamodel/schemas/oas31-schema.json | 1449 ++ .../datamodel/schemas/swagger2-schema.json | 1607 ++ .../pb33f/libopenapi/datamodel/spec_info.go | 190 + .../github.com/pb33f/libopenapi/document.go | 305 + .../index/circular_reference_result.go | 29 + .../pb33f/libopenapi/index/extract_refs.go | 432 + .../pb33f/libopenapi/index/find_component.go | 399 + .../pb33f/libopenapi/index/index_model.go | 279 + .../pb33f/libopenapi/index/index_utils.go | 91 + .../pb33f/libopenapi/index/search_index.go | 34 + .../pb33f/libopenapi/index/spec_index.go | 1173 ++ .../pb33f/libopenapi/index/utility_methods.go | 450 + .../pb33f/libopenapi/libopenapi-logo.png | Bin 0 -> 94065 bytes .../pb33f/libopenapi/resolver/resolver.go | 457 + .../pb33f/libopenapi/utils/nodes.go | 68 + .../pb33f/libopenapi/utils/type_check.go | 49 + .../pb33f/libopenapi/utils/utils.go | 638 + .../libopenapi/what-changed/model/callback.go | 113 + .../what-changed/model/change_types.go | 139 + .../model/comparison_functions.go | 380 + .../what-changed/model/components.go | 279 + .../libopenapi/what-changed/model/contact.go | 81 + .../what-changed/model/discriminator.go | 96 + .../libopenapi/what-changed/model/document.go | 324 + .../libopenapi/what-changed/model/encoding.go | 99 + .../libopenapi/what-changed/model/example.go | 215 + .../libopenapi/what-changed/model/examples.go | 86 + .../what-changed/model/extensions.go | 97 + .../what-changed/model/external_docs.go | 82 + .../libopenapi/what-changed/model/header.go | 280 + .../libopenapi/what-changed/model/info.go | 147 + .../libopenapi/what-changed/model/items.go | 88 + .../libopenapi/what-changed/model/license.go | 70 + .../libopenapi/what-changed/model/link.go | 160 + .../what-changed/model/media_type.go | 149 + .../what-changed/model/oauth_flows.go | 257 + .../what-changed/model/operation.go | 561 + .../what-changed/model/parameter.go | 354 + .../what-changed/model/path_item.go | 639 + .../libopenapi/what-changed/model/paths.go | 206 + .../what-changed/model/request_body.go | 93 + .../libopenapi/what-changed/model/response.go | 199 + .../what-changed/model/responses.go | 140 + .../libopenapi/what-changed/model/schema.go | 1237 ++ .../libopenapi/what-changed/model/scopes.go | 76 + .../model/security_requirement.go | 150 + .../what-changed/model/security_scheme.go | 181 + .../libopenapi/what-changed/model/server.go | 82 + .../what-changed/model/server_variable.go | 82 + .../libopenapi/what-changed/model/tags.go | 150 + .../libopenapi/what-changed/model/xml.go | 114 + .../libopenapi/what-changed/what_changed.go | 36 + .../prometheus/collectors/collectors.go | 40 + .../collectors/dbstats_collector.go | 119 + .../prometheus/collectors/expvar_collector.go | 57 + .../collectors/go_collector_go116.go | 49 + .../collectors/go_collector_latest.go | 162 + .../collectors/process_collector.go | 56 + .../santhosh-tekuri/jsonschema/v5/.gitignore | 4 + .../santhosh-tekuri/jsonschema/v5/.gitmodules | 3 + .../santhosh-tekuri/jsonschema/v5/LICENSE | 175 + .../santhosh-tekuri/jsonschema/v5/README.md | 220 + .../santhosh-tekuri/jsonschema/v5/compiler.go | 812 ++ .../santhosh-tekuri/jsonschema/v5/content.go | 29 + .../santhosh-tekuri/jsonschema/v5/doc.go | 49 + .../santhosh-tekuri/jsonschema/v5/draft.go | 1453 ++ .../santhosh-tekuri/jsonschema/v5/errors.go | 129 + .../jsonschema/v5/extension.go | 116 + .../santhosh-tekuri/jsonschema/v5/format.go | 567 + .../santhosh-tekuri/jsonschema/v5/loader.go | 60 + .../santhosh-tekuri/jsonschema/v5/output.go | 77 + .../santhosh-tekuri/jsonschema/v5/resource.go | 280 + .../santhosh-tekuri/jsonschema/v5/schema.go | 829 ++ .../github.com/senseyeio/duration/.travis.yml | 14 + vendor/github.com/senseyeio/duration/LICENSE | 22 + .../github.com/senseyeio/duration/README.md | 84 + .../senseyeio/duration/coveralls.bash | 25 + .../github.com/senseyeio/duration/duration.go | 146 + .../serverlessworkflow/sdk-go/v2/LICENSE | 201 + .../sdk-go/v2/model/action.go | 121 + .../sdk-go/v2/model/action_data_filter.go | 49 + .../sdk-go/v2/model/auth.go | 195 + .../sdk-go/v2/model/callback_state.go | 60 + .../sdk-go/v2/model/common.go | 25 + .../sdk-go/v2/model/delay_state.go | 33 + .../serverlessworkflow/sdk-go/v2/model/doc.go | 18 + .../sdk-go/v2/model/event.go | 114 + .../sdk-go/v2/model/event_data_filter.go | 43 + .../sdk-go/v2/model/event_state.go | 105 + .../sdk-go/v2/model/event_validator.go | 34 + .../sdk-go/v2/model/foreach_state.go | 105 + .../v2/model/foreach_state_validator.go | 59 + .../sdk-go/v2/model/function.go | 63 + .../sdk-go/v2/model/inject_state.go | 48 + .../sdk-go/v2/model/object.go | 97 + .../sdk-go/v2/model/operation_state.go | 68 + .../sdk-go/v2/model/parallel_state.go | 109 + .../v2/model/parallel_state_validator.go | 55 + .../sdk-go/v2/model/retry.go | 43 + .../sdk-go/v2/model/retry_validator.go | 39 + .../sdk-go/v2/model/sleep_state.go | 48 + .../sdk-go/v2/model/state_exec_timeout.go | 32 + .../sdk-go/v2/model/states.go | 278 + .../sdk-go/v2/model/states_validator.go | 33 + .../sdk-go/v2/model/switch_state.go | 146 + .../sdk-go/v2/model/switch_state_validator.go | 59 + .../sdk-go/v2/model/util.go | 313 + .../sdk-go/v2/model/workflow.go | 517 + .../sdk-go/v2/model/workflow_ref.go | 50 + .../sdk-go/v2/model/workflow_validator.go | 97 + .../sdk-go/v2/model/zz_generated.deepcopy.go | 1745 +++ .../sdk-go/v2/parser/parser.go | 89 + .../sdk-go/v2/util/floatstr/floatstr.go | 105 + .../sdk-go/v2/validator/tags.go | 20 + .../sdk-go/v2/validator/validator.go | 74 + .../vmware-labs/yaml-jsonpath/LICENSE | 181 + .../vmware-labs/yaml-jsonpath/NOTICE | 7 + .../yaml-jsonpath/pkg/yamlpath/comparison.go | 93 + .../yaml-jsonpath/pkg/yamlpath/doc.go | 8 + .../yaml-jsonpath/pkg/yamlpath/filter.go | 297 + .../pkg/yamlpath/filter_parser.go | 295 + .../yaml-jsonpath/pkg/yamlpath/lexer.go | 1011 ++ .../yaml-jsonpath/pkg/yamlpath/path.go | 463 + .../yaml-jsonpath/pkg/yamlpath/slicer.go | 143 + vendor/go.uber.org/zap/CHANGELOG.md | 13 + vendor/go.uber.org/zap/array_go118.go | 8 +- vendor/go.uber.org/zap/logger.go | 7 + vendor/go.uber.org/zap/options.go | 3 +- vendor/go.uber.org/zap/sink.go | 100 +- vendor/go.uber.org/zap/stacktrace.go | 2 +- vendor/go.uber.org/zap/sugar.go | 31 +- vendor/go.uber.org/zap/writer.go | 2 +- vendor/go.uber.org/zap/zapcore/entry.go | 3 +- vendor/golang.org/x/crypto/sha3/doc.go | 62 + vendor/golang.org/x/crypto/sha3/hashes.go | 97 + .../x/crypto/sha3/hashes_generic.go | 28 + vendor/golang.org/x/crypto/sha3/keccakf.go | 415 + .../golang.org/x/crypto/sha3/keccakf_amd64.go | 14 + .../golang.org/x/crypto/sha3/keccakf_amd64.s | 391 + vendor/golang.org/x/crypto/sha3/register.go | 19 + vendor/golang.org/x/crypto/sha3/sha3.go | 193 + vendor/golang.org/x/crypto/sha3/sha3_s390x.go | 287 + vendor/golang.org/x/crypto/sha3/sha3_s390x.s | 34 + vendor/golang.org/x/crypto/sha3/shake.go | 173 + .../golang.org/x/crypto/sha3/shake_generic.go | 20 + vendor/golang.org/x/crypto/sha3/xor.go | 24 + .../golang.org/x/crypto/sha3/xor_generic.go | 28 + .../golang.org/x/crypto/sha3/xor_unaligned.go | 68 + .../golang.org/x/net/internal/socks/client.go | 168 + .../golang.org/x/net/internal/socks/socks.go | 317 + vendor/golang.org/x/net/proxy/dial.go | 54 + vendor/golang.org/x/net/proxy/direct.go | 31 + vendor/golang.org/x/net/proxy/per_host.go | 155 + vendor/golang.org/x/net/proxy/proxy.go | 149 + vendor/golang.org/x/net/proxy/socks5.go | 42 + vendor/golang.org/x/sync/syncmap/go19.go | 18 + vendor/golang.org/x/sync/syncmap/map.go | 8 + vendor/golang.org/x/sync/syncmap/pre_go19.go | 371 + vendor/golang.org/x/sys/cpu/asm_aix_ppc64.s | 18 + vendor/golang.org/x/sys/cpu/byteorder.go | 66 + vendor/golang.org/x/sys/cpu/cpu.go | 287 + vendor/golang.org/x/sys/cpu/cpu_aix.go | 34 + vendor/golang.org/x/sys/cpu/cpu_arm.go | 73 + vendor/golang.org/x/sys/cpu/cpu_arm64.go | 172 + vendor/golang.org/x/sys/cpu/cpu_arm64.s | 32 + vendor/golang.org/x/sys/cpu/cpu_gc_arm64.go | 12 + vendor/golang.org/x/sys/cpu/cpu_gc_s390x.go | 22 + vendor/golang.org/x/sys/cpu/cpu_gc_x86.go | 17 + .../golang.org/x/sys/cpu/cpu_gccgo_arm64.go | 12 + .../golang.org/x/sys/cpu/cpu_gccgo_s390x.go | 23 + vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.c | 39 + vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.go | 33 + vendor/golang.org/x/sys/cpu/cpu_linux.go | 16 + vendor/golang.org/x/sys/cpu/cpu_linux_arm.go | 39 + .../golang.org/x/sys/cpu/cpu_linux_arm64.go | 111 + .../golang.org/x/sys/cpu/cpu_linux_mips64x.go | 24 + .../golang.org/x/sys/cpu/cpu_linux_noinit.go | 10 + .../golang.org/x/sys/cpu/cpu_linux_ppc64x.go | 32 + .../golang.org/x/sys/cpu/cpu_linux_s390x.go | 40 + vendor/golang.org/x/sys/cpu/cpu_loong64.go | 13 + vendor/golang.org/x/sys/cpu/cpu_mips64x.go | 16 + vendor/golang.org/x/sys/cpu/cpu_mipsx.go | 12 + .../golang.org/x/sys/cpu/cpu_netbsd_arm64.go | 173 + .../golang.org/x/sys/cpu/cpu_openbsd_arm64.go | 65 + .../golang.org/x/sys/cpu/cpu_openbsd_arm64.s | 11 + vendor/golang.org/x/sys/cpu/cpu_other_arm.go | 10 + .../golang.org/x/sys/cpu/cpu_other_arm64.go | 10 + .../golang.org/x/sys/cpu/cpu_other_mips64x.go | 13 + .../golang.org/x/sys/cpu/cpu_other_ppc64x.go | 15 + .../golang.org/x/sys/cpu/cpu_other_riscv64.go | 12 + vendor/golang.org/x/sys/cpu/cpu_ppc64x.go | 17 + vendor/golang.org/x/sys/cpu/cpu_riscv64.go | 12 + vendor/golang.org/x/sys/cpu/cpu_s390x.go | 172 + vendor/golang.org/x/sys/cpu/cpu_s390x.s | 58 + vendor/golang.org/x/sys/cpu/cpu_wasm.go | 18 + vendor/golang.org/x/sys/cpu/cpu_x86.go | 145 + vendor/golang.org/x/sys/cpu/cpu_x86.s | 28 + vendor/golang.org/x/sys/cpu/cpu_zos.go | 10 + vendor/golang.org/x/sys/cpu/cpu_zos_s390x.go | 25 + vendor/golang.org/x/sys/cpu/endian_big.go | 11 + vendor/golang.org/x/sys/cpu/endian_little.go | 11 + vendor/golang.org/x/sys/cpu/hwcap_linux.go | 71 + vendor/golang.org/x/sys/cpu/parse.go | 43 + .../x/sys/cpu/proc_cpuinfo_linux.go | 54 + vendor/golang.org/x/sys/cpu/runtime_auxv.go | 16 + .../x/sys/cpu/runtime_auxv_go121.go | 19 + .../golang.org/x/sys/cpu/syscall_aix_gccgo.go | 27 + .../x/sys/cpu/syscall_aix_ppc64_gc.go | 36 + .../x/tools/cmd/stringer/stringer.go | 657 + .../grpc/attributes/attributes.go | 2 +- vendor/google.golang.org/grpc/backoff.go | 2 +- .../grpc/balancer/balancer.go | 25 +- .../grpc/balancer/base/balancer.go | 4 +- .../grpc/balancer/conn_state_evaluator.go | 12 +- .../grpc/balancer/roundrobin/roundrobin.go | 16 +- .../grpc/balancer_conn_wrappers.go | 71 +- .../grpc_binarylog_v1/binarylog.pb.go | 13 +- .../grpc/channelz/channelz.go | 2 +- vendor/google.golang.org/grpc/clientconn.go | 135 +- .../grpc/credentials/credentials.go | 20 +- .../google.golang.org/grpc/credentials/tls.go | 2 +- vendor/google.golang.org/grpc/dialoptions.go | 15 +- .../grpc/encoding/encoding.go | 5 +- .../grpc/grpclog/loggerv2.go | 2 +- .../grpc/internal/binarylog/binarylog.go | 20 +- .../grpc/internal/binarylog/env_config.go | 20 +- .../grpc/internal/binarylog/method_logger.go | 19 +- .../grpc/internal/channelz/types.go | 16 +- .../grpc/internal/envconfig/envconfig.go | 8 +- .../grpc/internal/envconfig/observability.go | 36 + .../grpc/internal/envconfig/xds.go | 7 +- .../grpc/internal/grpclog/grpclog.go | 2 +- .../grpc/internal/grpcrand/grpcrand.go | 7 + .../grpc/internal/grpcsync/oncefunc.go | 32 + .../grpc/internal/grpcutil/compressor.go | 47 + .../grpc/internal/grpcutil/method.go | 1 - .../grpc/internal/internal.go | 42 +- .../grpc/internal/resolver/unix/unix.go | 5 +- .../internal/serviceconfig/serviceconfig.go | 8 +- .../grpc/internal/status/status.go | 10 + .../grpc/internal/transport/controlbuf.go | 4 +- .../grpc/internal/transport/handler_server.go | 8 +- .../grpc/internal/transport/http2_client.go | 194 +- .../grpc/internal/transport/http2_server.go | 19 +- .../grpc/internal/transport/http_util.go | 23 +- .../grpc/internal/transport/transport.go | 14 +- .../grpc/metadata/metadata.go | 73 +- .../google.golang.org/grpc/picker_wrapper.go | 7 +- vendor/google.golang.org/grpc/preloader.go | 2 +- .../grpc/resolver/resolver.go | 14 +- vendor/google.golang.org/grpc/rpc_util.go | 39 +- vendor/google.golang.org/grpc/server.go | 147 +- .../grpc/serviceconfig/serviceconfig.go | 2 +- .../google.golang.org/grpc/status/status.go | 12 +- vendor/google.golang.org/grpc/stream.go | 133 +- vendor/google.golang.org/grpc/tap/tap.go | 2 +- vendor/google.golang.org/grpc/version.go | 2 +- vendor/google.golang.org/grpc/vet.sh | 6 +- vendor/k8s.io/api/admission/v1/doc.go | 23 + .../k8s.io/api/admission/v1/generated.pb.go | 1783 +++ .../k8s.io/api/admission/v1/generated.proto | 167 + vendor/k8s.io/api/admission/v1/register.go | 53 + vendor/k8s.io/api/admission/v1/types.go | 169 + .../v1/types_swagger_doc_generated.go | 78 + .../api/admission/v1/zz_generated.deepcopy.go | 142 + vendor/k8s.io/api/admission/v1beta1/doc.go | 24 + .../api/admission/v1beta1/generated.pb.go | 1783 +++ .../api/admission/v1beta1/generated.proto | 167 + .../k8s.io/api/admission/v1beta1/register.go | 53 + vendor/k8s.io/api/admission/v1beta1/types.go | 174 + .../v1beta1/types_swagger_doc_generated.go | 78 + .../v1beta1/zz_generated.deepcopy.go | 142 + .../zz_generated.prerelease-lifecycle.go | 50 + .../apis/meta/internalversion/scheme/doc.go | 17 + .../meta/internalversion/scheme/register.go | 39 + vendor/k8s.io/client-go/metadata/interface.go | 49 + vendor/k8s.io/client-go/metadata/metadata.go | 331 + vendor/k8s.io/component-base/LICENSE | 202 + vendor/k8s.io/component-base/config/doc.go | 19 + vendor/k8s.io/component-base/config/types.go | 80 + .../config/v1alpha1/conversion.go | 53 + .../config/v1alpha1/defaults.go | 98 + .../component-base/config/v1alpha1/doc.go | 20 + .../config/v1alpha1/register.go | 31 + .../component-base/config/v1alpha1/types.go | 82 + .../v1alpha1/zz_generated.conversion.go | 133 + .../config/v1alpha1/zz_generated.deepcopy.go | 88 + .../config/zz_generated.deepcopy.go | 73 + vendor/modules.txt | 171 +- .../sigs.k8s.io/controller-runtime/.gitignore | 24 + .../controller-runtime/.golangci.yml | 143 + .../controller-runtime/CONTRIBUTING.md | 19 + vendor/sigs.k8s.io/controller-runtime/FAQ.md | 81 + vendor/sigs.k8s.io/controller-runtime/LICENSE | 201 + .../sigs.k8s.io/controller-runtime/Makefile | 123 + .../sigs.k8s.io/controller-runtime/README.md | 66 + .../sigs.k8s.io/controller-runtime/RELEASE.md | 47 + .../controller-runtime/SECURITY_CONTACTS | 14 + .../controller-runtime/TMP-LOGGING.md | 169 + .../controller-runtime/VERSIONING.md | 30 + .../sigs.k8s.io/controller-runtime/alias.go | 150 + .../controller-runtime/code-of-conduct.md | 3 + vendor/sigs.k8s.io/controller-runtime/doc.go | 128 + .../pkg/builder/controller.go | 333 + .../controller-runtime/pkg/builder/doc.go | 28 + .../controller-runtime/pkg/builder/options.go | 140 + .../controller-runtime/pkg/builder/webhook.go | 216 + .../controller-runtime/pkg/cache/cache.go | 275 + .../controller-runtime/pkg/cache/doc.go | 19 + .../pkg/cache/informer_cache.go | 217 + .../pkg/cache/internal/cache_reader.go | 218 + .../pkg/cache/internal/deleg_map.go | 126 + .../pkg/cache/internal/disabledeepcopy.go | 35 + .../pkg/cache/internal/informers_map.go | 480 + .../pkg/cache/internal/selector.go | 54 + .../pkg/cache/internal/transformers.go | 50 + .../pkg/cache/multi_namespace_cache.go | 331 + .../pkg/certwatcher/certwatcher.go | 166 + .../controller-runtime/pkg/certwatcher/doc.go | 23 + .../pkg/certwatcher/metrics/metrics.go | 45 + .../pkg/client/apiutil/apimachinery.go | 196 + .../pkg/client/apiutil/dynamicrestmapper.go | 290 + .../controller-runtime/pkg/client/client.go | 327 + .../pkg/client/client_cache.go | 150 + .../controller-runtime/pkg/client/codec.go | 40 + .../pkg/client/config/config.go | 157 + .../pkg/client/config/doc.go | 18 + .../controller-runtime/pkg/client/doc.go | 50 + .../controller-runtime/pkg/client/dryrun.go | 106 + .../pkg/client/interfaces.go | 155 + .../pkg/client/metadata_client.go | 196 + .../pkg/client/namespaced_client.go | 213 + .../controller-runtime/pkg/client/object.go | 77 + .../controller-runtime/pkg/client/options.go | 742 + .../controller-runtime/pkg/client/patch.go | 213 + .../controller-runtime/pkg/client/split.go | 141 + .../pkg/client/typed_client.go | 208 + .../pkg/client/unstructured_client.go | 275 + .../controller-runtime/pkg/client/watch.go | 114 + .../controller-runtime/pkg/cluster/cluster.go | 270 + .../pkg/cluster/internal.go | 128 + .../controller-runtime/pkg/config/config.go | 112 + .../controller-runtime/pkg/config/doc.go | 25 + .../pkg/config/v1alpha1/doc.go | 20 + .../pkg/config/v1alpha1/register.go | 37 + .../pkg/config/v1alpha1/types.go | 157 + .../config/v1alpha1/zz_generated.deepcopy.go | 153 + .../pkg/controller/controller.go | 155 + .../controllerutil/controllerutil.go | 394 + .../pkg/controller/controllerutil/doc.go | 20 + .../controller-runtime/pkg/controller/doc.go | 25 + .../pkg/conversion/conversion.go | 40 + .../controller-runtime/pkg/event/doc.go | 28 + .../controller-runtime/pkg/event/event.go | 55 + .../controller-runtime/pkg/handler/doc.go | 38 + .../controller-runtime/pkg/handler/enqueue.go | 90 + .../pkg/handler/enqueue_mapped.go | 97 + .../pkg/handler/enqueue_owner.go | 189 + .../pkg/handler/eventhandler.go | 104 + .../controller-runtime/pkg/healthz/doc.go | 32 + .../controller-runtime/pkg/healthz/healthz.go | 206 + .../pkg/internal/controller/controller.go | 360 + .../internal/controller/metrics/metrics.go | 78 + .../pkg/internal/httpserver/server.go | 16 + .../pkg/internal/log/log.go | 32 + .../pkg/internal/objectutil/objectutil.go | 78 + .../pkg/internal/recorder/recorder.go | 176 + .../pkg/leaderelection/doc.go | 24 + .../pkg/leaderelection/leader_election.go | 127 + .../controller-runtime/pkg/log/deleg.go | 199 + .../controller-runtime/pkg/log/log.go | 102 + .../controller-runtime/pkg/log/null.go | 59 + .../pkg/log/warning_handler.go | 76 + .../controller-runtime/pkg/manager/doc.go | 21 + .../pkg/manager/internal.go | 652 + .../controller-runtime/pkg/manager/manager.go | 638 + .../pkg/manager/runnable_group.go | 297 + .../pkg/manager/signals/doc.go | 20 + .../pkg/manager/signals/signal.go | 45 + .../pkg/manager/signals/signal_posix.go | 27 + .../pkg/manager/signals/signal_windows.go | 23 + .../pkg/metrics/client_go_adapter.go | 111 + .../controller-runtime/pkg/metrics/doc.go | 20 + .../pkg/metrics/listener.go | 52 + .../pkg/metrics/registry.go | 30 + .../pkg/metrics/workqueue.go | 130 + .../controller-runtime/pkg/predicate/doc.go | 20 + .../pkg/predicate/predicate.go | 353 + .../controller-runtime/pkg/ratelimiter/doc.go | 22 + .../pkg/ratelimiter/ratelimiter.go | 30 + .../controller-runtime/pkg/reconcile/doc.go | 21 + .../pkg/reconcile/reconcile.go | 102 + .../pkg/recorder/recorder.go | 31 + .../pkg/runtime/inject/doc.go | 22 + .../pkg/runtime/inject/inject.go | 164 + .../controller-runtime/pkg/scheme/scheme.go | 93 + .../controller-runtime/pkg/source/doc.go | 22 + .../pkg/source/internal/eventsource.go | 138 + .../controller-runtime/pkg/source/source.go | 375 + .../pkg/webhook/admission/decode.go | 72 + .../pkg/webhook/admission/defaulter.go | 87 + .../pkg/webhook/admission/defaulter_custom.go | 86 + .../pkg/webhook/admission/doc.go | 28 + .../pkg/webhook/admission/http.go | 153 + .../pkg/webhook/admission/inject.go | 31 + .../pkg/webhook/admission/multi.go | 147 + .../pkg/webhook/admission/response.go | 121 + .../pkg/webhook/admission/validator.go | 122 + .../pkg/webhook/admission/validator_custom.go | 113 + .../pkg/webhook/admission/webhook.go | 296 + .../controller-runtime/pkg/webhook/alias.go | 79 + .../pkg/webhook/conversion/conversion.go | 345 + .../pkg/webhook/conversion/decoder.go | 47 + .../controller-runtime/pkg/webhook/doc.go | 28 + .../pkg/webhook/internal/metrics/metrics.go | 85 + .../controller-runtime/pkg/webhook/server.go | 345 + 919 files changed, 129165 insertions(+), 1001 deletions(-) rename lib/test/{ => e2e}/service.go (91%) create mode 100644 vendor/github.com/Microsoft/go-winio/.gitattributes create mode 100644 vendor/github.com/Microsoft/go-winio/.gitignore create mode 100644 vendor/github.com/Microsoft/go-winio/.golangci.yml create mode 100644 vendor/github.com/Microsoft/go-winio/CODEOWNERS create mode 100644 vendor/github.com/Microsoft/go-winio/LICENSE create mode 100644 vendor/github.com/Microsoft/go-winio/README.md create mode 100644 vendor/github.com/Microsoft/go-winio/SECURITY.md create mode 100644 vendor/github.com/Microsoft/go-winio/backup.go create mode 100644 vendor/github.com/Microsoft/go-winio/doc.go create mode 100644 vendor/github.com/Microsoft/go-winio/ea.go create mode 100644 vendor/github.com/Microsoft/go-winio/file.go create mode 100644 vendor/github.com/Microsoft/go-winio/fileinfo.go create mode 100644 vendor/github.com/Microsoft/go-winio/hvsock.go create mode 100644 vendor/github.com/Microsoft/go-winio/internal/fs/doc.go create mode 100644 vendor/github.com/Microsoft/go-winio/internal/fs/fs.go create mode 100644 vendor/github.com/Microsoft/go-winio/internal/fs/security.go create mode 100644 vendor/github.com/Microsoft/go-winio/internal/fs/zsyscall_windows.go create mode 100644 vendor/github.com/Microsoft/go-winio/internal/socket/rawaddr.go create mode 100644 vendor/github.com/Microsoft/go-winio/internal/socket/socket.go create mode 100644 vendor/github.com/Microsoft/go-winio/internal/socket/zsyscall_windows.go create mode 100644 vendor/github.com/Microsoft/go-winio/internal/stringbuffer/wstring.go create mode 100644 vendor/github.com/Microsoft/go-winio/pipe.go create mode 100644 vendor/github.com/Microsoft/go-winio/pkg/guid/guid.go create mode 100644 vendor/github.com/Microsoft/go-winio/pkg/guid/guid_nonwindows.go create mode 100644 vendor/github.com/Microsoft/go-winio/pkg/guid/guid_windows.go create mode 100644 vendor/github.com/Microsoft/go-winio/pkg/guid/variant_string.go create mode 100644 vendor/github.com/Microsoft/go-winio/privilege.go create mode 100644 vendor/github.com/Microsoft/go-winio/reparse.go create mode 100644 vendor/github.com/Microsoft/go-winio/sd.go create mode 100644 vendor/github.com/Microsoft/go-winio/syscall.go create mode 100644 vendor/github.com/Microsoft/go-winio/tools.go create mode 100644 vendor/github.com/Microsoft/go-winio/zsyscall_windows.go create mode 100644 vendor/github.com/docker/distribution/LICENSE create mode 100644 vendor/github.com/docker/distribution/digestset/set.go create mode 100644 vendor/github.com/docker/distribution/reference/helpers.go create mode 100644 vendor/github.com/docker/distribution/reference/normalize.go create mode 100644 vendor/github.com/docker/distribution/reference/reference.go create mode 100644 vendor/github.com/docker/distribution/reference/regexp.go create mode 100644 vendor/github.com/docker/docker/AUTHORS create mode 100644 vendor/github.com/docker/docker/LICENSE create mode 100644 vendor/github.com/docker/docker/NOTICE create mode 100644 vendor/github.com/docker/docker/api/README.md create mode 100644 vendor/github.com/docker/docker/api/common.go create mode 100644 vendor/github.com/docker/docker/api/common_unix.go create mode 100644 vendor/github.com/docker/docker/api/common_windows.go create mode 100644 vendor/github.com/docker/docker/api/swagger-gen.yaml create mode 100644 vendor/github.com/docker/docker/api/swagger.yaml create mode 100644 vendor/github.com/docker/docker/api/types/auth.go create mode 100644 vendor/github.com/docker/docker/api/types/blkiodev/blkio.go create mode 100644 vendor/github.com/docker/docker/api/types/client.go create mode 100644 vendor/github.com/docker/docker/api/types/configs.go create mode 100644 vendor/github.com/docker/docker/api/types/container/config.go create mode 100644 vendor/github.com/docker/docker/api/types/container/container_changes.go create mode 100644 vendor/github.com/docker/docker/api/types/container/container_top.go create mode 100644 vendor/github.com/docker/docker/api/types/container/container_update.go create mode 100644 vendor/github.com/docker/docker/api/types/container/create_response.go create mode 100644 vendor/github.com/docker/docker/api/types/container/deprecated.go create mode 100644 vendor/github.com/docker/docker/api/types/container/host_config.go create mode 100644 vendor/github.com/docker/docker/api/types/container/hostconfig_unix.go create mode 100644 vendor/github.com/docker/docker/api/types/container/hostconfig_windows.go create mode 100644 vendor/github.com/docker/docker/api/types/container/wait_exit_error.go create mode 100644 vendor/github.com/docker/docker/api/types/container/wait_response.go create mode 100644 vendor/github.com/docker/docker/api/types/container/waitcondition.go create mode 100644 vendor/github.com/docker/docker/api/types/deprecated.go create mode 100644 vendor/github.com/docker/docker/api/types/error_response.go create mode 100644 vendor/github.com/docker/docker/api/types/error_response_ext.go create mode 100644 vendor/github.com/docker/docker/api/types/events/events.go create mode 100644 vendor/github.com/docker/docker/api/types/filters/parse.go create mode 100644 vendor/github.com/docker/docker/api/types/graph_driver_data.go create mode 100644 vendor/github.com/docker/docker/api/types/id_response.go create mode 100644 vendor/github.com/docker/docker/api/types/image/image_history.go create mode 100644 vendor/github.com/docker/docker/api/types/image_delete_response_item.go create mode 100644 vendor/github.com/docker/docker/api/types/image_summary.go create mode 100644 vendor/github.com/docker/docker/api/types/mount/mount.go create mode 100644 vendor/github.com/docker/docker/api/types/network/network.go create mode 100644 vendor/github.com/docker/docker/api/types/plugin.go create mode 100644 vendor/github.com/docker/docker/api/types/plugin_device.go create mode 100644 vendor/github.com/docker/docker/api/types/plugin_env.go create mode 100644 vendor/github.com/docker/docker/api/types/plugin_interface_type.go create mode 100644 vendor/github.com/docker/docker/api/types/plugin_mount.go create mode 100644 vendor/github.com/docker/docker/api/types/plugin_responses.go create mode 100644 vendor/github.com/docker/docker/api/types/port.go create mode 100644 vendor/github.com/docker/docker/api/types/registry/authenticate.go create mode 100644 vendor/github.com/docker/docker/api/types/registry/registry.go create mode 100644 vendor/github.com/docker/docker/api/types/service_update_response.go create mode 100644 vendor/github.com/docker/docker/api/types/stats.go create mode 100644 vendor/github.com/docker/docker/api/types/strslice/strslice.go create mode 100644 vendor/github.com/docker/docker/api/types/swarm/common.go create mode 100644 vendor/github.com/docker/docker/api/types/swarm/config.go create mode 100644 vendor/github.com/docker/docker/api/types/swarm/container.go create mode 100644 vendor/github.com/docker/docker/api/types/swarm/network.go create mode 100644 vendor/github.com/docker/docker/api/types/swarm/node.go create mode 100644 vendor/github.com/docker/docker/api/types/swarm/runtime.go create mode 100644 vendor/github.com/docker/docker/api/types/swarm/runtime/gen.go create mode 100644 vendor/github.com/docker/docker/api/types/swarm/runtime/plugin.pb.go create mode 100644 vendor/github.com/docker/docker/api/types/swarm/runtime/plugin.proto create mode 100644 vendor/github.com/docker/docker/api/types/swarm/secret.go create mode 100644 vendor/github.com/docker/docker/api/types/swarm/service.go create mode 100644 vendor/github.com/docker/docker/api/types/swarm/swarm.go create mode 100644 vendor/github.com/docker/docker/api/types/swarm/task.go create mode 100644 vendor/github.com/docker/docker/api/types/time/timestamp.go create mode 100644 vendor/github.com/docker/docker/api/types/types.go create mode 100644 vendor/github.com/docker/docker/api/types/versions/README.md create mode 100644 vendor/github.com/docker/docker/api/types/versions/compare.go create mode 100644 vendor/github.com/docker/docker/api/types/volume/cluster_volume.go create mode 100644 vendor/github.com/docker/docker/api/types/volume/create_options.go create mode 100644 vendor/github.com/docker/docker/api/types/volume/deprecated.go create mode 100644 vendor/github.com/docker/docker/api/types/volume/list_response.go create mode 100644 vendor/github.com/docker/docker/api/types/volume/options.go create mode 100644 vendor/github.com/docker/docker/api/types/volume/volume.go create mode 100644 vendor/github.com/docker/docker/api/types/volume/volume_update.go create mode 100644 vendor/github.com/docker/docker/client/README.md create mode 100644 vendor/github.com/docker/docker/client/build_cancel.go create mode 100644 vendor/github.com/docker/docker/client/build_prune.go create mode 100644 vendor/github.com/docker/docker/client/checkpoint_create.go create mode 100644 vendor/github.com/docker/docker/client/checkpoint_delete.go create mode 100644 vendor/github.com/docker/docker/client/checkpoint_list.go create mode 100644 vendor/github.com/docker/docker/client/client.go create mode 100644 vendor/github.com/docker/docker/client/client_deprecated.go create mode 100644 vendor/github.com/docker/docker/client/client_unix.go create mode 100644 vendor/github.com/docker/docker/client/client_windows.go create mode 100644 vendor/github.com/docker/docker/client/config_create.go create mode 100644 vendor/github.com/docker/docker/client/config_inspect.go create mode 100644 vendor/github.com/docker/docker/client/config_list.go create mode 100644 vendor/github.com/docker/docker/client/config_remove.go create mode 100644 vendor/github.com/docker/docker/client/config_update.go create mode 100644 vendor/github.com/docker/docker/client/container_attach.go create mode 100644 vendor/github.com/docker/docker/client/container_commit.go create mode 100644 vendor/github.com/docker/docker/client/container_copy.go create mode 100644 vendor/github.com/docker/docker/client/container_create.go create mode 100644 vendor/github.com/docker/docker/client/container_diff.go create mode 100644 vendor/github.com/docker/docker/client/container_exec.go create mode 100644 vendor/github.com/docker/docker/client/container_export.go create mode 100644 vendor/github.com/docker/docker/client/container_inspect.go create mode 100644 vendor/github.com/docker/docker/client/container_kill.go create mode 100644 vendor/github.com/docker/docker/client/container_list.go create mode 100644 vendor/github.com/docker/docker/client/container_logs.go create mode 100644 vendor/github.com/docker/docker/client/container_pause.go create mode 100644 vendor/github.com/docker/docker/client/container_prune.go create mode 100644 vendor/github.com/docker/docker/client/container_remove.go create mode 100644 vendor/github.com/docker/docker/client/container_rename.go create mode 100644 vendor/github.com/docker/docker/client/container_resize.go create mode 100644 vendor/github.com/docker/docker/client/container_restart.go create mode 100644 vendor/github.com/docker/docker/client/container_start.go create mode 100644 vendor/github.com/docker/docker/client/container_stats.go create mode 100644 vendor/github.com/docker/docker/client/container_stop.go create mode 100644 vendor/github.com/docker/docker/client/container_top.go create mode 100644 vendor/github.com/docker/docker/client/container_unpause.go create mode 100644 vendor/github.com/docker/docker/client/container_update.go create mode 100644 vendor/github.com/docker/docker/client/container_wait.go create mode 100644 vendor/github.com/docker/docker/client/disk_usage.go create mode 100644 vendor/github.com/docker/docker/client/distribution_inspect.go create mode 100644 vendor/github.com/docker/docker/client/envvars.go create mode 100644 vendor/github.com/docker/docker/client/errors.go create mode 100644 vendor/github.com/docker/docker/client/events.go create mode 100644 vendor/github.com/docker/docker/client/hijack.go create mode 100644 vendor/github.com/docker/docker/client/image_build.go create mode 100644 vendor/github.com/docker/docker/client/image_create.go create mode 100644 vendor/github.com/docker/docker/client/image_history.go create mode 100644 vendor/github.com/docker/docker/client/image_import.go create mode 100644 vendor/github.com/docker/docker/client/image_inspect.go create mode 100644 vendor/github.com/docker/docker/client/image_list.go create mode 100644 vendor/github.com/docker/docker/client/image_load.go create mode 100644 vendor/github.com/docker/docker/client/image_prune.go create mode 100644 vendor/github.com/docker/docker/client/image_pull.go create mode 100644 vendor/github.com/docker/docker/client/image_push.go create mode 100644 vendor/github.com/docker/docker/client/image_remove.go create mode 100644 vendor/github.com/docker/docker/client/image_save.go create mode 100644 vendor/github.com/docker/docker/client/image_search.go create mode 100644 vendor/github.com/docker/docker/client/image_tag.go create mode 100644 vendor/github.com/docker/docker/client/info.go create mode 100644 vendor/github.com/docker/docker/client/interface.go create mode 100644 vendor/github.com/docker/docker/client/interface_experimental.go create mode 100644 vendor/github.com/docker/docker/client/interface_stable.go create mode 100644 vendor/github.com/docker/docker/client/login.go create mode 100644 vendor/github.com/docker/docker/client/network_connect.go create mode 100644 vendor/github.com/docker/docker/client/network_create.go create mode 100644 vendor/github.com/docker/docker/client/network_disconnect.go create mode 100644 vendor/github.com/docker/docker/client/network_inspect.go create mode 100644 vendor/github.com/docker/docker/client/network_list.go create mode 100644 vendor/github.com/docker/docker/client/network_prune.go create mode 100644 vendor/github.com/docker/docker/client/network_remove.go create mode 100644 vendor/github.com/docker/docker/client/node_inspect.go create mode 100644 vendor/github.com/docker/docker/client/node_list.go create mode 100644 vendor/github.com/docker/docker/client/node_remove.go create mode 100644 vendor/github.com/docker/docker/client/node_update.go create mode 100644 vendor/github.com/docker/docker/client/options.go create mode 100644 vendor/github.com/docker/docker/client/ping.go create mode 100644 vendor/github.com/docker/docker/client/plugin_create.go create mode 100644 vendor/github.com/docker/docker/client/plugin_disable.go create mode 100644 vendor/github.com/docker/docker/client/plugin_enable.go create mode 100644 vendor/github.com/docker/docker/client/plugin_inspect.go create mode 100644 vendor/github.com/docker/docker/client/plugin_install.go create mode 100644 vendor/github.com/docker/docker/client/plugin_list.go create mode 100644 vendor/github.com/docker/docker/client/plugin_push.go create mode 100644 vendor/github.com/docker/docker/client/plugin_remove.go create mode 100644 vendor/github.com/docker/docker/client/plugin_set.go create mode 100644 vendor/github.com/docker/docker/client/plugin_upgrade.go create mode 100644 vendor/github.com/docker/docker/client/request.go create mode 100644 vendor/github.com/docker/docker/client/secret_create.go create mode 100644 vendor/github.com/docker/docker/client/secret_inspect.go create mode 100644 vendor/github.com/docker/docker/client/secret_list.go create mode 100644 vendor/github.com/docker/docker/client/secret_remove.go create mode 100644 vendor/github.com/docker/docker/client/secret_update.go create mode 100644 vendor/github.com/docker/docker/client/service_create.go create mode 100644 vendor/github.com/docker/docker/client/service_inspect.go create mode 100644 vendor/github.com/docker/docker/client/service_list.go create mode 100644 vendor/github.com/docker/docker/client/service_logs.go create mode 100644 vendor/github.com/docker/docker/client/service_remove.go create mode 100644 vendor/github.com/docker/docker/client/service_update.go create mode 100644 vendor/github.com/docker/docker/client/swarm_get_unlock_key.go create mode 100644 vendor/github.com/docker/docker/client/swarm_init.go create mode 100644 vendor/github.com/docker/docker/client/swarm_inspect.go create mode 100644 vendor/github.com/docker/docker/client/swarm_join.go create mode 100644 vendor/github.com/docker/docker/client/swarm_leave.go create mode 100644 vendor/github.com/docker/docker/client/swarm_unlock.go create mode 100644 vendor/github.com/docker/docker/client/swarm_update.go create mode 100644 vendor/github.com/docker/docker/client/task_inspect.go create mode 100644 vendor/github.com/docker/docker/client/task_list.go create mode 100644 vendor/github.com/docker/docker/client/task_logs.go create mode 100644 vendor/github.com/docker/docker/client/transport.go create mode 100644 vendor/github.com/docker/docker/client/utils.go create mode 100644 vendor/github.com/docker/docker/client/version.go create mode 100644 vendor/github.com/docker/docker/client/volume_create.go create mode 100644 vendor/github.com/docker/docker/client/volume_inspect.go create mode 100644 vendor/github.com/docker/docker/client/volume_list.go create mode 100644 vendor/github.com/docker/docker/client/volume_prune.go create mode 100644 vendor/github.com/docker/docker/client/volume_remove.go create mode 100644 vendor/github.com/docker/docker/client/volume_update.go create mode 100644 vendor/github.com/docker/docker/errdefs/defs.go create mode 100644 vendor/github.com/docker/docker/errdefs/doc.go create mode 100644 vendor/github.com/docker/docker/errdefs/helpers.go create mode 100644 vendor/github.com/docker/docker/errdefs/http_helpers.go create mode 100644 vendor/github.com/docker/docker/errdefs/is.go create mode 100644 vendor/github.com/docker/go-connections/LICENSE create mode 100644 vendor/github.com/docker/go-connections/nat/nat.go create mode 100644 vendor/github.com/docker/go-connections/nat/parse.go create mode 100644 vendor/github.com/docker/go-connections/nat/sort.go create mode 100644 vendor/github.com/docker/go-connections/sockets/README.md create mode 100644 vendor/github.com/docker/go-connections/sockets/inmem_socket.go create mode 100644 vendor/github.com/docker/go-connections/sockets/proxy.go create mode 100644 vendor/github.com/docker/go-connections/sockets/sockets.go create mode 100644 vendor/github.com/docker/go-connections/sockets/sockets_unix.go create mode 100644 vendor/github.com/docker/go-connections/sockets/sockets_windows.go create mode 100644 vendor/github.com/docker/go-connections/sockets/tcp_socket.go create mode 100644 vendor/github.com/docker/go-connections/sockets/unix_socket.go create mode 100644 vendor/github.com/docker/go-connections/tlsconfig/certpool_go17.go create mode 100644 vendor/github.com/docker/go-connections/tlsconfig/certpool_other.go create mode 100644 vendor/github.com/docker/go-connections/tlsconfig/config.go create mode 100644 vendor/github.com/docker/go-connections/tlsconfig/config_client_ciphers.go create mode 100644 vendor/github.com/docker/go-connections/tlsconfig/config_legacy_client_ciphers.go create mode 100644 vendor/github.com/docker/go-units/CONTRIBUTING.md create mode 100644 vendor/github.com/docker/go-units/LICENSE create mode 100644 vendor/github.com/docker/go-units/MAINTAINERS create mode 100644 vendor/github.com/docker/go-units/README.md create mode 100644 vendor/github.com/docker/go-units/circle.yml create mode 100644 vendor/github.com/docker/go-units/duration.go create mode 100644 vendor/github.com/docker/go-units/size.go create mode 100644 vendor/github.com/docker/go-units/ulimit.go create mode 100644 vendor/github.com/dprotaso/go-yit/.gitignore create mode 100644 vendor/github.com/dprotaso/go-yit/LICENSE create mode 100644 vendor/github.com/dprotaso/go-yit/README.md create mode 100644 vendor/github.com/dprotaso/go-yit/aggregates.go create mode 100644 vendor/github.com/dprotaso/go-yit/iterator.go create mode 100644 vendor/github.com/dprotaso/go-yit/predicates.go create mode 100644 vendor/github.com/go-playground/locales/.gitignore create mode 100644 vendor/github.com/go-playground/locales/.travis.yml create mode 100644 vendor/github.com/go-playground/locales/LICENSE create mode 100644 vendor/github.com/go-playground/locales/README.md create mode 100644 vendor/github.com/go-playground/locales/currency/currency.go create mode 100644 vendor/github.com/go-playground/locales/logo.png create mode 100644 vendor/github.com/go-playground/locales/rules.go create mode 100644 vendor/github.com/go-playground/universal-translator/.gitignore create mode 100644 vendor/github.com/go-playground/universal-translator/.travis.yml create mode 100644 vendor/github.com/go-playground/universal-translator/LICENSE create mode 100644 vendor/github.com/go-playground/universal-translator/Makefile create mode 100644 vendor/github.com/go-playground/universal-translator/README.md create mode 100644 vendor/github.com/go-playground/universal-translator/errors.go create mode 100644 vendor/github.com/go-playground/universal-translator/import_export.go create mode 100644 vendor/github.com/go-playground/universal-translator/logo.png create mode 100644 vendor/github.com/go-playground/universal-translator/translator.go create mode 100644 vendor/github.com/go-playground/universal-translator/universal_translator.go create mode 100644 vendor/github.com/go-playground/validator/v10/.gitignore create mode 100644 vendor/github.com/go-playground/validator/v10/LICENSE create mode 100644 vendor/github.com/go-playground/validator/v10/MAINTAINERS.md create mode 100644 vendor/github.com/go-playground/validator/v10/Makefile create mode 100644 vendor/github.com/go-playground/validator/v10/README.md create mode 100644 vendor/github.com/go-playground/validator/v10/baked_in.go create mode 100644 vendor/github.com/go-playground/validator/v10/cache.go create mode 100644 vendor/github.com/go-playground/validator/v10/country_codes.go create mode 100644 vendor/github.com/go-playground/validator/v10/currency_codes.go create mode 100644 vendor/github.com/go-playground/validator/v10/doc.go create mode 100644 vendor/github.com/go-playground/validator/v10/errors.go create mode 100644 vendor/github.com/go-playground/validator/v10/field_level.go create mode 100644 vendor/github.com/go-playground/validator/v10/logo.png create mode 100644 vendor/github.com/go-playground/validator/v10/postcode_regexes.go create mode 100644 vendor/github.com/go-playground/validator/v10/regexes.go create mode 100644 vendor/github.com/go-playground/validator/v10/struct_level.go create mode 100644 vendor/github.com/go-playground/validator/v10/translations.go create mode 100644 vendor/github.com/go-playground/validator/v10/util.go create mode 100644 vendor/github.com/go-playground/validator/v10/validator.go create mode 100644 vendor/github.com/go-playground/validator/v10/validator_instance.go create mode 100644 vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/command/deploy_undeploy_common.go rename vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/command/{ => quarkus}/build.go (93%) create mode 100644 vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/command/quarkus/convert.go create mode 100644 vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/command/quarkus/create.go create mode 100644 vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/command/quarkus/deploy.go create mode 100644 vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/command/quarkus/quarkus.go create mode 100644 vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/command/quarkus/quarkus_project.go create mode 100644 vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/command/quarkus/run.go create mode 100644 vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/command/run.go create mode 100644 vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/command/undeploy.go create mode 100644 vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/common/browser.go create mode 100644 vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/common/containers.go rename vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/{command => common}/create_workflow.go (68%) create mode 100644 vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/common/io.go create mode 100644 vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/common/kubectl.go create mode 100644 vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/common/operator.go create mode 100644 vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/common/readyCheck.go create mode 100644 vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/metadata/devModeImage.go create mode 100644 vendor/github.com/kiegroup/kogito-serverless-operator/api/LICENSE create mode 100644 vendor/github.com/kiegroup/kogito-serverless-operator/api/Makefile create mode 100644 vendor/github.com/kiegroup/kogito-serverless-operator/api/condition_types.go create mode 100644 vendor/github.com/kiegroup/kogito-serverless-operator/api/metadata/annotations.go create mode 100644 vendor/github.com/kiegroup/kogito-serverless-operator/api/status_types.go create mode 100644 vendor/github.com/kiegroup/kogito-serverless-operator/api/v1alpha08/conversion.go create mode 100644 vendor/github.com/kiegroup/kogito-serverless-operator/api/v1alpha08/groupversion_info.go create mode 100644 vendor/github.com/kiegroup/kogito-serverless-operator/api/v1alpha08/sonataflow_types.go create mode 100644 vendor/github.com/kiegroup/kogito-serverless-operator/api/v1alpha08/sonataflowbuild_types.go create mode 100644 vendor/github.com/kiegroup/kogito-serverless-operator/api/v1alpha08/sonataflowplatform_types.go create mode 100644 vendor/github.com/kiegroup/kogito-serverless-operator/api/v1alpha08/sonataflowplatform_types_support.go create mode 100644 vendor/github.com/kiegroup/kogito-serverless-operator/api/v1alpha08/zz_generated.deepcopy.go create mode 100644 vendor/github.com/kiegroup/kogito-serverless-operator/api/zz_generated.deepcopy.go create mode 100644 vendor/github.com/kiegroup/kogito-serverless-operator/workflowproj/LICENSE create mode 100644 vendor/github.com/kiegroup/kogito-serverless-operator/workflowproj/Makefile create mode 100644 vendor/github.com/kiegroup/kogito-serverless-operator/workflowproj/README.md create mode 100644 vendor/github.com/kiegroup/kogito-serverless-operator/workflowproj/camelschema.go create mode 100644 vendor/github.com/kiegroup/kogito-serverless-operator/workflowproj/io.go create mode 100644 vendor/github.com/kiegroup/kogito-serverless-operator/workflowproj/operator.go create mode 100644 vendor/github.com/kiegroup/kogito-serverless-operator/workflowproj/resources.go create mode 100644 vendor/github.com/kiegroup/kogito-serverless-operator/workflowproj/workflowproj.go create mode 100644 vendor/github.com/leodido/go-urn/.gitignore create mode 100644 vendor/github.com/leodido/go-urn/.travis.yml create mode 100644 vendor/github.com/leodido/go-urn/LICENSE create mode 100644 vendor/github.com/leodido/go-urn/README.md create mode 100644 vendor/github.com/leodido/go-urn/machine.go create mode 100644 vendor/github.com/leodido/go-urn/machine.go.rl create mode 100644 vendor/github.com/leodido/go-urn/makefile create mode 100644 vendor/github.com/leodido/go-urn/urn.go create mode 100644 vendor/github.com/opencontainers/image-spec/LICENSE create mode 100644 vendor/github.com/opencontainers/image-spec/specs-go/v1/annotations.go create mode 100644 vendor/github.com/opencontainers/image-spec/specs-go/v1/config.go create mode 100644 vendor/github.com/opencontainers/image-spec/specs-go/v1/descriptor.go create mode 100644 vendor/github.com/opencontainers/image-spec/specs-go/v1/index.go create mode 100644 vendor/github.com/opencontainers/image-spec/specs-go/v1/layout.go create mode 100644 vendor/github.com/opencontainers/image-spec/specs-go/v1/manifest.go create mode 100644 vendor/github.com/opencontainers/image-spec/specs-go/v1/mediatype.go create mode 100644 vendor/github.com/opencontainers/image-spec/specs-go/version.go create mode 100644 vendor/github.com/opencontainers/image-spec/specs-go/versioned.go create mode 100644 vendor/github.com/pb33f/libopenapi/LICENSE create mode 100644 vendor/github.com/pb33f/libopenapi/README.md create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/constants.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/document_config.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/high/base/base.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/high/base/contact.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/high/base/discriminator.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/high/base/dynamic_value.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/high/base/example.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/high/base/external_doc.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/high/base/info.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/high/base/license.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/high/base/schema.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/high/base/schema_proxy.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/high/base/security_requirement.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/high/base/tag.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/high/base/xml.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/high/node_builder.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/high/shared.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/high/v2/definitions.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/high/v2/examples.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/high/v2/header.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/high/v2/items.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/high/v2/operation.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/high/v2/parameter.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/high/v2/parameter_definitions.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/high/v2/path_item.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/high/v2/paths.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/high/v2/response.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/high/v2/responses.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/high/v2/responses_definitions.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/high/v2/scopes.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/high/v2/security_definitions.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/high/v2/security_scheme.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/high/v2/swagger.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/high/v3/callback.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/high/v3/components.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/high/v3/document.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/high/v3/encoding.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/high/v3/header.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/high/v3/link.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/high/v3/media_type.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/high/v3/oauth_flow.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/high/v3/oauth_flows.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/high/v3/operation.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/high/v3/parameter.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/high/v3/path_item.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/high/v3/paths.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/high/v3/request_body.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/high/v3/response.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/high/v3/responses.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/high/v3/security_scheme.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/high/v3/server.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/high/v3/server_variable.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/low/base/base.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/low/base/constants.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/low/base/contact.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/low/base/discriminator.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/low/base/example.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/low/base/external_doc.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/low/base/info.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/low/base/license.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/low/base/schema.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/low/base/schema_proxy.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/low/base/security_requirement.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/low/base/tag.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/low/base/xml.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/low/extraction_functions.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/low/low.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/low/model_builder.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/low/model_interfaces.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/low/reference.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/low/serializing.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/low/v2/constants.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/low/v2/definitions.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/low/v2/examples.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/low/v2/header.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/low/v2/items.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/low/v2/operation.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/low/v2/parameter.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/low/v2/path_item.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/low/v2/paths.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/low/v2/response.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/low/v2/responses.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/low/v2/scopes.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/low/v2/security_scheme.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/low/v2/swagger.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/low/v3/callback.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/low/v3/components.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/low/v3/constants.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/low/v3/create_document.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/low/v3/document.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/low/v3/encoding.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/low/v3/header.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/low/v3/link.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/low/v3/media_type.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/low/v3/oauth_flows.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/low/v3/operation.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/low/v3/parameter.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/low/v3/path_item.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/low/v3/paths.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/low/v3/request_body.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/low/v3/response.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/low/v3/responses.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/low/v3/security_scheme.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/low/v3/server.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/low/v3/server_variable.go create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/schemas/oas3-schema.json create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/schemas/oas31-schema.json create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/schemas/swagger2-schema.json create mode 100644 vendor/github.com/pb33f/libopenapi/datamodel/spec_info.go create mode 100644 vendor/github.com/pb33f/libopenapi/document.go create mode 100644 vendor/github.com/pb33f/libopenapi/index/circular_reference_result.go create mode 100644 vendor/github.com/pb33f/libopenapi/index/extract_refs.go create mode 100644 vendor/github.com/pb33f/libopenapi/index/find_component.go create mode 100644 vendor/github.com/pb33f/libopenapi/index/index_model.go create mode 100644 vendor/github.com/pb33f/libopenapi/index/index_utils.go create mode 100644 vendor/github.com/pb33f/libopenapi/index/search_index.go create mode 100644 vendor/github.com/pb33f/libopenapi/index/spec_index.go create mode 100644 vendor/github.com/pb33f/libopenapi/index/utility_methods.go create mode 100644 vendor/github.com/pb33f/libopenapi/libopenapi-logo.png create mode 100644 vendor/github.com/pb33f/libopenapi/resolver/resolver.go create mode 100644 vendor/github.com/pb33f/libopenapi/utils/nodes.go create mode 100644 vendor/github.com/pb33f/libopenapi/utils/type_check.go create mode 100644 vendor/github.com/pb33f/libopenapi/utils/utils.go create mode 100644 vendor/github.com/pb33f/libopenapi/what-changed/model/callback.go create mode 100644 vendor/github.com/pb33f/libopenapi/what-changed/model/change_types.go create mode 100644 vendor/github.com/pb33f/libopenapi/what-changed/model/comparison_functions.go create mode 100644 vendor/github.com/pb33f/libopenapi/what-changed/model/components.go create mode 100644 vendor/github.com/pb33f/libopenapi/what-changed/model/contact.go create mode 100644 vendor/github.com/pb33f/libopenapi/what-changed/model/discriminator.go create mode 100644 vendor/github.com/pb33f/libopenapi/what-changed/model/document.go create mode 100644 vendor/github.com/pb33f/libopenapi/what-changed/model/encoding.go create mode 100644 vendor/github.com/pb33f/libopenapi/what-changed/model/example.go create mode 100644 vendor/github.com/pb33f/libopenapi/what-changed/model/examples.go create mode 100644 vendor/github.com/pb33f/libopenapi/what-changed/model/extensions.go create mode 100644 vendor/github.com/pb33f/libopenapi/what-changed/model/external_docs.go create mode 100644 vendor/github.com/pb33f/libopenapi/what-changed/model/header.go create mode 100644 vendor/github.com/pb33f/libopenapi/what-changed/model/info.go create mode 100644 vendor/github.com/pb33f/libopenapi/what-changed/model/items.go create mode 100644 vendor/github.com/pb33f/libopenapi/what-changed/model/license.go create mode 100644 vendor/github.com/pb33f/libopenapi/what-changed/model/link.go create mode 100644 vendor/github.com/pb33f/libopenapi/what-changed/model/media_type.go create mode 100644 vendor/github.com/pb33f/libopenapi/what-changed/model/oauth_flows.go create mode 100644 vendor/github.com/pb33f/libopenapi/what-changed/model/operation.go create mode 100644 vendor/github.com/pb33f/libopenapi/what-changed/model/parameter.go create mode 100644 vendor/github.com/pb33f/libopenapi/what-changed/model/path_item.go create mode 100644 vendor/github.com/pb33f/libopenapi/what-changed/model/paths.go create mode 100644 vendor/github.com/pb33f/libopenapi/what-changed/model/request_body.go create mode 100644 vendor/github.com/pb33f/libopenapi/what-changed/model/response.go create mode 100644 vendor/github.com/pb33f/libopenapi/what-changed/model/responses.go create mode 100644 vendor/github.com/pb33f/libopenapi/what-changed/model/schema.go create mode 100644 vendor/github.com/pb33f/libopenapi/what-changed/model/scopes.go create mode 100644 vendor/github.com/pb33f/libopenapi/what-changed/model/security_requirement.go create mode 100644 vendor/github.com/pb33f/libopenapi/what-changed/model/security_scheme.go create mode 100644 vendor/github.com/pb33f/libopenapi/what-changed/model/server.go create mode 100644 vendor/github.com/pb33f/libopenapi/what-changed/model/server_variable.go create mode 100644 vendor/github.com/pb33f/libopenapi/what-changed/model/tags.go create mode 100644 vendor/github.com/pb33f/libopenapi/what-changed/model/xml.go create mode 100644 vendor/github.com/pb33f/libopenapi/what-changed/what_changed.go create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/collectors/collectors.go create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/collectors/dbstats_collector.go create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/collectors/expvar_collector.go create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/collectors/go_collector_go116.go create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/collectors/go_collector_latest.go create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/collectors/process_collector.go create mode 100644 vendor/github.com/santhosh-tekuri/jsonschema/v5/.gitignore create mode 100644 vendor/github.com/santhosh-tekuri/jsonschema/v5/.gitmodules create mode 100644 vendor/github.com/santhosh-tekuri/jsonschema/v5/LICENSE create mode 100644 vendor/github.com/santhosh-tekuri/jsonschema/v5/README.md create mode 100644 vendor/github.com/santhosh-tekuri/jsonschema/v5/compiler.go create mode 100644 vendor/github.com/santhosh-tekuri/jsonschema/v5/content.go create mode 100644 vendor/github.com/santhosh-tekuri/jsonschema/v5/doc.go create mode 100644 vendor/github.com/santhosh-tekuri/jsonschema/v5/draft.go create mode 100644 vendor/github.com/santhosh-tekuri/jsonschema/v5/errors.go create mode 100644 vendor/github.com/santhosh-tekuri/jsonschema/v5/extension.go create mode 100644 vendor/github.com/santhosh-tekuri/jsonschema/v5/format.go create mode 100644 vendor/github.com/santhosh-tekuri/jsonschema/v5/loader.go create mode 100644 vendor/github.com/santhosh-tekuri/jsonschema/v5/output.go create mode 100644 vendor/github.com/santhosh-tekuri/jsonschema/v5/resource.go create mode 100644 vendor/github.com/santhosh-tekuri/jsonschema/v5/schema.go create mode 100644 vendor/github.com/senseyeio/duration/.travis.yml create mode 100644 vendor/github.com/senseyeio/duration/LICENSE create mode 100644 vendor/github.com/senseyeio/duration/README.md create mode 100644 vendor/github.com/senseyeio/duration/coveralls.bash create mode 100644 vendor/github.com/senseyeio/duration/duration.go create mode 100644 vendor/github.com/serverlessworkflow/sdk-go/v2/LICENSE create mode 100644 vendor/github.com/serverlessworkflow/sdk-go/v2/model/action.go create mode 100644 vendor/github.com/serverlessworkflow/sdk-go/v2/model/action_data_filter.go create mode 100644 vendor/github.com/serverlessworkflow/sdk-go/v2/model/auth.go create mode 100644 vendor/github.com/serverlessworkflow/sdk-go/v2/model/callback_state.go create mode 100644 vendor/github.com/serverlessworkflow/sdk-go/v2/model/common.go create mode 100644 vendor/github.com/serverlessworkflow/sdk-go/v2/model/delay_state.go create mode 100644 vendor/github.com/serverlessworkflow/sdk-go/v2/model/doc.go create mode 100644 vendor/github.com/serverlessworkflow/sdk-go/v2/model/event.go create mode 100644 vendor/github.com/serverlessworkflow/sdk-go/v2/model/event_data_filter.go create mode 100644 vendor/github.com/serverlessworkflow/sdk-go/v2/model/event_state.go create mode 100644 vendor/github.com/serverlessworkflow/sdk-go/v2/model/event_validator.go create mode 100644 vendor/github.com/serverlessworkflow/sdk-go/v2/model/foreach_state.go create mode 100644 vendor/github.com/serverlessworkflow/sdk-go/v2/model/foreach_state_validator.go create mode 100644 vendor/github.com/serverlessworkflow/sdk-go/v2/model/function.go create mode 100644 vendor/github.com/serverlessworkflow/sdk-go/v2/model/inject_state.go create mode 100644 vendor/github.com/serverlessworkflow/sdk-go/v2/model/object.go create mode 100644 vendor/github.com/serverlessworkflow/sdk-go/v2/model/operation_state.go create mode 100644 vendor/github.com/serverlessworkflow/sdk-go/v2/model/parallel_state.go create mode 100644 vendor/github.com/serverlessworkflow/sdk-go/v2/model/parallel_state_validator.go create mode 100644 vendor/github.com/serverlessworkflow/sdk-go/v2/model/retry.go create mode 100644 vendor/github.com/serverlessworkflow/sdk-go/v2/model/retry_validator.go create mode 100644 vendor/github.com/serverlessworkflow/sdk-go/v2/model/sleep_state.go create mode 100644 vendor/github.com/serverlessworkflow/sdk-go/v2/model/state_exec_timeout.go create mode 100644 vendor/github.com/serverlessworkflow/sdk-go/v2/model/states.go create mode 100644 vendor/github.com/serverlessworkflow/sdk-go/v2/model/states_validator.go create mode 100644 vendor/github.com/serverlessworkflow/sdk-go/v2/model/switch_state.go create mode 100644 vendor/github.com/serverlessworkflow/sdk-go/v2/model/switch_state_validator.go create mode 100644 vendor/github.com/serverlessworkflow/sdk-go/v2/model/util.go create mode 100644 vendor/github.com/serverlessworkflow/sdk-go/v2/model/workflow.go create mode 100644 vendor/github.com/serverlessworkflow/sdk-go/v2/model/workflow_ref.go create mode 100644 vendor/github.com/serverlessworkflow/sdk-go/v2/model/workflow_validator.go create mode 100644 vendor/github.com/serverlessworkflow/sdk-go/v2/model/zz_generated.deepcopy.go create mode 100644 vendor/github.com/serverlessworkflow/sdk-go/v2/parser/parser.go create mode 100644 vendor/github.com/serverlessworkflow/sdk-go/v2/util/floatstr/floatstr.go create mode 100644 vendor/github.com/serverlessworkflow/sdk-go/v2/validator/tags.go create mode 100644 vendor/github.com/serverlessworkflow/sdk-go/v2/validator/validator.go create mode 100644 vendor/github.com/vmware-labs/yaml-jsonpath/LICENSE create mode 100644 vendor/github.com/vmware-labs/yaml-jsonpath/NOTICE create mode 100644 vendor/github.com/vmware-labs/yaml-jsonpath/pkg/yamlpath/comparison.go create mode 100644 vendor/github.com/vmware-labs/yaml-jsonpath/pkg/yamlpath/doc.go create mode 100644 vendor/github.com/vmware-labs/yaml-jsonpath/pkg/yamlpath/filter.go create mode 100644 vendor/github.com/vmware-labs/yaml-jsonpath/pkg/yamlpath/filter_parser.go create mode 100644 vendor/github.com/vmware-labs/yaml-jsonpath/pkg/yamlpath/lexer.go create mode 100644 vendor/github.com/vmware-labs/yaml-jsonpath/pkg/yamlpath/path.go create mode 100644 vendor/github.com/vmware-labs/yaml-jsonpath/pkg/yamlpath/slicer.go create mode 100644 vendor/golang.org/x/crypto/sha3/doc.go create mode 100644 vendor/golang.org/x/crypto/sha3/hashes.go create mode 100644 vendor/golang.org/x/crypto/sha3/hashes_generic.go create mode 100644 vendor/golang.org/x/crypto/sha3/keccakf.go create mode 100644 vendor/golang.org/x/crypto/sha3/keccakf_amd64.go create mode 100644 vendor/golang.org/x/crypto/sha3/keccakf_amd64.s create mode 100644 vendor/golang.org/x/crypto/sha3/register.go create mode 100644 vendor/golang.org/x/crypto/sha3/sha3.go create mode 100644 vendor/golang.org/x/crypto/sha3/sha3_s390x.go create mode 100644 vendor/golang.org/x/crypto/sha3/sha3_s390x.s create mode 100644 vendor/golang.org/x/crypto/sha3/shake.go create mode 100644 vendor/golang.org/x/crypto/sha3/shake_generic.go create mode 100644 vendor/golang.org/x/crypto/sha3/xor.go create mode 100644 vendor/golang.org/x/crypto/sha3/xor_generic.go create mode 100644 vendor/golang.org/x/crypto/sha3/xor_unaligned.go create mode 100644 vendor/golang.org/x/net/internal/socks/client.go create mode 100644 vendor/golang.org/x/net/internal/socks/socks.go create mode 100644 vendor/golang.org/x/net/proxy/dial.go create mode 100644 vendor/golang.org/x/net/proxy/direct.go create mode 100644 vendor/golang.org/x/net/proxy/per_host.go create mode 100644 vendor/golang.org/x/net/proxy/proxy.go create mode 100644 vendor/golang.org/x/net/proxy/socks5.go create mode 100644 vendor/golang.org/x/sync/syncmap/go19.go create mode 100644 vendor/golang.org/x/sync/syncmap/map.go create mode 100644 vendor/golang.org/x/sync/syncmap/pre_go19.go create mode 100644 vendor/golang.org/x/sys/cpu/asm_aix_ppc64.s create mode 100644 vendor/golang.org/x/sys/cpu/byteorder.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_aix.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_arm.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_arm64.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_arm64.s create mode 100644 vendor/golang.org/x/sys/cpu/cpu_gc_arm64.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_gc_s390x.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_gc_x86.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_gccgo_arm64.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_gccgo_s390x.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.c create mode 100644 vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_linux.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_linux_arm.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_linux_arm64.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_linux_mips64x.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_linux_noinit.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_linux_ppc64x.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_linux_s390x.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_loong64.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_mips64x.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_mipsx.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_netbsd_arm64.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_openbsd_arm64.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_openbsd_arm64.s create mode 100644 vendor/golang.org/x/sys/cpu/cpu_other_arm.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_other_arm64.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_other_mips64x.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_other_ppc64x.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_other_riscv64.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_ppc64x.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_riscv64.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_s390x.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_s390x.s create mode 100644 vendor/golang.org/x/sys/cpu/cpu_wasm.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_x86.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_x86.s create mode 100644 vendor/golang.org/x/sys/cpu/cpu_zos.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_zos_s390x.go create mode 100644 vendor/golang.org/x/sys/cpu/endian_big.go create mode 100644 vendor/golang.org/x/sys/cpu/endian_little.go create mode 100644 vendor/golang.org/x/sys/cpu/hwcap_linux.go create mode 100644 vendor/golang.org/x/sys/cpu/parse.go create mode 100644 vendor/golang.org/x/sys/cpu/proc_cpuinfo_linux.go create mode 100644 vendor/golang.org/x/sys/cpu/runtime_auxv.go create mode 100644 vendor/golang.org/x/sys/cpu/runtime_auxv_go121.go create mode 100644 vendor/golang.org/x/sys/cpu/syscall_aix_gccgo.go create mode 100644 vendor/golang.org/x/sys/cpu/syscall_aix_ppc64_gc.go create mode 100644 vendor/golang.org/x/tools/cmd/stringer/stringer.go create mode 100644 vendor/google.golang.org/grpc/internal/envconfig/observability.go create mode 100644 vendor/google.golang.org/grpc/internal/grpcsync/oncefunc.go create mode 100644 vendor/google.golang.org/grpc/internal/grpcutil/compressor.go create mode 100644 vendor/k8s.io/api/admission/v1/doc.go create mode 100644 vendor/k8s.io/api/admission/v1/generated.pb.go create mode 100644 vendor/k8s.io/api/admission/v1/generated.proto create mode 100644 vendor/k8s.io/api/admission/v1/register.go create mode 100644 vendor/k8s.io/api/admission/v1/types.go create mode 100644 vendor/k8s.io/api/admission/v1/types_swagger_doc_generated.go create mode 100644 vendor/k8s.io/api/admission/v1/zz_generated.deepcopy.go create mode 100644 vendor/k8s.io/api/admission/v1beta1/doc.go create mode 100644 vendor/k8s.io/api/admission/v1beta1/generated.pb.go create mode 100644 vendor/k8s.io/api/admission/v1beta1/generated.proto create mode 100644 vendor/k8s.io/api/admission/v1beta1/register.go create mode 100644 vendor/k8s.io/api/admission/v1beta1/types.go create mode 100644 vendor/k8s.io/api/admission/v1beta1/types_swagger_doc_generated.go create mode 100644 vendor/k8s.io/api/admission/v1beta1/zz_generated.deepcopy.go create mode 100644 vendor/k8s.io/api/admission/v1beta1/zz_generated.prerelease-lifecycle.go create mode 100644 vendor/k8s.io/apimachinery/pkg/apis/meta/internalversion/scheme/doc.go create mode 100644 vendor/k8s.io/apimachinery/pkg/apis/meta/internalversion/scheme/register.go create mode 100644 vendor/k8s.io/client-go/metadata/interface.go create mode 100644 vendor/k8s.io/client-go/metadata/metadata.go create mode 100644 vendor/k8s.io/component-base/LICENSE create mode 100644 vendor/k8s.io/component-base/config/doc.go create mode 100644 vendor/k8s.io/component-base/config/types.go create mode 100644 vendor/k8s.io/component-base/config/v1alpha1/conversion.go create mode 100644 vendor/k8s.io/component-base/config/v1alpha1/defaults.go create mode 100644 vendor/k8s.io/component-base/config/v1alpha1/doc.go create mode 100644 vendor/k8s.io/component-base/config/v1alpha1/register.go create mode 100644 vendor/k8s.io/component-base/config/v1alpha1/types.go create mode 100644 vendor/k8s.io/component-base/config/v1alpha1/zz_generated.conversion.go create mode 100644 vendor/k8s.io/component-base/config/v1alpha1/zz_generated.deepcopy.go create mode 100644 vendor/k8s.io/component-base/config/zz_generated.deepcopy.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/.gitignore create mode 100644 vendor/sigs.k8s.io/controller-runtime/.golangci.yml create mode 100644 vendor/sigs.k8s.io/controller-runtime/CONTRIBUTING.md create mode 100644 vendor/sigs.k8s.io/controller-runtime/FAQ.md create mode 100644 vendor/sigs.k8s.io/controller-runtime/LICENSE create mode 100644 vendor/sigs.k8s.io/controller-runtime/Makefile create mode 100644 vendor/sigs.k8s.io/controller-runtime/README.md create mode 100644 vendor/sigs.k8s.io/controller-runtime/RELEASE.md create mode 100644 vendor/sigs.k8s.io/controller-runtime/SECURITY_CONTACTS create mode 100644 vendor/sigs.k8s.io/controller-runtime/TMP-LOGGING.md create mode 100644 vendor/sigs.k8s.io/controller-runtime/VERSIONING.md create mode 100644 vendor/sigs.k8s.io/controller-runtime/alias.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/code-of-conduct.md create mode 100644 vendor/sigs.k8s.io/controller-runtime/doc.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/builder/controller.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/builder/doc.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/builder/options.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/builder/webhook.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/cache/cache.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/cache/doc.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/cache/informer_cache.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/cache/internal/cache_reader.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/cache/internal/deleg_map.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/cache/internal/disabledeepcopy.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/cache/internal/informers_map.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/cache/internal/selector.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/cache/internal/transformers.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/cache/multi_namespace_cache.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/certwatcher/certwatcher.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/certwatcher/doc.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/certwatcher/metrics/metrics.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/client/apiutil/apimachinery.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/client/apiutil/dynamicrestmapper.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/client/client.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/client/client_cache.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/client/codec.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/client/config/config.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/client/config/doc.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/client/doc.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/client/dryrun.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/client/interfaces.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/client/metadata_client.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/client/namespaced_client.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/client/object.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/client/options.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/client/patch.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/client/split.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/client/typed_client.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/client/unstructured_client.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/client/watch.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/cluster/cluster.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/cluster/internal.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/config/config.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/config/doc.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/config/v1alpha1/doc.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/config/v1alpha1/register.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/config/v1alpha1/types.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/config/v1alpha1/zz_generated.deepcopy.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/controller/controller.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/controller/controllerutil/controllerutil.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/controller/controllerutil/doc.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/controller/doc.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/conversion/conversion.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/event/doc.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/event/event.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/handler/doc.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/handler/enqueue.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/handler/enqueue_mapped.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/handler/enqueue_owner.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/handler/eventhandler.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/healthz/doc.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/healthz/healthz.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/internal/controller/controller.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/internal/controller/metrics/metrics.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/internal/httpserver/server.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/internal/log/log.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/internal/objectutil/objectutil.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/internal/recorder/recorder.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/leaderelection/doc.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/leaderelection/leader_election.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/log/deleg.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/log/log.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/log/null.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/log/warning_handler.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/manager/doc.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/manager/internal.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/manager/manager.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/manager/runnable_group.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/manager/signals/doc.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/manager/signals/signal.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/manager/signals/signal_posix.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/manager/signals/signal_windows.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/metrics/client_go_adapter.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/metrics/doc.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/metrics/listener.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/metrics/registry.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/metrics/workqueue.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/predicate/doc.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/predicate/predicate.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/ratelimiter/doc.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/ratelimiter/ratelimiter.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/reconcile/doc.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/reconcile/reconcile.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/recorder/recorder.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/runtime/inject/doc.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/runtime/inject/inject.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/scheme/scheme.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/source/doc.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/source/internal/eventsource.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/source/source.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/decode.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/defaulter.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/defaulter_custom.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/doc.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/http.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/inject.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/multi.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/response.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/validator.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/validator_custom.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/webhook.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/webhook/alias.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/webhook/conversion/conversion.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/webhook/conversion/decoder.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/webhook/doc.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/webhook/internal/metrics/metrics.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/webhook/server.go diff --git a/go.mod b/go.mod index 6fb4e33c3c..8a6e2745a4 100644 --- a/go.mod +++ b/go.mod @@ -6,6 +6,7 @@ require ( github.com/google/go-cmp v0.5.9 github.com/hashicorp/golang-lru v0.5.4 github.com/hashicorp/hcl v1.0.0 + github.com/kiegroup/kie-tools/packages/kn-plugin-workflow v0.30.1 github.com/mitchellh/go-homedir v1.1.0 github.com/spf13/afero v1.9.3 // indirect github.com/spf13/cobra v1.6.1 @@ -24,13 +25,11 @@ require ( knative.dev/eventing v0.36.7 knative.dev/hack v0.0.0-20230217102752-199139daec7e knative.dev/networking v0.0.0-20230225001731-5e096d63b0cb - knative.dev/pkg v0.0.0-20230224205330-75da922ef055 + knative.dev/pkg v0.0.0-20230525143525-9bda38b21643 knative.dev/serving v0.36.4 sigs.k8s.io/yaml v1.3.0 ) -require github.com/kiegroup/kie-tools/packages/kn-plugin-workflow v0.28.0 - require ( cloud.google.com/go/compute v1.10.0 // indirect contrib.go.opencensus.io/exporter/ocagent v0.7.1-0.20200907061046-05415f1de66d // indirect @@ -41,6 +40,7 @@ require ( github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect github.com/Azure/go-autorest/logger v0.2.1 // indirect github.com/Azure/go-autorest/tracing v0.6.0 // indirect + github.com/Microsoft/go-winio v0.6.1 // indirect github.com/antlr/antlr4/runtime/Go/antlr v1.4.10 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/blendle/zapdriver v1.3.1 // indirect @@ -52,6 +52,11 @@ require ( github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dgraph-io/ristretto v0.0.1 // indirect + github.com/docker/distribution v2.8.2+incompatible // indirect + github.com/docker/docker v23.0.6+incompatible // indirect + github.com/docker/go-connections v0.4.0 // indirect + github.com/docker/go-units v0.5.0 // indirect + github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // indirect github.com/emicklei/go-restful/v3 v3.9.0 // indirect github.com/evanphx/json-patch v5.6.0+incompatible // indirect github.com/evanphx/json-patch/v5 v5.6.0 // indirect @@ -63,6 +68,9 @@ require ( github.com/go-openapi/jsonpointer v0.19.6 // indirect github.com/go-openapi/jsonreference v0.20.1 // indirect github.com/go-openapi/swag v0.22.3 // indirect + github.com/go-playground/locales v0.14.0 // indirect + github.com/go-playground/universal-translator v0.18.0 // indirect + github.com/go-playground/validator/v10 v10.11.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang-jwt/jwt/v4 v4.4.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect @@ -80,6 +88,9 @@ require ( github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/kelseyhightower/envconfig v1.4.0 // indirect + github.com/kiegroup/kogito-serverless-operator/api v1.40.0 // indirect + github.com/kiegroup/kogito-serverless-operator/workflowproj v1.40.0 // indirect + github.com/leodido/go-urn v1.2.1 // indirect github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/mailru/easyjson v0.7.7 // indirect @@ -90,8 +101,10 @@ require ( github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect + github.com/opencontainers/image-spec v1.0.3-0.20220114050600-8b9d41f48198 // indirect github.com/openzipkin/zipkin-go v0.4.0 // indirect github.com/ory/viper v1.7.5 // indirect + github.com/pb33f/libopenapi v0.8.4 // indirect github.com/pelletier/go-toml v1.9.5 // indirect github.com/pelletier/go-toml/v2 v2.0.5 // indirect github.com/peterbourgon/diskv v2.0.1+incompatible // indirect @@ -104,18 +117,21 @@ require ( github.com/rickb777/date v1.20.0 // indirect github.com/rickb777/plural v1.4.1 // indirect github.com/robfig/cron/v3 v3.0.1 // indirect - github.com/rogpeppe/go-internal v1.8.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/santhosh-tekuri/jsonschema/v5 v5.3.0 // indirect + github.com/senseyeio/duration v0.0.0-20180430131211-7c2a214ada46 // indirect github.com/sergi/go-diff v1.2.0 // indirect + github.com/serverlessworkflow/sdk-go/v2 v2.2.3 // indirect github.com/spf13/cast v1.5.0 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/subosito/gotenv v1.4.1 // indirect + github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect github.com/xlab/treeprint v1.1.0 // indirect go.opencensus.io v0.23.0 // indirect go.starlark.net v0.0.0-20220817180228-f738f5508c12 // indirect go.uber.org/atomic v1.10.0 // indirect go.uber.org/multierr v1.9.0 // indirect - go.uber.org/zap v1.23.0 // indirect + go.uber.org/zap v1.24.0 // indirect golang.org/x/crypto v0.8.0 // indirect golang.org/x/net v0.10.0 // indirect golang.org/x/oauth2 v0.7.0 // indirect @@ -128,16 +144,18 @@ require ( google.golang.org/api v0.96.0 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto v0.0.0-20220919141832-68c03719ef51 // indirect - google.golang.org/grpc v1.49.0 // indirect + google.golang.org/grpc v1.51.0 // indirect google.golang.org/protobuf v1.30.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect + k8s.io/component-base v0.27.2 // indirect k8s.io/gengo v0.0.0-20221011193443-fad74ee6edd9 // indirect k8s.io/klog/v2 v2.90.1 // indirect k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f // indirect k8s.io/utils v0.0.0-20230313181309-38a27ef9d749 // indirect + sigs.k8s.io/controller-runtime v0.15.0 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/kustomize/api v0.12.1 // indirect sigs.k8s.io/kustomize/kyaml v0.13.9 // indirect @@ -160,4 +178,5 @@ replace ( knative.dev/networking => knative.dev/networking v0.0.0-20230225001731-5e096d63b0cb knative.dev/pkg => knative.dev/pkg v0.0.0-20230224205330-75da922ef055 knative.dev/serving => knative.dev/serving v0.36.4 + sigs.k8s.io/controller-runtime => sigs.k8s.io/controller-runtime v0.13.0 ) diff --git a/go.sum b/go.sum index eba80ccacc..2303d13993 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +4d63.com/gochecknoglobals v0.1.0/go.mod h1:wfdC5ZjKSPr7CybKEcgJhUOgeAQW1+7WcyK8OvUilfo= +bitbucket.org/creachadair/shell v0.0.6/go.mod h1:8Qqi/cYk7vPnsOePHroKXDJYmb5x7ENhtiFtfZq8K+M= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= @@ -12,6 +14,7 @@ cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6 cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.60.0/go.mod h1:yw2G51M9IfRboUH61Us8GqCeF1PzPblB823Mn2q2eAU= cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= @@ -46,11 +49,15 @@ cloud.google.com/go/compute v1.10.0 h1:aoLIYaA1fX3ywihqpBk2APQKOo20nXsp1GEZQbx5J cloud.google.com/go/compute v1.10.0/go.mod h1:ER5CLbMxl90o2jtNbGSbtfOpQKR0t15FOtRsugnLrlU= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= +cloud.google.com/go/firestore v1.6.0/go.mod h1:afJwI0vaXwAG54kI7A//lP/lSPDkQORQuMkv56TxEPU= cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/pubsub v1.5.0/go.mod h1:ZEwJccE3z93Z2HWvstpri00jOg7oO4UZDtKhwDwqF0w= +cloud.google.com/go/spanner v1.7.0/go.mod h1:sd3K2gZ9Fd0vMPLXzeCrF6fq4i63Q7aTLW/lBIfBkIk= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= @@ -62,7 +69,11 @@ contrib.go.opencensus.io/exporter/ocagent v0.7.1-0.20200907061046-05415f1de66d h contrib.go.opencensus.io/exporter/ocagent v0.7.1-0.20200907061046-05415f1de66d/go.mod h1:IshRmMJBhDfFj5Y67nVhMYTTIze91RUeT73ipWKs/GY= contrib.go.opencensus.io/exporter/prometheus v0.4.2 h1:sqfsYl5GIY/L570iT+l93ehxaWJs2/OwXtiWwew3oAg= contrib.go.opencensus.io/exporter/prometheus v0.4.2/go.mod h1:dvEHbiKmgvbr5pjaF9fpw1KeYcjrnC1J8B+JKjsZyRQ= +contrib.go.opencensus.io/exporter/stackdriver v0.13.4/go.mod h1:aXENhDJ1Y4lIg4EUaVTwzvYETVNZk10Pu26tevFKLUc= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/Antonboom/errname v0.1.5/go.mod h1:DugbBstvPFQbv/5uLcRRzfrNqKE9tVdVCqWCLp6Cifo= +github.com/Antonboom/nilnil v0.1.0/go.mod h1:PhHLvRPSghY5Y7mX4TW+BHZQYo1A8flE5H20D3IPZBo= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs= github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/Azure/go-autorest/autorest v0.11.28 h1:ndAExarwr5Y+GaHE6VCaY1kyS/HwwGGyuimVhWsHOEM= @@ -80,28 +91,61 @@ github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZ github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo= github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24/go.mod h1:4UJr5HIiMZrwgkSPdsjy2uOQExX/WEILpIrO9UPGuXs= +github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= +github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= +github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= +github.com/Masterminds/sprig v2.15.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= +github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= +github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= +github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/OpenPeeDeeP/depguard v1.0.1/go.mod h1:xsIw86fROiiwelg+jB2uM9PiKihMMmUx/1V+TNhjQvM= github.com/Shopify/sarama v1.30.0/go.mod h1:zujlQQx1kzHsh4jfV1USnptCQrHAEZ2Hk8fTKCulPVs= github.com/Shopify/toxiproxy/v2 v2.1.6-0.20210914104332-15ea381dcdae/go.mod h1:/cvHQkZ1fst0EmZnA5dFtiQdWCNCFYzb+uE2vqVgvx0= +github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= +github.com/alexkohler/prealloc v1.0.0/go.mod h1:VetnK3dIgFBBKmg0YnD9F9x6Icjd+9cvfHR56wJVlKE= +github.com/andybalholm/brotli v1.0.2/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= +github.com/andybalholm/brotli v1.0.3/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/antihax/optional v0.0.0-20180407024304-ca021399b1a6/go.mod h1:V8iCPQYkqmusNa815XgQio277wI47sdRh1dUOLdyC6Q= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/antlr/antlr4/runtime/Go/antlr v1.4.10 h1:yL7+Jz0jTC6yykIK/Wh74gnTJnrGr5AyrNMXuA0gves= github.com/antlr/antlr4/runtime/Go/antlr v1.4.10/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY= +github.com/aokoli/goutils v1.0.1/go.mod h1:SijmP0QR8LtwsmDs8Yii5Z/S4trXFGFC2oO5g9DP+DQ= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/ashanbrown/forbidigo v1.2.0/go.mod h1:vVW7PEdqEFqapJe95xHkTfB1+XvZXBFg8t0sG2FIxmI= +github.com/ashanbrown/makezero v0.0.0-20210520155254-b6261585ddde/go.mod h1:oG9Dnez7/ESBqc4EdrdNlryeo7d0KcW1ftXHm7nU/UU= +github.com/aws/aws-sdk-go v1.23.20/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.25.37/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.36.30/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM= +github.com/bkielbasa/cyclop v1.2.0/go.mod h1:qOI0yy6A7dYC4Zgsa72Ppm9kONl0RoIlPbzot9mhmeI= github.com/blendle/zapdriver v1.3.1 h1:C3dydBOWYRiOk+B8X9IVZ5IOe+7cl+tGOexN4QqHfpE= github.com/blendle/zapdriver v1.3.1/go.mod h1:mdXfREi6u5MArG4j9fewC+FGnXaBR+T4Ox4J2u4eHCc= +github.com/blizzy78/varnamelen v0.3.0/go.mod h1:hbwRdBvoBqxk34XyQ6HA0UH3G0/1TKuv5AC4eaBT0Ec= +github.com/bombsimon/wsl/v3 v3.3.0/go.mod h1:st10JtZYLE4D5sC7b8xV4zTKZwAQjCH/Hy2Pm1FNZIc= +github.com/breml/bidichk v0.1.1/go.mod h1:zbfeitpevDUGI7V91Uzzuwrn4Vls8MoBMrwtt78jmso= github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= +github.com/butuzov/ireturn v0.1.1/go.mod h1:Wh6Zl3IMtTpaIKbmwzqi6olnM9ptYQxxVacMsOEFPoc= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.3.0 h1:t/LhUZLVitR1Ow2YOnduCsavhwFUklBMoGVYUCqmCqk= github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= @@ -111,6 +155,8 @@ github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/charithe/durationcheck v0.0.9/go.mod h1:SSbRIBVfMjCi/kEB6K65XEA83D6prSM8ap1UCpNKtgg= +github.com/chavacava/garif v0.0.0-20210405164556-e8a0a408d6af/go.mod h1:Qjyv4H3//PWVzTeCezG2b9IRn6myJxJSr4TD/xo6ojU= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= @@ -128,18 +174,48 @@ github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWH github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20190620071333-e64a0ec8b42a/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/daixiang0/gci v0.2.9/go.mod h1:+4dZ7TISfSmqfAGv59ePaHfNzgGtIkHAhhdKggP1JAc= +github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/denis-tingajkin/go-header v0.4.2/go.mod h1:eLRHAVXzE5atsKAnNRDB90WHCFFnBUn4RN0nRcs1LJA= github.com/dgraph-io/ristretto v0.0.1 h1:cJwdnj42uV8Jg4+KLrYovLiCgIfz9wtWm6E6KA+1tLs= github.com/dgraph-io/ristretto v0.0.1/go.mod h1:T40EBc7CJke8TkpiYfGGKAeFjSaxuFXhuXRyumBd6RE= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= +github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v23.0.6+incompatible h1:aBD4np894vatVX99UTx/GyOUOK4uEcROwA3+bQhEcoU= +github.com/docker/docker v23.0.6+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= +github.com/dprotaso/go-yit v0.0.0-20191028211022-135eb7262960/go.mod h1:9HQzr9D/0PGwMEbC3d5AB7oi67+h4TsQqItC1GVYG58= +github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 h1:PRxIJD8XjimM5aTknUK9w6DHLDox2r2M3DI4i2pnd3w= +github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936/go.mod h1:ttYvX5qlB+mlV1okblJqcSMtR4c52UKxDiX9GRBS8+Q= +github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/eapache/go-resiliency v1.2.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= @@ -154,20 +230,32 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.m github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= +github.com/envoyproxy/protoc-gen-validate v0.0.14/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/esimonov/ifshort v1.0.3/go.mod h1:yZqNJUrNn20K8Q9n2CrjTKYyVEmX209Hgu+M1LBpeZE= +github.com/ettle/strcase v0.1.1/go.mod h1:hzDLsPC7/lwKyBOywSHEP89nt2pDgdy+No1NBA9o9VY= github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U= github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= +github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94= github.com/flowstack/go-jsonschema v0.1.1/go.mod h1:yL7fNggx1o8rm9RlgXv7hTBWxdBM0rVwpMwimd3F3N0= github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +github.com/fullstorydev/grpcurl v1.6.0/go.mod h1:ZQ+ayqbKMJNhzLmbpCiurTVlaK2M/3nqZCxaQ2Ze/sM= +github.com/fzipp/gocyclo v0.3.1/go.mod h1:DJHO6AUmbdqj2ET4Z9iArSuwWgYDRryYt2wASxc7x3E= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-critic/go-critic v0.6.1/go.mod h1:SdNCfU0yF3UBjtaZGw6586/WocupMOJuiqgom5DsQxM= github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= @@ -188,15 +276,47 @@ github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTg github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/zapr v1.2.3 h1:a9vnzlIBPQBBkeaR9IuMUfmVOrQlkoC4YfPoFkX3T7A= +github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= github.com/go-openapi/jsonreference v0.20.1 h1:FBLnyygC4/IZZr893oiomc9XaghoveYTrLC1F86HID8= github.com/go-openapi/jsonreference v0.20.1/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= +github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU= +github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= +github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho= +github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= +github.com/go-playground/validator/v10 v10.11.1 h1:prmOlTVv+YjZjmRmNSF3VmspqJIxJWXmqUsHwfTRRkQ= +github.com/go-playground/validator/v10 v10.11.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU= +github.com/go-redis/redis v6.15.8+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= +github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/go-toolsmith/astcast v1.0.0/go.mod h1:mt2OdQTeAQcY4DQgPSArJjHCcOwlX+Wl/kwN+LbLGQ4= +github.com/go-toolsmith/astcopy v1.0.0/go.mod h1:vrgyG+5Bxrnz4MZWPF+pI4R8h3qKRjjyvV/DSez4WVQ= +github.com/go-toolsmith/astequal v1.0.0/go.mod h1:H+xSiq0+LtiDC11+h1G32h7Of5O3CYFJ99GVbS5lDKY= +github.com/go-toolsmith/astequal v1.0.1/go.mod h1:4oGA3EZXTVItV/ipGiOx7NWkY5veFfcsOJVS2YxltLw= +github.com/go-toolsmith/astfmt v1.0.0/go.mod h1:cnWmsOAuq4jJY6Ct5YWlVLmcmLMn1JUPuQIHCY7CJDw= +github.com/go-toolsmith/astinfo v0.0.0-20180906194353-9809ff7efb21/go.mod h1:dDStQCHtmZpYOmjRP/8gHHnCCch3Zz3oEgCdZVdtweU= +github.com/go-toolsmith/astp v1.0.0/go.mod h1:RSyrtpVlfTFGDYRbrjyWP1pYu//tSFcvdYrA8meBmLI= +github.com/go-toolsmith/pkgload v1.0.0/go.mod h1:5eFArkbO80v7Z0kdngIxsRXRMTaX4Ilcwuh3clNrQJc= +github.com/go-toolsmith/strparse v1.0.0/go.mod h1:YI2nUKP9YGZnL/L1/DLFBfixrcjslWct4wyljWhSRy8= +github.com/go-toolsmith/typep v1.0.0/go.mod h1:JSQCQMUPdRlMZFswiq3TGpNp1GMktqkR2Ns5AIQkATU= +github.com/go-toolsmith/typep v1.0.2/go.mod h1:JSQCQMUPdRlMZFswiq3TGpNp1GMktqkR2Ns5AIQkATU= +github.com/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM= +github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= @@ -204,6 +324,7 @@ github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzw github.com/golang-jwt/jwt/v4 v4.4.2 h1:rcc4lwaZgFMCZ5jxF9ABolDcIHdBytAFgqFPbSJQAYs= github.com/golang-jwt/jwt/v4 v4.4.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -218,6 +339,7 @@ github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= +github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -239,10 +361,22 @@ github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2/go.mod h1:k9Qvh+8juN+UKMCS/3jFtGICgW8O96FVaZsaxdzDkR4= +github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a/go.mod h1:ryS0uhF+x9jgbj/N71xsEqODy9BN81/GonCZiOzirOk= +github.com/golangci/go-misc v0.0.0-20180628070357-927a3d87b613/go.mod h1:SyvUF2NxV+sN8upjjeVYr5W7tyxaT1JVtvhKhOn2ii8= +github.com/golangci/gofmt v0.0.0-20190930125516-244bba706f1a/go.mod h1:9qCChq59u/eW8im404Q2WWTrnBUQKjpNYKMbU4M7EFU= +github.com/golangci/golangci-lint v1.43.0/go.mod h1:VIFlUqidx5ggxDfQagdvd9E67UjMXtTHBkBQ7sHoC5Q= +github.com/golangci/lint-1 v0.0.0-20191013205115-297bf364a8e0/go.mod h1:66R6K6P6VWk9I95jvqGxkqJxVWGFy9XlDwLwVz1RCFg= +github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca/go.mod h1:tvlJhZqDe4LMs4ZHD0oMUlt9G2LWuDGoisJTBzLMV9o= +github.com/golangci/misspell v0.3.5/go.mod h1:dEbvlSfYbMQDtrpRMQU675gSDLDNa8sCPPChZ7PhiVA= +github.com/golangci/revgrep v0.0.0-20210930125155-c22e5001d4f2/go.mod h1:LK+zW4MpyytAWQRz0M4xnzEk50lSvqDQKfx304apFkY= +github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4/go.mod h1:Izgrg8RkN3rCIMLGE9CyYmU9pY2Jer6DgANEnZ/L/cQ= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= +github.com/google/certificate-transparency-go v1.0.21/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg= +github.com/google/certificate-transparency-go v1.1.1/go.mod h1:FDKqPvSXawb2ecErVRrD+nfy23RCzyl7eqVCEmlT1Zs= github.com/google/gnostic v0.6.9 h1:ZK/5VhkoX835RikCHpSUJV9a+S3e1zLh59YnyWeBW+0= github.com/google/gnostic v0.6.9/go.mod h1:Nm8234We1lq6iB9OmlgNv3nH91XLLVZHCDayfA3xq+E= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -277,18 +411,24 @@ github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200507031123-427632fa3b1c/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= +github.com/google/trillian v1.3.11/go.mod h1:0tPraVHrSDkA3BO6vKX67zgLXs6SsOAbHEivX+9mPgw= +github.com/google/uuid v0.0.0-20161128191214-064e2069ce9c/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -303,27 +443,82 @@ github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99 github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c= github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= +github.com/gookit/color v1.4.2/go.mod h1:fqRyamkC1W8uxl+lxCQxOT09l/vYfZ+QeiX3rKQHCoQ= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gordonklaus/ineffassign v0.0.0-20200309095847-7953dde2c7bf/go.mod h1:cuNKsD1zp2v6XfE/orVX2QE1LC+i254ceGcVeDT3pTU= +github.com/gordonklaus/ineffassign v0.0.0-20210225214923-2e10b2664254/go.mod h1:M9mZEtGIsR1oDaZagNPNG9iq9n2HrhZ17dsXk73V3Lw= +github.com/gorhill/cronexpr v0.0.0-20180427100037-88b0669f7d75/go.mod h1:g2644b03hfBX9Ov0ZBDgXXens4rxSxmqFBbhvKv2yVA= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= +github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gostaticanalysis/analysisutil v0.0.0-20190318220348-4088753ea4d3/go.mod h1:eEOZF4jCKGi+aprrirO9e7WKB3beBRtWgqGunKl6pKE= +github.com/gostaticanalysis/analysisutil v0.0.3/go.mod h1:eEOZF4jCKGi+aprrirO9e7WKB3beBRtWgqGunKl6pKE= +github.com/gostaticanalysis/analysisutil v0.1.0/go.mod h1:dMhHRU9KTiDcuLGdy87/2gTR8WruwYZrKdRq9m1O6uw= +github.com/gostaticanalysis/analysisutil v0.4.1/go.mod h1:18U/DLpRgIUd459wGxVHE0fRgmo1UgHDcbw7F5idXu0= +github.com/gostaticanalysis/analysisutil v0.7.1/go.mod h1:v21E3hY37WKMGSnbsw2S/ojApNWb6C1//mXO48CXbVc= +github.com/gostaticanalysis/comment v1.3.0/go.mod h1:xMicKDx7XRXYdVwY9f9wQpDJVnqWxw9wCauCMKp+IBI= +github.com/gostaticanalysis/comment v1.4.1/go.mod h1:ih6ZxzTHLdadaiSnF5WY3dxUoXfXAlTaRzuaNDlSado= +github.com/gostaticanalysis/comment v1.4.2/go.mod h1:KLUTGDv6HOCotCH8h2erHKmpci2ZoR8VPu34YA2uzdM= +github.com/gostaticanalysis/forcetypeassert v0.0.0-20200621232751-01d4955beaa5/go.mod h1:qZEedyP/sY1lTGV1uJ3VhWZ2mqag3IkWsDHVbplHXak= +github.com/gostaticanalysis/nilerr v0.1.1/go.mod h1:wZYb6YI5YAxxq0i1+VJbY0s2YONW0HU0GPE3+5PWN4A= +github.com/gostaticanalysis/testutil v0.3.1-0.20210208050101-bfb5c8eec0e4/go.mod h1:D+FIZ+7OahH3ePw/izIEeH5I06eKs1IKI4Xr64/Am3M= +github.com/gostaticanalysis/testutil v0.4.0/go.mod h1:bLIoPefWXrRi/ssLFWX1dx7Repi5x3CuviD3dgAZaBU= github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA= github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-middleware v1.2.2/go.mod h1:EaizFBKfUKtMIF5iaDEhniwNedqGo9FuLFzppDr3uwI= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.12.1/go.mod h1:8XEsbTttt/W+VvjtQhLACqCisSPWTxCZ7sBRjU6iH9c= github.com/grpc-ecosystem/grpc-gateway v1.14.6/go.mod h1:zdiPV4Yse/1gnckTHtghG4GkDEdKCRJduHpTxT3/jcw= github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= +github.com/hashicorp/consul/api v1.10.1/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M= +github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= +github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= +github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg2DmyNY= +github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= +github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/huandu/xstrings v1.0.0/go.mod h1:4qWG/gcEcfX4z/mBDHJ++3ReCw9ibxbsNJbcucJdbSo= +github.com/huandu/xstrings v1.2.0/go.mod h1:DvyZB1rfVYsBIigL8HwpZgxHwXozlTgGqn63UyNX5k4= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.3.4/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc= github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= @@ -333,10 +528,22 @@ github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxy github.com/jcmturner/gokrb5/v8 v8.4.2/go.mod h1:sb+Xq/fTY5yktf/VxLsE3wlfPqQjp0aWNYyvBVK62bc= github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jgautheron/goconst v1.5.1/go.mod h1:aAosetZ5zaeC/2EfMeRswtxUFBpe2Hr7HzkgX4fanO4= +github.com/jhump/protoreflect v1.6.1/go.mod h1:RZQ/lnuN+zqeRVpQigTwO6o0AJUkxbnSnpuG7toUTG4= +github.com/jingyugao/rowserrcheck v1.1.1/go.mod h1:4yvlZSDb3IyDTUZJUmpZfm2Hwok+Dtp+nu2qOq+er9c= +github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af/go.mod h1:HEWGJkRDzjJY2sqdDwxccsGicWEf9BQOZsq2tV+xzM0= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= +github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/jonboulle/clockwork v0.2.0/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/josharian/txtarfs v0.0.0-20210218200122-0702f000015a/go.mod h1:izVPOvVRsHiKkeGCT6tYBNWyDVuzj9wAaBb5R9qamfw= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= @@ -344,42 +551,117 @@ github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHm github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/juju/ratelimit v1.0.1/go.mod h1:qapgC/Gy+xNh9UxzV13HGGl/6UXNN+ct+vwSgWNm/qk= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/julz/importas v0.0.0-20210419104244-841f0c0fe66d/go.mod h1:oSFU2R4XK/P7kNBrnL/FEQlDGN1/6WoxXEjSSXO0DV0= +github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8= github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= -github.com/kiegroup/kie-tools/packages/kn-plugin-workflow v0.28.0 h1:K/OkcvcwvkZBwW1JvroAKk8phoHWYdKnNJKUZwAhb+s= -github.com/kiegroup/kie-tools/packages/kn-plugin-workflow v0.28.0/go.mod h1:26y81DjhYK/rVL334xwze8C4J/AjuTlEHPe08gooQV8= +github.com/kiegroup/kie-tools/packages/kn-plugin-workflow v0.30.1 h1:2F4jQlSDry89jNEfnppI6hMfPnTlIOTplFWilWv/EVM= +github.com/kiegroup/kie-tools/packages/kn-plugin-workflow v0.30.1/go.mod h1:Bqvc3T5yJllsxi3Y4QPbigdsdE5sZ8eXlP8I+kHsCeg= +github.com/kiegroup/kogito-serverless-operator/api v1.40.0 h1:Mp9RLDS4h5rG9FJA2BrUfKbXcIi8pbln4iaeMa+fgWA= +github.com/kiegroup/kogito-serverless-operator/api v1.40.0/go.mod h1:5nAGodPBf6ebCjFtF7JKl40Ji0ptG0JwJNT/P0OupfE= +github.com/kiegroup/kogito-serverless-operator/workflowproj v1.40.0 h1:m37pPyVz4paQls4hdWZCiPkFf6yiB5aNvZ9bHuBFFIo= +github.com/kiegroup/kogito-serverless-operator/workflowproj v1.40.0/go.mod h1:0I0BmfULxZjRN7Lj1VsQtZ47k8g3ZRtEkJq5ODPr3HA= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/errcheck v1.6.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= +github.com/klauspost/compress v1.13.5/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kulti/thelper v0.4.0/go.mod h1:vMu2Cizjy/grP+jmsvOFDx1kYP6+PD1lqg4Yu5exl2U= +github.com/kunwardeep/paralleltest v1.0.3/go.mod h1:vLydzomDFpk7yu5UX02RmP0H8QfRPOV/oFhWN85Mjb4= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/kyoh86/exportloopref v0.1.8/go.mod h1:1tUcJeiioIs7VWe5gcOObrux3lb66+sBqGZrRkMwPgg= +github.com/ldez/gomoddirectives v0.2.2/go.mod h1:cpgBogWITnCfRq2qGoDkKMEVSaarhdBr6g8G04uz6d0= +github.com/ldez/tagliatelle v0.2.0/go.mod h1:8s6WJQwEYHbKZDsp/LjArytKOG8qaMrKQQ3mFukHs88= +github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= +github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= +github.com/letsencrypt/pkcs11key/v4 v4.0.0/go.mod h1:EFUvBDay26dErnNb70Nd0/VW3tJiIbETBPTl9ATXQag= +github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/lib/pq v1.9.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/lib/pq v1.10.3/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= +github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/maratori/testpackage v1.0.1/go.mod h1:ddKdw+XG0Phzhx8BFDTKgpWP4i7MpApTE5fXSKAqwDU= +github.com/matoous/godox v0.0.0-20210227103229-6504466cf951/go.mod h1:1BELzlh859Sh1c6+90blK8lbYy0kwQf1bYlBhBysy1s= +github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= +github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/mbilski/exhaustivestruct v1.2.0/go.mod h1:OeTBVxQWoEmB2J2JCHmXWPJ0aksxSUOUy+nvtVEfzXc= +github.com/mgechev/dots v0.0.0-20210922191527-e955255bf517/go.mod h1:KQ7+USdGKfpPjXk4Ga+5XxQM4Lm4e3gAogrreFAYpOg= +github.com/mgechev/revive v1.1.2/go.mod h1:bnXsMr+ZTH09V5rssEI+jHAZ4z+ZdyhgO/zsy3EhK+0= +github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= +github.com/miekg/dns v1.1.35/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= +github.com/miekg/pkcs11 v1.0.2/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= +github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= +github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= +github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-ps v1.0.0/go.mod h1:J4lOc8z8yJs6vUwklHw2XEIiT4z4C40KtWVN3nvg8Pg= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= +github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= +github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.4.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -387,46 +669,90 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0= github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4= +github.com/moricho/tparallel v0.2.1/go.mod h1:fXEIZxG2vdfl0ZF8b42f5a78EhjjD5mX8qUplsoSU4k= +github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= +github.com/mozilla/scribe v0.0.0-20180711195314-fb71baf557c1/go.mod h1:FIczTrinKo8VaLxe6PWTPEXRXDIHz2QAwiaBaP5/4a8= +github.com/mozilla/tls-observatory v0.0.0-20210609171429-7bc42856d2e5/go.mod h1:FUqVoUPHSEdDR0MnFM3Dh8AU0pZHLXUD127SAJGER/s= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-proto-validators v0.0.0-20180403085117-0950a7990007/go.mod h1:m2XC9Qq0AlmmVksL6FktJCdTYyLk7V3fKyp0sl1yWQo= +github.com/mwitkow/go-proto-validators v0.2.0/go.mod h1:ZfA1hW+UH/2ZHOWvQ3HnQaU0DtnpXu850MZiy+YUgcc= +github.com/nakabonne/nestif v0.3.1/go.mod h1:9EtoZochLn5iUprVDmDjqGKPofoUEBL8U4Ngq6aY7OE= +github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354/go.mod h1:KSVJerMDfblTH7p5MZaTt+8zaT2iEk3AkVb9PQdZuE8= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nishanths/exhaustive v0.2.3/go.mod h1:bhIX678Nx8inLM9PbpvK1yv6oGtoP8BfaIeMzgBNKvc= +github.com/nishanths/predeclared v0.0.0-20190419143655-18a43bb90ffc/go.mod h1:62PewwiQTlm/7Rj+cxVYqZvDIUc+JjZq6GHAC1fsObQ= +github.com/nishanths/predeclared v0.2.1/go.mod h1:HvkGJcA3naj4lOwnFXFDkFxVtSqQMB9sbB1usJ+xjQE= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/olekukonko/tablewriter v0.0.2/go.mod h1:rSAaSIOAGT9odnlyGlUfAJaoc5w2fSBUmeGDbRWPxyQ= +github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.2/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= +github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= github.com/onsi/ginkgo/v2 v2.1.6 h1:Fx2POJZfKRQcM1pH49qSZiYeu319wji004qX+GDovrU= +github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.16.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= +github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= +github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= github.com/onsi/gomega v1.20.1 h1:PA/3qinGoukvymdIDV8pii6tiZgC8kbmJO6Z5+b002Q= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.0.3-0.20220114050600-8b9d41f48198 h1:+czc/J8SlhPKLOtVLMQc+xDCFBT73ZStMsRhSsUhsSg= +github.com/opencontainers/image-spec v1.0.3-0.20220114050600-8b9d41f48198/go.mod h1:j4h1pJW6ZcJTgMZWP3+7RlG3zTaP02aDZ/Qw0sppK7Q= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/openzipkin/zipkin-go v0.4.0 h1:CtfRrOVZtbDj8rt1WXjklw0kqqJQwICrCKmlfUuBUUw= github.com/openzipkin/zipkin-go v0.4.0/go.mod h1:4c3sLeE8xjNqehmF5RpAFLPLJxXscc0R4l6Zg0P1tTQ= github.com/ory/viper v1.7.5 h1:+xVdq7SU3e1vNaCsk/ixsfxE4zylk1TJUiJrY647jUE= github.com/ory/viper v1.7.5/go.mod h1:ypOuyJmEUb3oENywQZRgeAMwqgOyDqwboO1tj3DjTaM= +github.com/otiai10/copy v1.2.0/go.mod h1:rrF5dJ5F0t/EWSYODDu4j9/vEeYHMkc8jt0zJChqQWw= +github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE= +github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs= +github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo= +github.com/otiai10/mint v1.3.1/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pb33f/libopenapi v0.8.4 h1:hP6etldkapogvEfILaCVrBNh9DwzK/ZKGrNPm3qAIwU= +github.com/pb33f/libopenapi v0.8.4/go.mod h1:lvUmCtjgHUGVj6WzN3I5/CS9wkXtyN3Ykjh6ZZP5lrI= +github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pelletier/go-toml/v2 v2.0.5 h1:ipoSadvV8oGUjnUbMub59IDPPwfxF694nG/jwbMiyQg= github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas= github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/phayes/checkstyle v0.0.0-20170904204023-bfd46e6a821d/go.mod h1:3OzsM7FXDQlpCiw2j81fOmAwQLnZnLGXVKUzeKQXIAw= github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= +github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/polyfloyd/go-errorlint v0.0.0-20210722154253-910bb7978349/go.mod h1:wi9BfjxjF/bwiZ701TzmfKu6UKC357IOAtNr0Td0Lvw= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= @@ -461,6 +787,16 @@ github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB github.com/prometheus/statsd_exporter v0.22.7/go.mod h1:N/TevpjkIh9ccs6nuzY3jQn9dFqnUakOjnEuMPJJJnI= github.com/prometheus/statsd_exporter v0.22.8 h1:Qo2D9ZzaQG+id9i5NYNGmbf1aa/KxKbB9aKfMS+Yib0= github.com/prometheus/statsd_exporter v0.22.8/go.mod h1:/DzwbTEaFTE0Ojz5PqcSk6+PFHOPWGxdXVr6yC8eFOM= +github.com/pseudomuto/protoc-gen-doc v1.3.2/go.mod h1:y5+P6n3iGrbKG+9O04V5ld71in3v/bX88wUwgt+U8EA= +github.com/pseudomuto/protokit v0.2.0/go.mod h1:2PdH30hxVHsup8KpBTOXTBeMVhJZVio3Q8ViKSAXT0Q= +github.com/quasilyte/go-consistent v0.0.0-20190521200055-c6f3937de18c/go.mod h1:5STLWrekHfjyYwxBRVRXNOSewLJ3PWfDJd1VyTS21fI= +github.com/quasilyte/go-ruleguard v0.3.1-0.20210203134552-1b5a410e1cc8/go.mod h1:KsAh3x0e7Fkpgs+Q9pNLS5XpFSvYCEVl5gP9Pp1xp30= +github.com/quasilyte/go-ruleguard v0.3.13/go.mod h1:Ul8wwdqR6kBVOCt2dipDBkE+T6vAV/iixkrKuRTN1oQ= +github.com/quasilyte/go-ruleguard/dsl v0.3.0/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU= +github.com/quasilyte/go-ruleguard/dsl v0.3.10/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU= +github.com/quasilyte/go-ruleguard/rules v0.0.0-20201231183845-9e62ed36efe1/go.mod h1:7JTjp89EGyU1d6XfBiXihJNG37wB2VRkd125Q1u7Plc= +github.com/quasilyte/go-ruleguard/rules v0.0.0-20210428214800-545e0d2e0bf7/go.mod h1:4cgAphtvu7Ftv7vOT2ZOYhC6CvBxZixcasr8qIOTA50= +github.com/quasilyte/regex/syntax v0.0.0-20200407221936-30656e2c4a95/go.mod h1:rlzQ04UMyJXu/aOvhd8qT+hvDrFpiwqp8MRXDY9szc0= github.com/rabbitmq/amqp091-go v1.1.0/go.mod h1:ogQDLSOACsLPsIq0NpbtiifNZi2YOz0VTJ0kHRghqbM= github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rickb777/date v1.20.0 h1:oRGcq4b+ba12N/HnsVZuWSK/QJb/o/hnjOJEyRMGUT0= @@ -469,46 +805,88 @@ github.com/rickb777/plural v1.4.1 h1:5MMLcbIaapLFmvDGRT5iPk8877hpTPt8Y9cdSKRw9sU github.com/rickb777/plural v1.4.1/go.mod h1:kdmXUpmKBJTS0FtG/TFumd//VBWsNTD7zOw7x4umxNw= github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.6.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= +github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/russross/blackfriday v1.6.0/go.mod h1:ti0ldHuxg49ri4ksnFxlkCfN+hvslNlmVHqNRXXJNAY= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/ryancurrah/gomodguard v1.2.3/go.mod h1:rYbA/4Tg5c54mV1sv4sQTP5WOPBcoLtnBZ7/TEhXAbg= +github.com/ryanrolds/sqlclosecheck v0.3.0/go.mod h1:1gREqxyTGR3lVtpngyFo3hZAgk0KCtEdgEkHwDbigdA= +github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/sagikazarmark/crypt v0.1.0/go.mod h1:B/mN0msZuINBtQ1zZLEQcegFJJf9vnYIR88KRMEuODE= +github.com/sanposhiho/wastedassign/v2 v2.0.6/go.mod h1:KyZ0MWTwxxBmfwn33zh3k1dmsbF2ud9pAAGfoLfjhtI= +github.com/santhosh-tekuri/jsonschema/v5 v5.3.0 h1:uIkTLo0AGRc8l7h5l9r+GcYi9qfVPt6lD4/bhmzfiKo= +github.com/santhosh-tekuri/jsonschema/v5 v5.3.0/go.mod h1:FKdcjfQW6rpZSnxxUvEA5H/cDPdvJ/SZJQLWWXWGrZ0= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/securego/gosec/v2 v2.9.1/go.mod h1:oDcDLcatOJxkCGaCaq8lua1jTnYf6Sou4wdiJ1n4iHc= +github.com/senseyeio/duration v0.0.0-20180430131211-7c2a214ada46 h1:Dz0HrI1AtNSGCE8LXLLqoZU4iuOJXPWndenCsZfstA8= +github.com/senseyeio/duration v0.0.0-20180430131211-7c2a214ada46/go.mod h1:is8FVkzSi7PYLWEXT5MgWhglFsyyiW8ffxAoJqfuFZo= +github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/serverlessworkflow/sdk-go/v2 v2.2.3 h1:s5+8GegK4vIMKAg2ETdO9OovSROGwVPPvrGz74G17oQ= +github.com/serverlessworkflow/sdk-go/v2 v2.2.3/go.mod h1:YmKuDaZ81zLyIfYZtgkcUpOzGN8xWMWeZGGaO5pW0Us= +github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c/go.mod h1:/PevMnwAxekIXwN8qQyfc5gl2NlkB3CQlkizAbOkeBs= +github.com/shirou/gopsutil/v3 v3.21.10/go.mod h1:t75NhzCZ/dYyPQjyQmrAYP6c8+LCdFANeBMdLPCNnew= +github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= +github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sivchari/tenv v1.4.7/go.mod h1:5nF+bITvkebQVanjU6IuMbvIot/7ReNsUV7I5NbprB0= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/sonatard/noctx v0.0.1/go.mod h1:9D2D/EoULe8Yy2joDHJj7bv3sZoq9AaSb8B4lqBjiZI= +github.com/sourcegraph/go-diff v0.6.1/go.mod h1:iBszgVvyxdc8SFZ7gm69go2KDdt3ag071iBaWPF6cjs= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72 h1:qLC7fQah7D6K1B0ujays3HV9gkFtllcxhzImRR7ArPQ= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= github.com/spf13/afero v1.9.3 h1:41FoI0fD7OR7mGcKE/aOiLkGreyf8ifIOQmJANWogMk= github.com/spf13/afero v1.9.3/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk= github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA= github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= +github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns= +github.com/spf13/viper v1.9.0/go.mod h1:+i6ajR7OX2XaiBkrcZJFK21htRk7eDeLg7+O6bhUPP4= github.com/spf13/viper v1.13.0 h1:BWSJ/M+f+3nmdz9bxB+bWX28kkALN2ok11D0rSo8EJU= github.com/spf13/viper v1.13.0/go.mod h1:Icm2xNL3/8uyh/wFuB1jI7TiTNKp8632Nwegu+zgdYw= +github.com/ssgreg/nlreturn/v2 v2.2.1/go.mod h1:E/iiPB78hV7Szg2YfRgyIrk1AD6JVMTRkkxBiELzh2I= github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v0.0.0-20170130113145-4d4bfba8f1d1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.1.4/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -517,27 +895,69 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= github.com/stvp/go-udp-testing v0.0.0-20201019212854-469649b16807/go.mod h1:7jxmlfBCDBXRzr0eAQJ48XC1hBu1np4CS5+cHEYfwpc= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/subosito/gotenv v1.4.1 h1:jyEFiXpy21Wm81FBN71l9VoMMV8H8jG+qIK3GCpY6Qs= github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= +github.com/sylvia7788/contextcheck v1.0.4/go.mod h1:vuPKJMQ7MQ91ZTqfdyreNKwZjyUg6KO+IebVyQDedZQ= +github.com/tdakkota/asciicheck v0.0.0-20200416200610-e657995f937b/go.mod h1:yHp0ai0Z9gUljN3o0xMhYJnH/IcvkdTBOX2fmJ93JEM= +github.com/tenntenn/modver v1.0.1/go.mod h1:bePIyQPb7UeioSRkw3Q0XeMhYZSMx9B8ePqg6SAMGH0= +github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3/go.mod h1:ON8b8w4BN/kE1EOhwT0o+d62W65a6aPw1nouo9LMgyY= +github.com/tetafro/godot v1.4.11/go.mod h1:LR3CJpxDVGlYOWn3ZZg1PgNZdTUvzsZWu8xaEohUpn8= +github.com/timakin/bodyclose v0.0.0-20200424151742-cb6215831a94/go.mod h1:Qimiffbc6q9tBWlVV6x0P9sat/ao1xEkREYPPj9hphk= +github.com/tklauser/go-sysconf v0.3.9/go.mod h1:11DU/5sG7UexIrp/O6g35hrWzu0JxlwQ3LSFUzyeuhs= +github.com/tklauser/numcpus v0.3.0/go.mod h1:yFGUr7TUHQRAhyqBcEg0Ge34zDBAsIvJJcyE6boqnA8= +github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tmc/grpc-websocket-proxy v0.0.0-20200427203606-3cfed13b9966/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tomarrell/wrapcheck/v2 v2.4.0/go.mod h1:68bQ/eJg55BROaRTbMjC7vuhL2OgfoG8bLp9ZyoBfyY= +github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce/go.mod h1:o8v6yHRoik09Xen7gje4m9ERNah1d1PPsVq1VEx9vE4= +github.com/tommy-muehle/go-mnd/v2 v2.4.0/go.mod h1:WsUAkMJMYww6l/ufffCD3m+P7LEvr8TnZn9lwVDlgzw= +github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/ultraware/funlen v0.0.3/go.mod h1:Dp4UiAus7Wdb9KUZsYWZEWiRzGuM2kXM1lPbfaF6xhA= +github.com/ultraware/whitespace v0.0.4/go.mod h1:aVMh/gQve5Maj9hQ/hg+F75lr/X5A89uZnzAmWSineA= +github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= +github.com/uudashr/gocognit v1.0.5/go.mod h1:wgYz0mitoKOTysqxTDMOUXg+Jb5SvtihkfmugIZYpEA= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasthttp v1.30.0/go.mod h1:2rsYD01CKFrjjsvFxx75KlEUNpWNBY9JWD3K/7o2Cus= +github.com/valyala/quicktemplate v1.7.0/go.mod h1:sqKJnoaOF88V07vkO+9FL8fb9uZg/VPSJnLYn+LmLk8= +github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= +github.com/viki-org/dnscache v0.0.0-20130720023526-c70c1f23c5d8/go.mod h1:dniwbG03GafCjFohMDmz6Zc6oCuiqgH6tGNyXTkHzXE= +github.com/vmware-labs/yaml-jsonpath v0.3.2 h1:/5QKeCBGdsInyDCyVNLbXyilb61MXGi9NP674f9Hobk= +github.com/vmware-labs/yaml-jsonpath v0.3.2/go.mod h1:U6whw1z03QyqgWdgXxvVnQ90zN1BWz5V+51Ewf8k+rQ= github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs= github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xlab/treeprint v1.1.0 h1:G/1DjNkPpfZCFt9CSh6b5/nY4VimlbHF3Rh4obvtzDk= github.com/xlab/treeprint v1.1.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0= +github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/yeya24/promlinter v0.1.0/go.mod h1:rs5vtZzeBHqqMwXqFScncpCF6u06lezhZepno9AB1Oc= +github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg= +github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= +github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= +go.etcd.io/etcd v0.0.0-20200513171258-e048e166ab9c/go.mod h1:xCI7ZzBfRuGgBXyXO6yfWfDmlWd35khcWpUa4L0xI/k= +go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= +go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= +go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= +go.mozilla.org/mozlog v0.0.0-20170222151521-4bb13139d403/go.mod h1:jHoPAGnDrCy6kaI2tAze5Prf0Nr0w/oNkROt2lw3n3o= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -549,28 +969,46 @@ go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.starlark.net v0.0.0-20220817180228-f738f5508c12 h1:xOBJXWGEDwU5xSDxH6macxO11Us0AH2fTa9rmsbbF7g= go.starlark.net v0.0.0-20220817180228-f738f5508c12/go.mod h1:VZcBMdr3cT3PnBoWunTabuSEXwVAH+ZJ5zxfs3AdASk= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= -go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk= +go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= +go.uber.org/multierr v1.4.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI= go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.23.0 h1:OjGQ5KQDEUawVHxNwQgPpiypGHOxo2mNZsOqTak4fFY= -go.uber.org/zap v1.23.0/go.mod h1:D+nX8jyLsMHMYrln8A0rJjFt/T/9/bGgIhAqxv5URuY= +go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= +go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= +go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= +go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= +golang.org/x/crypto v0.0.0-20180501155221-613d6eafa307/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= +golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210920023735-84f357641f63/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.8.0 h1:pd9TJtTueMTVQXzk8E2XESSMQDj/U7OUu0PqJqPXQjQ= golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= @@ -584,6 +1022,7 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -609,12 +1048,16 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk= golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -626,6 +1069,8 @@ golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191002035440-2ec189313ef0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -634,6 +1079,7 @@ golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200421231249-e086a090c8fd/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= @@ -653,6 +1099,7 @@ golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLd golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210917221730-978cfadd31cf/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= @@ -678,6 +1125,7 @@ golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= @@ -694,6 +1142,7 @@ golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190412183630-56d357773e84/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -704,11 +1153,16 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI= golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -717,15 +1171,21 @@ golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -734,6 +1194,7 @@ golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -755,6 +1216,7 @@ golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -765,8 +1227,14 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210816074244-15123e1e1f71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210915083310-ed5796bab164/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210917161153-d61c044b1678/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211013075003-97ac67df715c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -786,6 +1254,7 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.8.0 h1:n5xxQn2i3PC0yLAbjTpNT85q/Kgzcr2gIoX9OrJUols= @@ -801,17 +1270,27 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190110163146-51295c7ec13a/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190307163923-6a08e3108db3/go.mod h1:25r3+/G6/xytQM8iWZKq3Hn0kr0rgFKPUNVEL/dr3z4= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190311215038-5c2858a9cfe5/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190321232350-e250d351ecad/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190322203728-c1a832b0ad89/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= @@ -820,16 +1299,26 @@ golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190910044552-dd2b5c81c578/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190916130336-e45ffcd953cc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191010075000-0337d82405ff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117220505-0cba7a3a9ee9/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= @@ -839,30 +1328,58 @@ golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapK golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200324003944-a576cf524670/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200329025819-fd4102a86c65/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200414032229-332987a829c3/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200422022333-3d57cf2e726e/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200426102838-f3a5411a4c3b/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200622203043-20e05c1c8ffa/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200624225443-88f3c62a19ff/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200625211823-6506e20df31f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200626171337-aa94e735be7f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200630154851-b2d8b0336632/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200706234117-b22de6825cf7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200724022722-7017fd6b1305/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200812195022-5ae4c3c160a0/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200820010801-b793a1359eac/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200831203904-5a2aa26beb65/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20201001104356-43ebab892c4c/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= +golang.org/x/tools v0.0.0-20201002184944-ecd9fd270d5d/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= +golang.org/x/tools v0.0.0-20201023174141-c8cfbd0f21e6/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201028025901-8cd080b735b3/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201114224030-61ea331ec02b/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201118003311-bd56c0adb394/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201230224404-63754364767c/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210101214203-2dba1e4ea05c/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210104081019-d8d6ddbec6ee/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.1-0.20210205202024-ef80cdb6ec6d/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU= +golang.org/x/tools v0.1.1-0.20210302220138-2ac05c832e1a/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.6/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= +golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= golang.org/x/tools v0.9.1 h1:8WMNJAz3zrtPmnYC7ISf5dEn3MT0gY7jBJfw27yrrLo= golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -878,6 +1395,7 @@ google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEt google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.10.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= @@ -896,6 +1414,7 @@ google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34q google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= +google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8= google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= @@ -920,11 +1439,14 @@ google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9Ywl google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.2/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20170818010345-ee236bd376b0/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20181107211654-5fc9ac540362/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -932,6 +1454,7 @@ google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRn google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20190927181202-20e1ac93f88c/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= @@ -945,6 +1468,7 @@ google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfG google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= @@ -952,6 +1476,8 @@ google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1m google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200527145253-8367513e4ece/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200626011028-ee7919e894b5/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200707001353-8e8330bf89df/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= @@ -1009,15 +1535,19 @@ google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljW google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= google.golang.org/genproto v0.0.0-20220919141832-68c03719ef51 h1:ucpgjuzWqWrj0NEwjUpsGTf2IGxyLtmuSk0oGgifjec= google.golang.org/genproto v0.0.0-20220919141832-68c03719ef51/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.0/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= @@ -1041,8 +1571,8 @@ google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11 google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.49.0 h1:WTLtQzmQori5FUH25Pq4WT22oCsv8USpQ+F6rqtsmxw= -google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc v1.51.0 h1:E1eGv1FTqoLIdnBCZufiSHgKjlqG6fKFf6pPWtMTh8U= +google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= @@ -1065,25 +1595,37 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLks gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +gopkg.in/cheggaaa/pb.v1 v1.0.28/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.63.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.6/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20191026110619-0b21df46bc1d/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= @@ -1099,6 +1641,7 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.2.1/go.mod h1:lPVVZ2BS5TfnjLyizF7o7hv7j9/L+8cZY2hLyjP9cGY= k8s.io/api v0.25.4 h1:3YO8J4RtmG7elEgaWMb4HgmpS2CfY1QlaOz9nwB+ZSs= k8s.io/api v0.25.4/go.mod h1:IG2+RzyPQLllQxnhzD8KQNEu4c4YvyDTpSMztf4A0OQ= k8s.io/apiextensions-apiserver v0.25.4 h1:7hu9pF+xikxQuQZ7/30z/qxIPZc2J1lFElPtr7f+B6U= @@ -1111,6 +1654,8 @@ k8s.io/client-go v0.25.4 h1:3RNRDffAkNU56M/a7gUfXaEzdhZlYhoW8dgViGy5fn8= k8s.io/client-go v0.25.4/go.mod h1:8trHCAC83XKY0wsBIpbirZU4NTUpbuhc2JnI7OruGZw= k8s.io/code-generator v0.25.4 h1:tjQ7/+9eN7UOiU2DP+0v4ntTI4JZLi2c1N0WllpFhTc= k8s.io/code-generator v0.25.4/go.mod h1:9F5fuVZOMWRme7MYj2YT3L9ropPWPokd9VRhVyD3+0w= +k8s.io/component-base v0.27.2 h1:neju+7s/r5O4x4/txeUONNTS9r1HsPbyoPBAtHsDCpo= +k8s.io/component-base v0.27.2/go.mod h1:5UPk7EjfgrfgRIuDBFtsEFAe4DAvP3U+M8RTzoSJkpo= k8s.io/gengo v0.0.0-20221011193443-fad74ee6edd9 h1:iu3o/SxaHVI7tKPtkGzD3M9IzrE21j+CUKH98NQJ8Ms= k8s.io/gengo v0.0.0-20221011193443-fad74ee6edd9/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= @@ -1132,9 +1677,15 @@ knative.dev/pkg v0.0.0-20230224205330-75da922ef055 h1:VfKOAnbgJXJMz7n66yW7Rj6Sl2 knative.dev/pkg v0.0.0-20230224205330-75da922ef055/go.mod h1:QkgVAUCziNOZmoqL/E25ig2cbVQ2teZyGNCNqaApO44= knative.dev/serving v0.36.4 h1:M3AyrrOyEf7DXbW1w8pSI4vOtZGjsVyJFASISU6sNwg= knative.dev/serving v0.36.4/go.mod h1:1xtMO2p5x4BTb28Z0/hE94QMdmHPIweZ2v4wV/9HAkI= +mvdan.cc/gofumpt v0.1.1/go.mod h1:yXG1r1WqZVKWbVRtBWKWX9+CxGYfA51nSomhM0woR48= +mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed/go.mod h1:Xkxe497xwlCKkIaQYRfC7CSLworTXY9RMqwhhCm+8Nc= +mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b/go.mod h1:2odslEg/xrtNQqCYg2/jCoyKnw3vv5biOc3JnIcYfL4= +mvdan.cc/unparam v0.0.0-20210104141923-aac4ce9116a7/go.mod h1:hBpJkZE8H/sb+VRFvw2+rBpHNsTBcvSpk61hr8mzXZE= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sigs.k8s.io/controller-runtime v0.13.0 h1:iqa5RNciy7ADWnIc8QxCbOX5FEKVR3uxVxKHRMc2WIQ= +sigs.k8s.io/controller-runtime v0.13.0/go.mod h1:Zbz+el8Yg31jubvAEyglRZGdLAjplZl+PgtYNI6WNTI= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= sigs.k8s.io/kustomize/api v0.12.1 h1:7YM7gW3kYBwtKvoY216ZzY+8hM+lV53LUayghNRJ0vM= @@ -1143,6 +1694,7 @@ sigs.k8s.io/kustomize/kyaml v0.13.9 h1:Qz53EAaFFANyNgyOEJbT/yoIHygK40/ZcvU3rgry2 sigs.k8s.io/kustomize/kyaml v0.13.9/go.mod h1:QsRbD0/KcU+wdk0/L0fIp2KLnohkVzs6fQ85/nOXac4= sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE= sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/hack/build.sh.d/kn-plugin-workflow.sh b/hack/build.sh.d/kn-plugin-workflow.sh index 5d9b3a763d..3070e37c2c 100644 --- a/hack/build.sh.d/kn-plugin-workflow.sh +++ b/hack/build.sh.d/kn-plugin-workflow.sh @@ -1,8 +1,8 @@ #!/usr/bin/env bash -readonly quarkus_version="2.13.7.SP1-redhat-00001" +readonly quarkus_version="2.13.8.Final-redhat-00004" readonly quarkus_platform_group_id="com.redhat.quarkus.platform" -readonly dev_mode_image="quay.io/kiegroup/kogito-swf-devmode:1.40" +readonly dev_mode_image="registry.redhat.io/openshift-serverless-1-tech-preview/logic-swf-devmode-rhel8:1.30" export EXTERNAL_LD_FLAGS="${EXTERNAL_LD_FLAGS:-} \ -X github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/metadata.DevModeImage=${dev_mode_image} \ -X github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/metadata.QuarkusVersion=${quarkus_version} \ diff --git a/lib/test/service.go b/lib/test/e2e/service.go similarity index 91% rename from lib/test/service.go rename to lib/test/e2e/service.go index 40de05f83b..583f92cbc2 100644 --- a/lib/test/service.go +++ b/lib/test/e2e/service.go @@ -12,11 +12,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -package test +package e2e import ( "context" "encoding/json" + "knative.dev/client/lib/test" "strings" "knative.dev/pkg/kmap" @@ -45,28 +46,28 @@ type ExpectedRevisionListOption func(*servingv1.RevisionList) type ExpectedKNExportOption func(*clientv1alpha1.Export) // ServiceCreate verifies given service creation in sync mode and also verifies output -func ServiceCreate(r *KnRunResultCollector, serviceName string) { +func ServiceCreate(r *test.KnRunResultCollector, serviceName string) { out := r.KnTest().Kn().Run("service", "create", serviceName, "--image", pkgtest.ImagePath("helloworld")) r.AssertNoError(out) assert.Check(r.T(), util.ContainsAllIgnoreCase(out.Stdout, "service", serviceName, "creating", "namespace", r.KnTest().Kn().Namespace(), "ready")) } // ServiceListEmpty verifies that there are no services present -func ServiceListEmpty(r *KnRunResultCollector) { +func ServiceListEmpty(r *test.KnRunResultCollector) { out := r.KnTest().Kn().Run("service", "list") r.AssertNoError(out) assert.Check(r.T(), util.ContainsAll(out.Stdout, "No services found.")) } // ServiceList verifies if given service exists -func ServiceList(r *KnRunResultCollector, serviceName string) { +func ServiceList(r *test.KnRunResultCollector, serviceName string) { out := r.KnTest().Kn().Run("service", "list", serviceName) r.AssertNoError(out) assert.Check(r.T(), util.ContainsAll(out.Stdout, serviceName)) } // ServiceDescribe describes given service and verifies the keys in the output -func ServiceDescribe(r *KnRunResultCollector, serviceName string) { +func ServiceDescribe(r *test.KnRunResultCollector, serviceName string) { out := r.KnTest().Kn().Run("service", "describe", serviceName) r.AssertNoError(out) assert.Assert(r.T(), util.ContainsAll(out.Stdout, serviceName, r.KnTest().Kn().Namespace(), pkgtest.ImagePath("helloworld"))) @@ -75,14 +76,14 @@ func ServiceDescribe(r *KnRunResultCollector, serviceName string) { } // ServiceListOutput verifies listing given service using '--output name' flag -func ServiceListOutput(r *KnRunResultCollector, serviceName string) { +func ServiceListOutput(r *test.KnRunResultCollector, serviceName string) { out := r.KnTest().Kn().Run("service", "list", serviceName, "--output", "name") r.AssertNoError(out) assert.Check(r.T(), util.ContainsAll(out.Stdout, serviceName, "service.serving.knative.dev")) } // ServiceUpdate verifies service update operation with given arguments in sync mode -func ServiceUpdate(r *KnRunResultCollector, serviceName string, args ...string) { +func ServiceUpdate(r *test.KnRunResultCollector, serviceName string, args ...string) { fullArgs := append([]string{}, "service", "update", serviceName) fullArgs = append(fullArgs, args...) out := r.KnTest().Kn().Run(fullArgs...) @@ -92,7 +93,7 @@ func ServiceUpdate(r *KnRunResultCollector, serviceName string, args ...string) // ServiceUpdateWithError verifies service update operation with given arguments in sync mode // when expecting an error -func ServiceUpdateWithError(r *KnRunResultCollector, serviceName string, args ...string) { +func ServiceUpdateWithError(r *test.KnRunResultCollector, serviceName string, args ...string) { fullArgs := append([]string{}, "service", "update", serviceName) fullArgs = append(fullArgs, args...) out := r.KnTest().Kn().Run(fullArgs...) @@ -100,21 +101,21 @@ func ServiceUpdateWithError(r *KnRunResultCollector, serviceName string, args .. } // ServiceDelete verifies service deletion in sync mode -func ServiceDelete(r *KnRunResultCollector, serviceName string) { +func ServiceDelete(r *test.KnRunResultCollector, serviceName string) { out := r.KnTest().Kn().Run("service", "delete", serviceName, "--wait") r.AssertNoError(out) assert.Check(r.T(), util.ContainsAll(out.Stdout, "Service", serviceName, "successfully deleted in namespace", r.KnTest().Kn().Namespace())) } // ServiceDescribeWithJSONPath returns output of given JSON path by describing the service -func ServiceDescribeWithJSONPath(r *KnRunResultCollector, serviceName, jsonpath string) string { +func ServiceDescribeWithJSONPath(r *test.KnRunResultCollector, serviceName, jsonpath string) string { out := r.KnTest().Kn().Run("service", "describe", serviceName, "-o", jsonpath) r.AssertNoError(out) return out.Stdout } // ValidateServiceResources validates cpu and mem resources -func ValidateServiceResources(r *KnRunResultCollector, serviceName string, requestsMemory, requestsCPU, limitsMemory, limitsCPU string) { +func ValidateServiceResources(r *test.KnRunResultCollector, serviceName string, requestsMemory, requestsCPU, limitsMemory, limitsCPU string) { var err error rlist := corev1.ResourceList{} rlist[corev1.ResourceCPU], err = resource.ParseQuantity(requestsCPU) @@ -143,7 +144,7 @@ func ValidateServiceResources(r *KnRunResultCollector, serviceName string, reque // GetServiceFromKNServiceDescribe runs the kn service describe command // decodes it into a ksvc and returns it. -func GetServiceFromKNServiceDescribe(r *KnRunResultCollector, serviceName string) servingv1.Service { +func GetServiceFromKNServiceDescribe(r *test.KnRunResultCollector, serviceName string) servingv1.Service { out := r.KnTest().Kn().Run("service", "describe", serviceName, "-ojson") data := json.NewDecoder(strings.NewReader(out.Stdout)) data.UseNumber() diff --git a/pkg/kn/commands/service/export_test.go b/pkg/kn/commands/service/export_test.go index 7b2b2ee83f..33e22dca8f 100644 --- a/pkg/kn/commands/service/export_test.go +++ b/pkg/kn/commands/service/export_test.go @@ -17,6 +17,7 @@ package service import ( "context" "encoding/json" + libtest "knative.dev/client/lib/test/e2e" "testing" "knative.dev/client/pkg/serving" @@ -24,7 +25,6 @@ import ( "gotest.tools/v3/assert" v1 "k8s.io/api/core/v1" - libtest "knative.dev/client/lib/test" clientv1alpha1 "knative.dev/client/pkg/apis/client/v1alpha1" knclient "knative.dev/client/pkg/serving/v1" "knative.dev/client/pkg/util/mock" diff --git a/pkg/serving/v1/gitops_test.go b/pkg/serving/v1/gitops_test.go index 8095dccceb..7888ca5eb2 100644 --- a/pkg/serving/v1/gitops_test.go +++ b/pkg/serving/v1/gitops_test.go @@ -16,6 +16,7 @@ package v1 import ( "context" + libtest "knative.dev/client/lib/test/e2e" "path/filepath" "testing" "time" @@ -27,7 +28,6 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" servingtest "knative.dev/serving/pkg/testing/v1" - libtest "knative.dev/client/lib/test" "knative.dev/pkg/ptr" servingv1 "knative.dev/serving/pkg/apis/serving/v1" ) diff --git a/test/e2e/basic_workflow_test.go b/test/e2e/basic_workflow_test.go index 288418de70..deb3b7232a 100644 --- a/test/e2e/basic_workflow_test.go +++ b/test/e2e/basic_workflow_test.go @@ -18,6 +18,7 @@ package e2e import ( + "knative.dev/client/lib/test/e2e" "testing" "gotest.tools/v3/assert" @@ -38,23 +39,23 @@ func TestBasicWorkflow(t *testing.T) { defer r.DumpIfFailed() t.Log("returns no service before running tests") - test.ServiceListEmpty(r) + e2e.ServiceListEmpty(r) t.Log("create hello service and return no error") - test.ServiceCreate(r, "hello") + e2e.ServiceCreate(r, "hello") t.Log("return valid info about hello service") - test.ServiceList(r, "hello") - test.ServiceDescribe(r, "hello") + e2e.ServiceList(r, "hello") + e2e.ServiceDescribe(r, "hello") t.Log("return list --output name about hello service") - test.ServiceListOutput(r, "hello") + e2e.ServiceListOutput(r, "hello") t.Log("update hello service's configuration and return no error") - test.ServiceUpdate(r, "hello", "--env", "TARGET=kn", "--port", "8888") + e2e.ServiceUpdate(r, "hello", "--env", "TARGET=kn", "--port", "8888") t.Log("create another service and return no error") - test.ServiceCreate(r, "svc2") + e2e.ServiceCreate(r, "svc2") t.Log("return a list of revisions associated with hello and svc2 services") test.RevisionListForService(r, "hello") @@ -64,11 +65,11 @@ func TestBasicWorkflow(t *testing.T) { test.RevisionDescribe(r, "hello") t.Log("delete hello and svc2 services and return no error") - test.ServiceDelete(r, "hello") - test.ServiceDelete(r, "svc2") + e2e.ServiceDelete(r, "hello") + e2e.ServiceDelete(r, "svc2") t.Log("return no service after completing tests") - test.ServiceListEmpty(r) + e2e.ServiceListEmpty(r) } func TestWrongCommand(t *testing.T) { diff --git a/test/e2e/domain_mapping_test.go b/test/e2e/domain_mapping_test.go index 76dd6627cf..cd40ead76a 100644 --- a/test/e2e/domain_mapping_test.go +++ b/test/e2e/domain_mapping_test.go @@ -18,6 +18,7 @@ package e2e import ( + "knative.dev/client/lib/test/e2e" "testing" "time" @@ -47,14 +48,14 @@ func TestDomain(t *testing.T) { domainName := "hello.example.com" t.Log("create domain mapping to hello ksvc") - test.ServiceCreate(r, "hello") + e2e.ServiceCreate(r, "hello") domainCreate(r, domainName, "hello") t.Log("list domain mappings") domainList(r, domainName) t.Log("update domain mapping Knative service reference") - test.ServiceCreate(r, "foo") + e2e.ServiceCreate(r, "foo") domainUpdate(r, domainName, "foo") t.Log("describe domain mappings") diff --git a/test/e2e/extra_containers_test.go b/test/e2e/extra_containers_test.go index 4d09ddfad8..0b641a1f39 100644 --- a/test/e2e/extra_containers_test.go +++ b/test/e2e/extra_containers_test.go @@ -21,6 +21,7 @@ import ( "bytes" "fmt" "io" + "knative.dev/client/lib/test/e2e" "os/exec" "path/filepath" "strings" @@ -51,14 +52,14 @@ func TestMultiContainers(t *testing.T) { container := addContainer(r, "sidecar", pkgtest.ImagePath("sidecarcontainer")) test.CreateFile("sidecar.yaml", container.Stdout, tempDir, test.FileModeReadWrite) createServiceWithSidecar(r, "testsvc0", filepath.Join(tempDir, "sidecar.yaml")) - test.ServiceDelete(r, "testsvc0") + e2e.ServiceDelete(r, "testsvc0") t.Log("Creating a multicontainer service from os.Stdin") container = addContainer(r, "sidecar", pkgtest.ImagePath("sidecarcontainer")) out := createServiceWithPipeInput(r, "testsvc1", container.Stdout) r.AssertNoError(out) assert.Check(r.T(), util.ContainsAllIgnoreCase(out.Stdout, "service", "testsvc1", "creating", "namespace", r.KnTest().Kn().Namespace(), "ready")) - test.ServiceDelete(r, "testsvc1") + e2e.ServiceDelete(r, "testsvc1") t.Log("Creating a multicontainer service from os.Stdin with EOF error") out = createServiceWithPipeInput(r, "testsvc2", "") diff --git a/test/e2e/ping_test.go b/test/e2e/ping_test.go index 80fa0b4202..ba0f182f9b 100644 --- a/test/e2e/ping_test.go +++ b/test/e2e/ping_test.go @@ -18,6 +18,7 @@ package e2e import ( + "knative.dev/client/lib/test/e2e" "testing" "gotest.tools/v3/assert" @@ -38,7 +39,7 @@ func TestSourcePing(t *testing.T) { defer r.DumpIfFailed() t.Log("Creating a testservice") - test.ServiceCreate(r, "testsvc0") + e2e.ServiceCreate(r, "testsvc0") t.Log("create Ping sources with a sink to a service") @@ -53,7 +54,7 @@ func TestSourcePing(t *testing.T) { t.Log("update Ping source sink service") pingSourceCreate(r, "testpingsource2", "* * * * */1", "ping", "ksvc:testsvc0") - test.ServiceCreate(r, "testsvc1") + e2e.ServiceCreate(r, "testsvc1") pingSourceUpdateSink(r, "testpingsource2", "ksvc:testsvc1") jpSinkRefNameInSpec := "jsonpath={.spec.sink.ref.name}" out, err := test.GetResourceFieldsWithJSONPath(t, it, "pingsource", "testpingsource2", jpSinkRefNameInSpec) diff --git a/test/e2e/revision_test.go b/test/e2e/revision_test.go index fd9fb9a340..b4819ffe39 100644 --- a/test/e2e/revision_test.go +++ b/test/e2e/revision_test.go @@ -18,6 +18,7 @@ package e2e import ( + "knative.dev/client/lib/test/e2e" "testing" "gotest.tools/v3/assert" @@ -37,7 +38,7 @@ func TestRevision(t *testing.T) { defer r.DumpIfFailed() t.Log("create hello service and return no error") - test.ServiceCreate(r, "hello") + e2e.ServiceCreate(r, "hello") t.Log("describe revision from hello service with print flags") revName := test.FindRevision(r, "hello") @@ -45,13 +46,13 @@ func TestRevision(t *testing.T) { test.RevisionDescribeWithPrintFlags(r, revName) t.Log("update hello service and increase revision count to 2") - test.ServiceUpdate(r, "hello", "--env", "TARGET=kn", "--port", "8888") + e2e.ServiceUpdate(r, "hello", "--env", "TARGET=kn", "--port", "8888") t.Log("show a list of revisions sorted by the count of configuration generation") test.RevisionListWithService(r, "hello") t.Log("update hello service and increase revision count to 3") - test.ServiceUpdate(r, "hello", "--env", "TARGET=kn", "--port", "9000") + e2e.ServiceUpdate(r, "hello", "--env", "TARGET=kn", "--port", "9000") t.Log("delete three revisions with one revision a nonexistent") existRevision1 := test.FindRevisionByGeneration(r, "hello", 1) @@ -60,28 +61,28 @@ func TestRevision(t *testing.T) { test.RevisionMultipleDelete(r, existRevision1, existRevision2, nonexistRevision) t.Log("update hello service and increase revision count to 4") - test.ServiceUpdate(r, "hello", "--env", "TARGET=kn", "--port", "8888") + e2e.ServiceUpdate(r, "hello", "--env", "TARGET=kn", "--port", "8888") t.Log("delete all unreferenced revision from hello service and return no error") unRefRevision := test.FindRevisionByGeneration(r, "hello", 3) test.RevisionDeleteWithPruneOption(r, "hello", unRefRevision) t.Log("update hello service and increase revision count to 5") - test.ServiceUpdate(r, "hello", "--env", "TARGET=kn", "--port", "9000") + e2e.ServiceUpdate(r, "hello", "--env", "TARGET=kn", "--port", "9000") t.Log("create hello service and return no error") - test.ServiceCreate(r, "hello1") + e2e.ServiceCreate(r, "hello1") t.Log("update hello1 service and increase revision count to 2") - test.ServiceUpdate(r, "hello1", "--env", "TARGET=kn", "--port", "8888") + e2e.ServiceUpdate(r, "hello1", "--env", "TARGET=kn", "--port", "8888") t.Log("delete all unreferenced revisions return no error") unRefRevision1 := test.FindRevisionByGeneration(r, "hello", 4) unRefRevision2 := test.FindRevisionByGeneration(r, "hello1", 1) test.RevisionDeleteWithPruneAllOption(r, unRefRevision1, unRefRevision2) t.Log("delete hello1 service and return no error") - test.ServiceDelete(r, "hello1") + e2e.ServiceDelete(r, "hello1") t.Log("delete latest revision from hello service and return no error") revName = test.FindRevision(r, "hello") test.RevisionDelete(r, revName) t.Log("delete hello service and return no error") - test.ServiceDelete(r, "hello") + e2e.ServiceDelete(r, "hello") } diff --git a/test/e2e/route_test.go b/test/e2e/route_test.go index 8880f9582b..aab90e817f 100644 --- a/test/e2e/route_test.go +++ b/test/e2e/route_test.go @@ -19,6 +19,7 @@ package e2e import ( "fmt" + "knative.dev/client/lib/test/e2e" "strings" "testing" @@ -40,7 +41,7 @@ func TestRoute(t *testing.T) { defer r.DumpIfFailed() t.Log("create hello service and return no error") - test.ServiceCreate(r, "hello") + e2e.ServiceCreate(r, "hello") t.Log("return a list of routes") routeList(r) @@ -61,7 +62,7 @@ func TestRoute(t *testing.T) { routeDescribeWithPrintFlags(r, "hello") t.Log("delete hello service and return no error") - test.ServiceDelete(r, "hello") + e2e.ServiceDelete(r, "hello") } func routeList(r *test.KnRunResultCollector) { diff --git a/test/e2e/service_export_test.go b/test/e2e/service_export_test.go index 261a812f4f..743e1851d7 100644 --- a/test/e2e/service_export_test.go +++ b/test/e2e/service_export_test.go @@ -19,6 +19,7 @@ package e2e import ( "encoding/json" + "knative.dev/client/lib/test/e2e" "os" "strings" "testing" @@ -61,153 +62,153 @@ func TestServiceExport(t *testing.T) { userImage = "" } t.Log("export service-revision1 and compare") - serviceExport(r, "hello", test.BuildServiceWithOptions("hello", - servingtest.WithConfigSpec(test.BuildConfigurationSpec()), + serviceExport(r, "hello", e2e.BuildServiceWithOptions("hello", + servingtest.WithConfigSpec(e2e.BuildConfigurationSpec()), servingtest.WithBYORevisionName("hello-rev1"), - test.WithRevisionAnnotations(map[string]string{"client.knative.dev/user-image": userImage}), + e2e.WithRevisionAnnotations(map[string]string{"client.knative.dev/user-image": userImage}), ), "--mode", "replay", "-o", "json") t.Log("update service - add env variable") - test.ServiceUpdate(r, "hello", "--env", "a=mouse", "--revision-name", "rev2", "--no-lock-to-digest") - serviceExport(r, "hello", test.BuildServiceWithOptions("hello", - servingtest.WithConfigSpec(test.BuildConfigurationSpec()), + e2e.ServiceUpdate(r, "hello", "--env", "a=mouse", "--revision-name", "rev2", "--no-lock-to-digest") + serviceExport(r, "hello", e2e.BuildServiceWithOptions("hello", + servingtest.WithConfigSpec(e2e.BuildConfigurationSpec()), servingtest.WithBYORevisionName("hello-rev2"), servingtest.WithEnv(corev1.EnvVar{Name: "a", Value: "mouse"}), ), "--mode", "replay", "-o", "json") t.Log("export service-revision2 with kubernetes-resources") - serviceExportWithServiceList(r, "hello", test.BuildServiceListWithOptions( - test.WithService(test.BuildServiceWithOptions("hello", - servingtest.WithConfigSpec(test.BuildConfigurationSpec()), + serviceExportWithServiceList(r, "hello", e2e.BuildServiceListWithOptions( + e2e.WithService(e2e.BuildServiceWithOptions("hello", + servingtest.WithConfigSpec(e2e.BuildConfigurationSpec()), servingtest.WithBYORevisionName("hello-rev2"), - test.WithTrafficSpec([]string{"latest"}, []int{100}, []string{""}), + e2e.WithTrafficSpec([]string{"latest"}, []int{100}, []string{""}), servingtest.WithEnv(corev1.EnvVar{Name: "a", Value: "mouse"}), )), ), "--with-revisions", "--mode", "replay", "-o", "yaml") t.Log("export service-revision2 with revisions-only") - serviceExportWithRevisionList(r, "hello", test.BuildServiceWithOptions("hello", - servingtest.WithConfigSpec(test.BuildConfigurationSpec()), + serviceExportWithRevisionList(r, "hello", e2e.BuildServiceWithOptions("hello", + servingtest.WithConfigSpec(e2e.BuildConfigurationSpec()), servingtest.WithBYORevisionName("hello-rev2"), - test.WithTrafficSpec([]string{"latest"}, []int{100}, []string{""}), + e2e.WithTrafficSpec([]string{"latest"}, []int{100}, []string{""}), servingtest.WithEnv(corev1.EnvVar{Name: "a", Value: "mouse"}), - ), test.BuildKNExportWithOptions(), "--with-revisions", "--mode", "export", "-o", "yaml") + ), e2e.BuildKNExportWithOptions(), "--with-revisions", "--mode", "export", "-o", "yaml") t.Log("update service with tag and split traffic") - test.ServiceUpdate(r, "hello", "--tag", "hello-rev1=candidate", "--traffic", "candidate=2%,@latest=98%") + e2e.ServiceUpdate(r, "hello", "--tag", "hello-rev1=candidate", "--traffic", "candidate=2%,@latest=98%") t.Log("export service-revision2 after tagging kubernetes-resources") - serviceExportWithServiceList(r, "hello", test.BuildServiceListWithOptions( - test.WithService(test.BuildServiceWithOptions("hello", - servingtest.WithConfigSpec(test.BuildConfigurationSpec()), + serviceExportWithServiceList(r, "hello", e2e.BuildServiceListWithOptions( + e2e.WithService(e2e.BuildServiceWithOptions("hello", + servingtest.WithConfigSpec(e2e.BuildConfigurationSpec()), servingtest.WithBYORevisionName("hello-rev1"), - test.WithRevisionAnnotations(map[string]string{ + e2e.WithRevisionAnnotations(map[string]string{ "client.knative.dev/user-image": userImage, "serving.knative.dev/routes": "hello", }), )), - test.WithService(test.BuildServiceWithOptions("hello", - servingtest.WithConfigSpec(test.BuildConfigurationSpec()), + e2e.WithService(e2e.BuildServiceWithOptions("hello", + servingtest.WithConfigSpec(e2e.BuildConfigurationSpec()), servingtest.WithBYORevisionName("hello-rev2"), - test.WithTrafficSpec([]string{"latest", "hello-rev1"}, []int{98, 2}, []string{"", "candidate"}), + e2e.WithTrafficSpec([]string{"latest", "hello-rev1"}, []int{98, 2}, []string{"", "candidate"}), servingtest.WithEnv(corev1.EnvVar{Name: "a", Value: "mouse"}), )), ), "--with-revisions", "--mode", "replay", "-o", "yaml") t.Log("export service-revision2 after tagging with revisions-only") - serviceExportWithRevisionList(r, "hello", test.BuildServiceWithOptions("hello", - servingtest.WithConfigSpec(test.BuildConfigurationSpec()), + serviceExportWithRevisionList(r, "hello", e2e.BuildServiceWithOptions("hello", + servingtest.WithConfigSpec(e2e.BuildConfigurationSpec()), servingtest.WithBYORevisionName("hello-rev2"), - test.WithTrafficSpec([]string{"latest", "hello-rev1"}, []int{98, 2}, []string{"", "candidate"}), + e2e.WithTrafficSpec([]string{"latest", "hello-rev1"}, []int{98, 2}, []string{"", "candidate"}), servingtest.WithEnv(corev1.EnvVar{Name: "a", Value: "mouse"}), - ), test.BuildKNExportWithOptions( - test.WithKNRevision(*(test.BuildRevision("hello-rev1", + ), e2e.BuildKNExportWithOptions( + e2e.WithKNRevision(*(e2e.BuildRevision("hello-rev1", servingtest.WithRevisionAnn("client.knative.dev/user-image", userImage), servingtest.WithRevisionAnn("serving.knative.dev/routes", "hello"), servingtest.WithRevisionLabel("serving.knative.dev/configuration", "hello"), servingtest.WithRevisionLabel("serving.knative.dev/configurationGeneration", "1"), servingtest.WithRevisionLabel("serving.knative.dev/routingState", "active"), servingtest.WithRevisionLabel("serving.knative.dev/service", "hello"), - test.WithRevisionImage(pkgtest.ImagePath("helloworld")), + e2e.WithRevisionImage(pkgtest.ImagePath("helloworld")), ))), ), "--with-revisions", "--mode", "export", "-o", "yaml") t.Log("update service - untag, add env variable, traffic split and system revision name") - test.ServiceUpdate(r, "hello", "--untag", "candidate") - test.ServiceUpdate(r, "hello", "--env", "b=cat", "--revision-name", "hello-rev3", "--traffic", "hello-rev1=30,hello-rev2=30,hello-rev3=40") + e2e.ServiceUpdate(r, "hello", "--untag", "candidate") + e2e.ServiceUpdate(r, "hello", "--env", "b=cat", "--revision-name", "hello-rev3", "--traffic", "hello-rev1=30,hello-rev2=30,hello-rev3=40") t.Log("export service-revision3 with kubernetes-resources") - serviceExportWithServiceList(r, "hello", test.BuildServiceListWithOptions( - test.WithService(test.BuildServiceWithOptions("hello", - servingtest.WithConfigSpec(test.BuildConfigurationSpec()), - test.WithRevisionAnnotations(map[string]string{ + serviceExportWithServiceList(r, "hello", e2e.BuildServiceListWithOptions( + e2e.WithService(e2e.BuildServiceWithOptions("hello", + servingtest.WithConfigSpec(e2e.BuildConfigurationSpec()), + e2e.WithRevisionAnnotations(map[string]string{ "client.knative.dev/user-image": userImage, "serving.knative.dev/routes": "hello", }), servingtest.WithBYORevisionName("hello-rev1"), ), ), - test.WithService(test.BuildServiceWithOptions("hello", - servingtest.WithConfigSpec(test.BuildConfigurationSpec()), + e2e.WithService(e2e.BuildServiceWithOptions("hello", + servingtest.WithConfigSpec(e2e.BuildConfigurationSpec()), servingtest.WithBYORevisionName("hello-rev2"), - test.WithRevisionAnnotations(map[string]string{ + e2e.WithRevisionAnnotations(map[string]string{ "serving.knative.dev/routes": "hello", }), servingtest.WithEnv(corev1.EnvVar{Name: "a", Value: "mouse"}), ), ), - test.WithService(test.BuildServiceWithOptions("hello", - servingtest.WithConfigSpec(test.BuildConfigurationSpec()), + e2e.WithService(e2e.BuildServiceWithOptions("hello", + servingtest.WithConfigSpec(e2e.BuildConfigurationSpec()), servingtest.WithBYORevisionName("hello-rev3"), - test.WithTrafficSpec([]string{"hello-rev1", "hello-rev2", "hello-rev3"}, []int{30, 30, 40}, []string{"", "", ""}), + e2e.WithTrafficSpec([]string{"hello-rev1", "hello-rev2", "hello-rev3"}, []int{30, 30, 40}, []string{"", "", ""}), servingtest.WithEnv(corev1.EnvVar{Name: "a", Value: "mouse"}, corev1.EnvVar{Name: "b", Value: "cat"}), ), )), "--with-revisions", "--mode", "replay", "-o", "yaml") t.Log("export service-revision3 with revisions-only") - serviceExportWithRevisionList(r, "hello", test.BuildServiceWithOptions("hello", - servingtest.WithConfigSpec(test.BuildConfigurationSpec()), - test.WithTrafficSpec([]string{"hello-rev1", "hello-rev2", "hello-rev3"}, []int{30, 30, 40}, []string{"", "", ""}), + serviceExportWithRevisionList(r, "hello", e2e.BuildServiceWithOptions("hello", + servingtest.WithConfigSpec(e2e.BuildConfigurationSpec()), + e2e.WithTrafficSpec([]string{"hello-rev1", "hello-rev2", "hello-rev3"}, []int{30, 30, 40}, []string{"", "", ""}), servingtest.WithBYORevisionName("hello-rev3"), servingtest.WithEnv(corev1.EnvVar{Name: "a", Value: "mouse"}, corev1.EnvVar{Name: "b", Value: "cat"}), - ), test.BuildKNExportWithOptions( - test.WithKNRevision(*(test.BuildRevision("hello-rev1", + ), e2e.BuildKNExportWithOptions( + e2e.WithKNRevision(*(e2e.BuildRevision("hello-rev1", servingtest.WithRevisionAnn("client.knative.dev/user-image", userImage), servingtest.WithRevisionAnn("serving.knative.dev/routes", "hello"), servingtest.WithRevisionLabel("serving.knative.dev/configuration", "hello"), servingtest.WithRevisionLabel("serving.knative.dev/configurationGeneration", "1"), servingtest.WithRevisionLabel("serving.knative.dev/routingState", "active"), servingtest.WithRevisionLabel("serving.knative.dev/service", "hello"), - test.WithRevisionImage(pkgtest.ImagePath("helloworld")), + e2e.WithRevisionImage(pkgtest.ImagePath("helloworld")), ))), - test.WithKNRevision(*(test.BuildRevision("hello-rev2", + e2e.WithKNRevision(*(e2e.BuildRevision("hello-rev2", servingtest.WithRevisionAnn("serving.knative.dev/routes", "hello"), servingtest.WithRevisionLabel("serving.knative.dev/configuration", "hello"), servingtest.WithRevisionLabel("serving.knative.dev/configurationGeneration", "2"), servingtest.WithRevisionLabel("serving.knative.dev/routingState", "active"), servingtest.WithRevisionLabel("serving.knative.dev/service", "hello"), - test.WithRevisionImage(pkgtest.ImagePath("helloworld")), - test.WithRevisionEnv(corev1.EnvVar{Name: "a", Value: "mouse"}), + e2e.WithRevisionImage(pkgtest.ImagePath("helloworld")), + e2e.WithRevisionEnv(corev1.EnvVar{Name: "a", Value: "mouse"}), ))), ), "--with-revisions", "--mode", "export", "-o", "yaml") t.Log("send all traffic to revision 2") - test.ServiceUpdate(r, "hello", "--traffic", "hello-rev2=100") + e2e.ServiceUpdate(r, "hello", "--traffic", "hello-rev2=100") t.Log("export kubernetes-resources - all traffic to revision 2") - serviceExportWithServiceList(r, "hello", test.BuildServiceListWithOptions( - test.WithService(test.BuildServiceWithOptions("hello", - servingtest.WithConfigSpec(test.BuildConfigurationSpec()), + serviceExportWithServiceList(r, "hello", e2e.BuildServiceListWithOptions( + e2e.WithService(e2e.BuildServiceWithOptions("hello", + servingtest.WithConfigSpec(e2e.BuildConfigurationSpec()), servingtest.WithBYORevisionName("hello-rev2"), - test.WithRevisionAnnotations(map[string]string{ + e2e.WithRevisionAnnotations(map[string]string{ "serving.knative.dev/routes": "hello", }), servingtest.WithEnv(corev1.EnvVar{Name: "a", Value: "mouse"}), ), ), - test.WithService(test.BuildServiceWithOptions("hello", - servingtest.WithConfigSpec(test.BuildConfigurationSpec()), - test.WithTrafficSpec([]string{"hello-rev2"}, []int{100}, []string{""}), + e2e.WithService(e2e.BuildServiceWithOptions("hello", + servingtest.WithConfigSpec(e2e.BuildConfigurationSpec()), + e2e.WithTrafficSpec([]string{"hello-rev2"}, []int{100}, []string{""}), servingtest.WithBYORevisionName("hello-rev3"), servingtest.WithEnv(corev1.EnvVar{Name: "a", Value: "mouse"}, corev1.EnvVar{Name: "b", Value: "cat"}), ), @@ -215,20 +216,20 @@ func TestServiceExport(t *testing.T) { ), "--with-revisions", "--mode", "replay", "-o", "yaml") t.Log("export revisions-only - all traffic to revision 2") - serviceExportWithRevisionList(r, "hello", test.BuildServiceWithOptions("hello", - servingtest.WithConfigSpec(test.BuildConfigurationSpec()), + serviceExportWithRevisionList(r, "hello", e2e.BuildServiceWithOptions("hello", + servingtest.WithConfigSpec(e2e.BuildConfigurationSpec()), servingtest.WithBYORevisionName("hello-rev3"), - test.WithTrafficSpec([]string{"hello-rev2"}, []int{100}, []string{""}), + e2e.WithTrafficSpec([]string{"hello-rev2"}, []int{100}, []string{""}), servingtest.WithEnv(corev1.EnvVar{Name: "a", Value: "mouse"}, corev1.EnvVar{Name: "b", Value: "cat"}), - ), test.BuildKNExportWithOptions( - test.WithKNRevision(*(test.BuildRevision("hello-rev2", + ), e2e.BuildKNExportWithOptions( + e2e.WithKNRevision(*(e2e.BuildRevision("hello-rev2", servingtest.WithRevisionAnn("serving.knative.dev/routes", "hello"), servingtest.WithRevisionLabel("serving.knative.dev/configuration", "hello"), servingtest.WithRevisionLabel("serving.knative.dev/configurationGeneration", "2"), servingtest.WithRevisionLabel("serving.knative.dev/routingState", "active"), servingtest.WithRevisionLabel("serving.knative.dev/service", "hello"), - test.WithRevisionImage(pkgtest.ImagePath("helloworld")), - test.WithRevisionEnv(corev1.EnvVar{Name: "a", Value: "mouse"}), + e2e.WithRevisionImage(pkgtest.ImagePath("helloworld")), + e2e.WithRevisionEnv(corev1.EnvVar{Name: "a", Value: "mouse"}), ))), ), "--with-revisions", "--mode", "export", "-o", "yaml") diff --git a/test/e2e/service_import_test.go b/test/e2e/service_import_test.go index 9bbf343c0a..f3e06268e1 100644 --- a/test/e2e/service_import_test.go +++ b/test/e2e/service_import_test.go @@ -18,6 +18,7 @@ package e2e import ( + "knative.dev/client/lib/test/e2e" "os" "path/filepath" "testing" @@ -44,10 +45,10 @@ func TestServiceImport(t *testing.T) { testFile := filepath.Join(tempDir, "foo-with-revisions") serviceCreateWithOptions(r, "foo", "--revision-name", "foo-rev-1") - test.ServiceUpdate(r, "foo", "--env", "TARGET=v2", "--revision-name", "foo-rev-2") - test.ServiceUpdate(r, "foo", "--traffic", "foo-rev-1=50,foo-rev-2=50") + e2e.ServiceUpdate(r, "foo", "--env", "TARGET=v2", "--revision-name", "foo-rev-2") + e2e.ServiceUpdate(r, "foo", "--traffic", "foo-rev-1=50,foo-rev-2=50") serviceExportToFile(r, "foo", testFile, true) - test.ServiceDelete(r, "foo") + e2e.ServiceDelete(r, "foo") serviceImport(r, testFile) t.Log("import existing service foo error") diff --git a/test/e2e/service_options_test.go b/test/e2e/service_options_test.go index ce1962c499..4861922485 100644 --- a/test/e2e/service_options_test.go +++ b/test/e2e/service_options_test.go @@ -20,6 +20,7 @@ package e2e import ( "encoding/json" "fmt" + "knative.dev/client/lib/test/e2e" "os" "strconv" "strings" @@ -56,7 +57,7 @@ func TestServiceOptions(t *testing.T) { validateServiceConcurrencyUtilization(r, "svc1", "50") t.Log("update and validate service with concurrency limit") - test.ServiceUpdate(r, "svc1", "--concurrency-limit", "300") + e2e.ServiceUpdate(r, "svc1", "--concurrency-limit", "300") validateServiceConcurrencyLimit(r, "svc1", "300") t.Log("update concurrency options with invalid values for service") @@ -70,7 +71,7 @@ func TestServiceOptions(t *testing.T) { validateServiceConcurrencyUtilization(r, "svc1", "50") t.Log("delete service") - test.ServiceDelete(r, "svc1") + e2e.ServiceDelete(r, "svc1") t.Log("create and validate service with min/max scale options") serviceCreateWithOptions(r, "svc2", "--scale-min", "1", "--scale-max", "3") @@ -78,7 +79,7 @@ func TestServiceOptions(t *testing.T) { validateServiceMaxScale(r, "svc2", "3") t.Log("update and validate service with max scale option") - test.ServiceUpdate(r, "svc2", "--scale-max", "2") + e2e.ServiceUpdate(r, "svc2", "--scale-max", "2") validateServiceMaxScale(r, "svc2", "2") t.Log("create and validate service with scale options") @@ -87,44 +88,44 @@ func TestServiceOptions(t *testing.T) { validateServiceMaxScale(r, "svc2a", "5") t.Log("update and validate service with scale option") - test.ServiceUpdate(r, "svc2a", "--scale", "2") + e2e.ServiceUpdate(r, "svc2a", "--scale", "2") validateServiceMaxScale(r, "svc2a", "2") validateServiceMinScale(r, "svc2a", "2") t.Log("delete service") - test.ServiceDelete(r, "svc2") + e2e.ServiceDelete(r, "svc2") t.Log("create, update and validate service with annotations") serviceCreateWithOptions(r, "svc3", "--annotation", "alpha=wolf", "--annotation", "brave=horse") validateServiceAnnotations(r, "svc3", map[string]string{"alpha": "wolf", "brave": "horse"}) - test.ServiceUpdate(r, "svc3", "--annotation", "alpha=direwolf", "--annotation", "brave-") + e2e.ServiceUpdate(r, "svc3", "--annotation", "alpha=direwolf", "--annotation", "brave-") validateServiceAnnotations(r, "svc3", map[string]string{"alpha": "direwolf", "brave": ""}) - test.ServiceDelete(r, "svc3") + e2e.ServiceDelete(r, "svc3") t.Log("create, update and validate service with annotations but -a") serviceCreateWithOptions(r, "svc3a", "-a", "alpha=wolf", "-a", "brave=horse") validateServiceAnnotations(r, "svc3a", map[string]string{"alpha": "wolf", "brave": "horse"}) - test.ServiceUpdate(r, "svc3a", "-a", "alpha=direwolf", "-a", "brave-") + e2e.ServiceUpdate(r, "svc3a", "-a", "alpha=direwolf", "-a", "brave-") validateServiceAnnotations(r, "svc3a", map[string]string{"alpha": "direwolf", "brave": ""}) - test.ServiceDelete(r, "svc3a") + e2e.ServiceDelete(r, "svc3a") t.Log("create, update and validate service with scale window option") for _, option := range []string{"--scale-window", "--autoscale-window"} { serviceCreateWithOptions(r, "svc4", option, "1m") validateScaleWindow(r, "svc4", "1m") - test.ServiceUpdate(r, "svc4", option, "15s") + e2e.ServiceUpdate(r, "svc4", option, "15s") validateScaleWindow(r, "svc4", "15s") - test.ServiceDelete(r, "svc4") + e2e.ServiceDelete(r, "svc4") } t.Log("create, update and validate service with cmd and arg options") serviceCreateWithOptions(r, "svc5", "--cmd", "/ko-app/helloworld") validateContainerField(r, "svc5", "command", "[\"/ko-app/helloworld\"]") - test.ServiceUpdate(r, "svc5", "--arg", "myArg1", "--arg", "--myArg2") + e2e.ServiceUpdate(r, "svc5", "--arg", "myArg1", "--arg", "--myArg2") validateContainerField(r, "svc5", "args", "[\"myArg1\",\"--myArg2\"]") - test.ServiceUpdate(r, "svc5", "--arg", "myArg1") + e2e.ServiceUpdate(r, "svc5", "--arg", "myArg1") validateContainerField(r, "svc5", "args", "[\"myArg1\"]") - test.ServiceDelete(r, "svc5") + e2e.ServiceDelete(r, "svc5") t.Log("create, update and validate service with user defined") var uid int64 = 1000 @@ -135,53 +136,53 @@ func TestServiceOptions(t *testing.T) { serviceCreateWithOptions(r, "svc6", "--user", strconv.FormatInt(uid, 10)) validateUserID(r, "svc6", uid) - test.ServiceUpdate(r, "svc6", "--user", strconv.FormatInt(uid+1, 10)) + e2e.ServiceUpdate(r, "svc6", "--user", strconv.FormatInt(uid+1, 10)) validateUserID(r, "svc6", uid+1) - test.ServiceDelete(r, "svc6") + e2e.ServiceDelete(r, "svc6") t.Log("create and validate service and revision labels") serviceCreateWithOptions(r, "svc7", "--label-service", "svc=helloworld-svc", "--label-revision", "rev=helloworld-rev") validateLabels(r, "svc7", map[string]string{"svc": "helloworld-svc"}, map[string]string{"rev": "helloworld-rev"}) - test.ServiceDelete(r, "svc7") + e2e.ServiceDelete(r, "svc7") t.Log("create and validate service resource options") serviceCreateWithOptions(r, "svc8", "--limit", "memory=500Mi,cpu=1000m", "--request", "memory=250Mi,cpu=200m") - test.ValidateServiceResources(r, "svc8", "250Mi", "200m", "500Mi", "1000m") - test.ServiceDelete(r, "svc8") + e2e.ValidateServiceResources(r, "svc8", "250Mi", "200m", "500Mi", "1000m") + e2e.ServiceDelete(r, "svc8") t.Log("create a grpc service and validate port name") serviceCreateWithOptions(r, "svc9", "--image", pkgtest.ImagePath("grpc-ping"), "--port", "h2c:8080") validatePort(r, "svc9", 8080, "h2c") - test.ServiceDelete(r, "svc9") + e2e.ServiceDelete(r, "svc9") t.Log("create and validate service with scale init option") serviceCreateWithOptions(r, "svc10", "--scale-init", "1") validateServiceInitScale(r, "svc10", "1") - test.ServiceUpdate(r, "svc10", "--scale-init", "2") + e2e.ServiceUpdate(r, "svc10", "--scale-init", "2") validateServiceInitScale(r, "svc10", "2") t.Log("delete service") - test.ServiceDelete(r, "svc10") + e2e.ServiceDelete(r, "svc10") t.Log("create and validate service with scale init option via --annotation flag") serviceCreateWithOptions(r, "svc11", "--annotation", autoscaling.InitialScaleAnnotationKey+"=2") validateServiceInitScale(r, "svc11", "2") t.Log("delete service") - test.ServiceDelete(r, "svc11") + e2e.ServiceDelete(r, "svc11") t.Log("create and validate service and revision annotations") serviceCreateWithOptions(r, "svc12", "--annotation-service", "svc=helloworld-svc", "--annotation-revision", "rev=helloworld-rev") validateServiceAndRevisionAnnotations(r, "svc12", map[string]string{"svc": "helloworld-svc"}, map[string]string{"rev": "helloworld-rev"}) - test.ServiceDelete(r, "svc12") + e2e.ServiceDelete(r, "svc12") t.Log("create and validate service annotations") serviceCreateWithOptions(r, "svc13", "--annotation-service", "svc=helloworld-svc") validateServiceAndRevisionAnnotations(r, "svc13", map[string]string{"svc": "helloworld-svc"}, nil) - test.ServiceDelete(r, "svc13") + e2e.ServiceDelete(r, "svc13") t.Log("create and validate revision annotations") serviceCreateWithOptions(r, "svc14", "--annotation-revision", "rev=helloworld-rev") validateServiceAndRevisionAnnotations(r, "svc14", nil, map[string]string{"rev": "helloworld-rev"}) - test.ServiceDelete(r, "svc14") + e2e.ServiceDelete(r, "svc14") t.Log("create and validate service env vars") env := []corev1.EnvVar{ @@ -190,7 +191,7 @@ func TestServiceOptions(t *testing.T) { } serviceCreateWithOptions(r, "svc15", "--env", "EXAMPLE=foo", "--env", "EXAMPLE2=bar") validateServiceEnvVariables(r, "svc15", env) - test.ServiceDelete(r, "svc15") + e2e.ServiceDelete(r, "svc15") t.Log("create and validate service env-value-from vars") _, err = kubectl.Run("create", "-n", it.Namespace(), "configmap", "test-cm", "--from-literal=key=value") @@ -207,7 +208,7 @@ func TestServiceOptions(t *testing.T) { } serviceCreateWithOptions(r, "svc16", "--env-value-from", "EXAMPLE=cm:test-cm:key") validateServiceEnvVariables(r, "svc16", env2) - test.ServiceDelete(r, "svc16") + e2e.ServiceDelete(r, "svc16") _, err = kubectl.Run("delete", "-n", it.Namespace(), "configmap", "test-cm") assert.NilError(t, err) @@ -228,7 +229,7 @@ func TestServiceOptions(t *testing.T) { } serviceCreateWithOptions(r, "svc17", "--env", "EXAMPLE=foo", "--env-value-from", "EXAMPLE2=config-map:test-cm2:key", "--env", "EXAMPLE3=bar") validateServiceEnvVariables(r, "svc17", env3) - test.ServiceDelete(r, "svc17") + e2e.ServiceDelete(r, "svc17") _, err = kubectl.Run("delete", "-n", it.Namespace(), "configmap", "test-cm2") assert.NilError(t, err) @@ -363,18 +364,18 @@ func validateContainerField(r *test.KnRunResultCollector, serviceName, field, ex } func validateUserID(r *test.KnRunResultCollector, serviceName string, uid int64) { - svc := test.GetServiceFromKNServiceDescribe(r, serviceName) + svc := e2e.GetServiceFromKNServiceDescribe(r, serviceName) assert.Equal(r.T(), *svc.Spec.Template.Spec.Containers[0].SecurityContext.RunAsUser, uid) } func validatePort(r *test.KnRunResultCollector, serviceName string, portNumber int32, portName string) { - svc := test.GetServiceFromKNServiceDescribe(r, serviceName) + svc := e2e.GetServiceFromKNServiceDescribe(r, serviceName) assert.Equal(r.T(), svc.Spec.Template.Spec.Containers[0].Ports[0].ContainerPort, portNumber) assert.Equal(r.T(), svc.Spec.Template.Spec.Containers[0].Ports[0].Name, portName) } func validateServiceEnvVariables(r *test.KnRunResultCollector, serviceName string, envVar []corev1.EnvVar) { - svc := test.GetServiceFromKNServiceDescribe(r, serviceName) + svc := e2e.GetServiceFromKNServiceDescribe(r, serviceName) for i, env := range svc.Spec.Template.Spec.Containers[0].Env { assert.Equal(r.T(), env.Name, envVar[i].Name) if envVar[i].ValueFrom != nil { diff --git a/test/e2e/service_test.go b/test/e2e/service_test.go index 62e3c402c0..69edebd999 100644 --- a/test/e2e/service_test.go +++ b/test/e2e/service_test.go @@ -20,6 +20,7 @@ package e2e import ( "encoding/json" "fmt" + "knative.dev/client/lib/test/e2e" "os" "strings" "testing" @@ -60,7 +61,7 @@ func TestService(t *testing.T) { defer r.DumpIfFailed() t.Log("create hello service, delete, and try to create duplicate and get service already exists error") - test.ServiceCreate(r, "hello") + e2e.ServiceCreate(r, "hello") serviceCreatePrivate(r, "hello-private") serviceCreateDuplicate(r, "hello-private") @@ -68,24 +69,24 @@ func TestService(t *testing.T) { serviceDescribeWithPrintFlags(r, "hello") t.Log("delete hello service repeatedly and get an error") - test.ServiceDelete(r, "hello") + e2e.ServiceDelete(r, "hello") serviceDeleteNonexistent(r, "hello") t.Log("delete two services with a service nonexistent") - test.ServiceCreate(r, "hello") + e2e.ServiceCreate(r, "hello") serviceMultipleDelete(r, "hello", "bla123") t.Log("create service private and make public") serviceCreatePrivateUpdatePublic(r, "hello-private-public") t.Log("error message from --untag with tag that doesn't exist") - test.ServiceCreate(r, "untag") + e2e.ServiceCreate(r, "untag") serviceUntagTagThatDoesNotExist(r, "untag") t.Log("delete all services in a namespace") - test.ServiceCreate(r, "svc1") - test.ServiceCreate(r, "service2") - test.ServiceCreate(r, "ksvc3") + e2e.ServiceCreate(r, "svc1") + e2e.ServiceCreate(r, "service2") + e2e.ServiceCreate(r, "ksvc3") serviceDeleteAll(r) t.Log("create services with volume mounts and subpaths") diff --git a/test/e2e/sinkprefix_test.go b/test/e2e/sinkprefix_test.go index bfaa55feac..11153c00a2 100644 --- a/test/e2e/sinkprefix_test.go +++ b/test/e2e/sinkprefix_test.go @@ -18,6 +18,7 @@ package e2e import ( + "knative.dev/client/lib/test/e2e" "testing" "gotest.tools/v3/assert" @@ -64,7 +65,7 @@ func TestSinkPrefixConfig(t *testing.T) { assert.NilError(t, tc.setup(t)) t.Log("Creating a testservice") - test.ServiceCreate(r, "testsvc0") + e2e.ServiceCreate(r, "testsvc0") t.Log("create Ping sources with a sink to hello:testsvc0") pingSourceCreateWithConfig(r, "testpingsource0", "* * * * */1", "ping", "hello:testsvc0", tc.knConfigPath) diff --git a/test/e2e/source_apiserver_test.go b/test/e2e/source_apiserver_test.go index d7db394163..0bcd7a1db5 100644 --- a/test/e2e/source_apiserver_test.go +++ b/test/e2e/source_apiserver_test.go @@ -19,6 +19,7 @@ package e2e import ( "fmt" + "knative.dev/client/lib/test/e2e" "strings" "testing" @@ -50,7 +51,7 @@ func TestSourceApiServer(t *testing.T) { defer r.DumpIfFailed() setupForSourceAPIServer(t, it) - test.ServiceCreate(r, "testsvc0") + e2e.ServiceCreate(r, "testsvc0") t.Log("create apiserver sources with a sink to a service") apiServerSourceCreate(r, "testapisource0", "Event:v1:key1=value1", "testsa", "ksvc:testsvc0") @@ -76,7 +77,7 @@ func TestSourceApiServer(t *testing.T) { t.Log("update apiserver source sink service") apiServerSourceCreate(r, "testapisource3", "Event:v1", "testsa", "ksvc:testsvc0") - test.ServiceCreate(r, "testsvc1") + e2e.ServiceCreate(r, "testsvc1") apiServerSourceUpdateSink(r, "testapisource3", "ksvc:testsvc1") jpSinkRefNameInSpec := "jsonpath={.spec.sink.ref.name}" out, err := test.GetResourceFieldsWithJSONPath(t, it, "apiserversource.sources.knative.dev", "testapisource3", jpSinkRefNameInSpec) diff --git a/test/e2e/source_binding_test.go b/test/e2e/source_binding_test.go index c41894607c..2429d1b7a4 100644 --- a/test/e2e/source_binding_test.go +++ b/test/e2e/source_binding_test.go @@ -18,6 +18,7 @@ package e2e import ( + "knative.dev/client/lib/test/e2e" "testing" "gotest.tools/v3/assert" @@ -37,7 +38,7 @@ func TestSourceBinding(t *testing.T) { r := test.NewKnRunResultCollector(t, it) defer r.DumpIfFailed() - test.ServiceCreate(r, "testsvc0") + e2e.ServiceCreate(r, "testsvc0") t.Log("create source binding") sourceBindingCreate(r, "my-binding0", "Deployment:apps/v1:myapp", "ksvc:testsvc0") @@ -48,7 +49,7 @@ func TestSourceBinding(t *testing.T) { t.Log("update source binding") sourceBindingCreate(r, "my-binding1", "Deployment:apps/v1:myapp", "ksvc:testsvc0") - test.ServiceCreate(r, "testsvc1") + e2e.ServiceCreate(r, "testsvc1") sourceBindingUpdate(r, "my-binding1", "Deployment:apps/v1:myapp", "ksvc:testsvc1") jpSinkRefNameInSpec := "jsonpath={.spec.sink.ref.name}" out, err := test.GetResourceFieldsWithJSONPath(t, it, "sinkbindings.sources.knative.dev", "my-binding1", jpSinkRefNameInSpec) diff --git a/test/e2e/source_container_test.go b/test/e2e/source_container_test.go index 973d417472..486a10e85a 100644 --- a/test/e2e/source_container_test.go +++ b/test/e2e/source_container_test.go @@ -18,6 +18,7 @@ package e2e import ( + "knative.dev/client/lib/test/e2e" "testing" "gotest.tools/v3/assert" @@ -39,7 +40,7 @@ func TestSourceContainer(t *testing.T) { r := test.NewKnRunResultCollector(t, it) defer r.DumpIfFailed() - test.ServiceCreate(r, "testsvc0") + e2e.ServiceCreate(r, "testsvc0") t.Log("create container source with a sink to a service") containerSourceCreate(r, "testsource0", "ksvc:testsvc0") @@ -56,7 +57,7 @@ func TestSourceContainer(t *testing.T) { t.Log("update container source sink service") containerSourceCreate(r, "testsource3", "ksvc:testsvc0") - test.ServiceCreate(r, "testsvc1") + e2e.ServiceCreate(r, "testsvc1") containerSourceUpdateSink(r, "testsource3", "ksvc:testsvc1") jpSinkRefNameInSpec := "jsonpath={.spec.sink.ref.name}" out, err := test.GetResourceFieldsWithJSONPath(t, it, "containersource.sources.knative.dev", "testsource3", jpSinkRefNameInSpec) diff --git a/test/e2e/source_list_test.go b/test/e2e/source_list_test.go index d5660cc595..081f04b833 100644 --- a/test/e2e/source_list_test.go +++ b/test/e2e/source_list_test.go @@ -18,6 +18,7 @@ package e2e import ( + "knative.dev/client/lib/test/e2e" "testing" "gotest.tools/v3/assert" @@ -55,7 +56,7 @@ func TestSourceList(t *testing.T) { defer r.DumpIfFailed() setupForSourceAPIServer(t, it) - test.ServiceCreate(r, "testsvc0") + e2e.ServiceCreate(r, "testsvc0") t.Log("List sources empty case") output := sourceList(r) diff --git a/test/e2e/subscription_test.go b/test/e2e/subscription_test.go index 3242563145..0930c311c1 100644 --- a/test/e2e/subscription_test.go +++ b/test/e2e/subscription_test.go @@ -18,6 +18,7 @@ package e2e import ( + "knative.dev/client/lib/test/e2e" "testing" "gotest.tools/v3/assert" @@ -39,13 +40,13 @@ func TestSubscriptions(t *testing.T) { t.Log("Create a subscription with all the flags") test.ChannelCreate(r, "c0") - test.ServiceCreate(r, "svc0") - test.ServiceCreate(r, "svc1") - test.ServiceCreate(r, "svc2") + e2e.ServiceCreate(r, "svc0") + e2e.ServiceCreate(r, "svc1") + e2e.ServiceCreate(r, "svc2") test.SubscriptionCreate(r, "sub0", "--channel", "c0", "--sink", "ksvc:svc0", "--sink-reply", "ksvc:svc1", "--sink-dead-letter", "ksvc:svc2") t.Log("Update a subscription") - test.ServiceCreate(r, "svc3") + e2e.ServiceCreate(r, "svc3") test.SubscriptionUpdate(r, "sub0", "--sink", "ksvc:svc3") t.Log("List subscriptions") @@ -59,9 +60,9 @@ func TestSubscriptions(t *testing.T) { t.Log("Delete subscription") test.SubscriptionDelete(r, "sub0") - test.ServiceDelete(r, "svc0") - test.ServiceDelete(r, "svc1") - test.ServiceDelete(r, "svc2") - test.ServiceDelete(r, "svc3") + e2e.ServiceDelete(r, "svc0") + e2e.ServiceDelete(r, "svc1") + e2e.ServiceDelete(r, "svc2") + e2e.ServiceDelete(r, "svc3") test.ChannelDelete(r, "c0") } diff --git a/test/e2e/traffic_split_test.go b/test/e2e/traffic_split_test.go index 46d0204fcd..dbd08aecf3 100644 --- a/test/e2e/traffic_split_test.go +++ b/test/e2e/traffic_split_test.go @@ -19,6 +19,7 @@ package e2e import ( "fmt" + "knative.dev/client/lib/test/e2e" "strconv" "strings" "testing" @@ -91,22 +92,22 @@ func TestTrafficSplit(t *testing.T) { defer r.DumpIfFailed() serviceName := test.GetNextServiceName(serviceBase) - test.ServiceCreate(r, serviceName) + e2e.ServiceCreate(r, serviceName) rev1 := fmt.Sprintf("%s-rev-1", serviceName) - test.ServiceUpdate(r, serviceName, "--env", "TARGET=v1", "--revision-name", rev1) + e2e.ServiceUpdate(r, serviceName, "--env", "TARGET=v1", "--revision-name", rev1) rev2 := fmt.Sprintf("%s-rev-2", serviceName) - test.ServiceUpdate(r, serviceName, "--env", "TARGET=v2", "--revision-name", rev2) + e2e.ServiceUpdate(r, serviceName, "--env", "TARGET=v2", "--revision-name", rev2) tflags := []string{"--tag", fmt.Sprintf("%s=v1,%s=v2", rev1, rev2), "--traffic", "v1=50,v2=50"} - test.ServiceUpdate(r, serviceName, tflags...) + e2e.ServiceUpdate(r, serviceName, tflags...) // make ordered fields per tflags (tag, revision, percent, latest) expectedTargets := []TargetFields{newTargetFields("v1", rev1, 50, false), newTargetFields("v2", rev2, 50, false)} verifyTargets(r, serviceName, expectedTargets, false) - test.ServiceDelete(r, serviceName) + e2e.ServiceDelete(r, serviceName) }, ) t.Run("20:80", @@ -116,19 +117,19 @@ func TestTrafficSplit(t *testing.T) { defer r.DumpIfFailed() serviceName := test.GetNextServiceName(serviceBase) - test.ServiceCreate(r, serviceName) + e2e.ServiceCreate(r, serviceName) rev1 := fmt.Sprintf("%s-rev-1", serviceName) - test.ServiceUpdate(r, serviceName, "--env", "TARGET=v1", "--revision-name", rev1) + e2e.ServiceUpdate(r, serviceName, "--env", "TARGET=v1", "--revision-name", rev1) rev2 := fmt.Sprintf("%s-rev-2", serviceName) - test.ServiceUpdate(r, serviceName, "--env", "TARGET=v2", "--revision-name", rev2) + e2e.ServiceUpdate(r, serviceName, "--env", "TARGET=v2", "--revision-name", rev2) - test.ServiceUpdate(r, serviceName, "--traffic", fmt.Sprintf("%s=20,%s=80", rev1, rev2)) + e2e.ServiceUpdate(r, serviceName, "--traffic", fmt.Sprintf("%s=20,%s=80", rev1, rev2)) expectedTargets := []TargetFields{newTargetFields("", rev1, 20, false), newTargetFields("", rev2, 80, false)} verifyTargets(r, serviceName, expectedTargets, false) - test.ServiceDelete(r, serviceName) + e2e.ServiceDelete(r, serviceName) }, ) t.Run("45:55 automatic traffic split", func(t *testing.T) { @@ -137,16 +138,16 @@ func TestTrafficSplit(t *testing.T) { defer r.DumpIfFailed() serviceName := test.GetNextServiceName(serviceBase) - test.ServiceCreate(r, serviceName) - test.ServiceUpdate(r, serviceName, "--env", "TARGET=v1", "--traffic", "80") + e2e.ServiceCreate(r, serviceName) + e2e.ServiceUpdate(r, serviceName, "--env", "TARGET=v1", "--traffic", "80") rev1 := fmt.Sprintf("%s-00001", serviceName) rev2 := fmt.Sprintf("%s-00002", serviceName) - test.ServiceUpdate(r, serviceName, "--traffic", fmt.Sprintf("%s=45", rev1)) + e2e.ServiceUpdate(r, serviceName, "--traffic", fmt.Sprintf("%s=45", rev1)) expectedTargets := []TargetFields{newTargetFields("", rev1, 45, false), newTargetFields("", rev2, 55, false)} verifyTargets(r, serviceName, expectedTargets, false) - test.ServiceDelete(r, serviceName) + e2e.ServiceDelete(r, serviceName) }) t.Run("45:55 automatic traffic split to new @latest and previous revision after mutation", func(t *testing.T) { t.Log("direct 45% traffic explicitly to newly created revision (@latest) and remaining 55 will automatically be directed to previous revision") @@ -155,16 +156,16 @@ func TestTrafficSplit(t *testing.T) { serviceName := test.GetNextServiceName(serviceBase) - test.ServiceCreate(r, serviceName) + e2e.ServiceCreate(r, serviceName) - test.ServiceUpdate(r, serviceName, "--env", "TARGET=v1", "--traffic", "@latest=45") + e2e.ServiceUpdate(r, serviceName, "--env", "TARGET=v1", "--traffic", "@latest=45") rev1 := fmt.Sprintf("%s-00001", serviceName) rev2 := fmt.Sprintf("%s-00002", serviceName) expectedTargets := []TargetFields{newTargetFields("", rev2, 45, true), newTargetFields("", rev1, 55, false)} verifyTargets(r, serviceName, expectedTargets, false) - test.ServiceDelete(r, serviceName) + e2e.ServiceDelete(r, serviceName) }) t.Run("45:55 automatic traffic split to @latest after mutation", func(t *testing.T) { t.Log("direct 45% traffic explicitly to previous revision and remaining 55 will automatically be directed to @latest") @@ -173,15 +174,15 @@ func TestTrafficSplit(t *testing.T) { serviceName := test.GetNextServiceName(serviceBase) - test.ServiceCreate(r, serviceName) + e2e.ServiceCreate(r, serviceName) rev1 := fmt.Sprintf("%s-00001", serviceName) rev2 := fmt.Sprintf("%s-00002", serviceName) - test.ServiceUpdate(r, serviceName, "--env", "TARGET=v1", "--traffic", fmt.Sprintf("%s=%d", rev1, 45)) + e2e.ServiceUpdate(r, serviceName, "--env", "TARGET=v1", "--traffic", fmt.Sprintf("%s=%d", rev1, 45)) expectedTargets := []TargetFields{newTargetFields("", rev2, 55, true), newTargetFields("", rev1, 45, false)} verifyTargets(r, serviceName, expectedTargets, false) - test.ServiceDelete(r, serviceName) + e2e.ServiceDelete(r, serviceName) }) t.Run("automatic traffic split failure", func(t *testing.T) { t.Log("direct 50% traffic to one of the three revisions. Remaining will not be automatically redirected as only one revision should be missing from spec") @@ -193,13 +194,13 @@ func TestTrafficSplit(t *testing.T) { rev1 := fmt.Sprintf("%s-00001", serviceName) rev2 := fmt.Sprintf("%s-00002", serviceName) - test.ServiceCreate(r, serviceName) + e2e.ServiceCreate(r, serviceName) - test.ServiceUpdate(r, serviceName, "--env", "TARGET=v1", "--traffic", "40") - test.ServiceUpdate(r, serviceName, "--env", "TARGET=v2", "--traffic", fmt.Sprintf("%s=%d,%s=%d", rev1, 10, rev2, 20)) - test.ServiceUpdateWithError(r, serviceName, "--traffic", fmt.Sprintf("%s=%d", rev1, 50)) + e2e.ServiceUpdate(r, serviceName, "--env", "TARGET=v1", "--traffic", "40") + e2e.ServiceUpdate(r, serviceName, "--env", "TARGET=v2", "--traffic", fmt.Sprintf("%s=%d,%s=%d", rev1, 10, rev2, 20)) + e2e.ServiceUpdateWithError(r, serviceName, "--traffic", fmt.Sprintf("%s=%d", rev1, 50)) - test.ServiceDelete(r, serviceName) + e2e.ServiceDelete(r, serviceName) }) t.Run("automatic traffic split failure with @latest", func(t *testing.T) { t.Log("direct 50% traffic to @latest of the three revisions. Remaining will not be automatically redirected as only one revision should be missing from spec") @@ -208,12 +209,12 @@ func TestTrafficSplit(t *testing.T) { serviceName := test.GetNextServiceName(serviceBase) - test.ServiceCreate(r, serviceName) + e2e.ServiceCreate(r, serviceName) - test.ServiceUpdate(r, serviceName, "--env", "TARGET=v1", "--traffic", "20") - test.ServiceUpdateWithError(r, serviceName, "--env", "TARGET=v2", "--traffic", "@latest=50") + e2e.ServiceUpdate(r, serviceName, "--env", "TARGET=v1", "--traffic", "20") + e2e.ServiceUpdateWithError(r, serviceName, "--env", "TARGET=v2", "--traffic", "@latest=50") - test.ServiceDelete(r, serviceName) + e2e.ServiceDelete(r, serviceName) }) t.Run("TagCandidate", func(t *testing.T) { @@ -226,14 +227,14 @@ func TestTrafficSplit(t *testing.T) { serviceCreateWithOptions(r, serviceName, "--revision-name", rev1) rev2 := fmt.Sprintf("%s-rev-2", serviceName) - test.ServiceUpdate(r, serviceName, "--env", "TARGET=v1", "--revision-name", rev2) + e2e.ServiceUpdate(r, serviceName, "--env", "TARGET=v1", "--revision-name", rev2) // no traffic, append new target with tag in traffic block - test.ServiceUpdate(r, serviceName, "--tag", fmt.Sprintf("%s=%s", rev1, "candidate")) + e2e.ServiceUpdate(r, serviceName, "--tag", fmt.Sprintf("%s=%s", rev1, "candidate")) expectedTargets := []TargetFields{newTargetFields("", rev2, 100, true), newTargetFields("candidate", rev1, 0, false)} verifyTargets(r, serviceName, expectedTargets, false) - test.ServiceDelete(r, serviceName) + e2e.ServiceDelete(r, serviceName) }, ) t.Run("TagCandidate:2:98", @@ -247,16 +248,16 @@ func TestTrafficSplit(t *testing.T) { serviceCreateWithOptions(r, serviceName, "--revision-name", rev1) rev2 := fmt.Sprintf("%s-rev-2", serviceName) - test.ServiceUpdate(r, serviceName, "--env", "TARGET=v1", "--revision-name", rev2) + e2e.ServiceUpdate(r, serviceName, "--env", "TARGET=v1", "--revision-name", rev2) // traffic by tag name and use % at the end - test.ServiceUpdate(r, serviceName, + e2e.ServiceUpdate(r, serviceName, "--tag", fmt.Sprintf("%s=%s", rev1, "candidate"), "--traffic", "candidate=2%,@latest=98%") expectedTargets := []TargetFields{newTargetFields("", rev2, 98, true), newTargetFields("candidate", rev1, 2, false)} verifyTargets(r, serviceName, expectedTargets, false) - test.ServiceDelete(r, serviceName) + e2e.ServiceDelete(r, serviceName) }, ) t.Run("TagCurrent", @@ -271,17 +272,17 @@ func TestTrafficSplit(t *testing.T) { serviceCreateWithOptions(r, serviceName, "--revision-name", rev1) rev2 := fmt.Sprintf("%s-rev-2", serviceName) - test.ServiceUpdate(r, serviceName, "--env", "TARGET=v2", "--revision-name", rev2) + e2e.ServiceUpdate(r, serviceName, "--env", "TARGET=v2", "--revision-name", rev2) rev3 := fmt.Sprintf("%s-rev-3", serviceName) - test.ServiceUpdate(r, serviceName, "--env", "TARGET=v3", "--revision-name", rev3) //note that this gives 100% traffic to latest revision (rev3) + e2e.ServiceUpdate(r, serviceName, "--env", "TARGET=v3", "--revision-name", rev3) //note that this gives 100% traffic to latest revision (rev3) // make existing state: tag current and candidate exist in traffic block - test.ServiceUpdate(r, serviceName, "--tag", fmt.Sprintf("%s=current,%s=candidate", rev1, rev2)) + e2e.ServiceUpdate(r, serviceName, "--tag", fmt.Sprintf("%s=current,%s=candidate", rev1, rev2)) // desired state of tags: update tag of revision (rev2) from candidate to current (which is present on rev1) //untag first to update - test.ServiceUpdate(r, serviceName, + e2e.ServiceUpdate(r, serviceName, "--untag", "current,candidate", "--tag", fmt.Sprintf("%s=current", rev2)) @@ -289,7 +290,7 @@ func TestTrafficSplit(t *testing.T) { // target for rev1 is removed as it had no traffic and we untagged it's tag current expectedTargets := []TargetFields{newTargetFields("", rev3, 100, true), newTargetFields("current", rev2, 0, false)} verifyTargets(r, serviceName, expectedTargets, false) - test.ServiceDelete(r, serviceName) + e2e.ServiceDelete(r, serviceName) }, ) t.Run("TagStagingLatest", @@ -303,14 +304,14 @@ func TestTrafficSplit(t *testing.T) { serviceCreateWithOptions(r, serviceName, "--revision-name", rev1) // make existing state: tag @latest as testing - test.ServiceUpdate(r, serviceName, "--tag", "@latest=testing") + e2e.ServiceUpdate(r, serviceName, "--tag", "@latest=testing") // desired state: change tag from testing to staging - test.ServiceUpdate(r, serviceName, "--untag", "testing", "--tag", "@latest=staging") + e2e.ServiceUpdate(r, serviceName, "--untag", "testing", "--tag", "@latest=staging") expectedTargets := []TargetFields{newTargetFields("staging", rev1, 100, true)} verifyTargets(r, serviceName, expectedTargets, false) - test.ServiceDelete(r, serviceName) + e2e.ServiceDelete(r, serviceName) }, ) t.Run("TagStagingNonLatest", @@ -324,18 +325,18 @@ func TestTrafficSplit(t *testing.T) { serviceCreateWithOptions(r, serviceName, "--revision-name", rev1) rev2 := fmt.Sprintf("%s-rev-2", serviceName) - test.ServiceUpdate(r, serviceName, "--env", "TARGET=v2", "--revision-name", rev2) + e2e.ServiceUpdate(r, serviceName, "--env", "TARGET=v2", "--revision-name", rev2) // make existing state: tag a revision as testing - test.ServiceUpdate(r, serviceName, "--tag", fmt.Sprintf("%s=testing", rev1)) + e2e.ServiceUpdate(r, serviceName, "--tag", fmt.Sprintf("%s=testing", rev1)) // desired state: change tag from testing to staging - test.ServiceUpdate(r, serviceName, "--untag", "testing", "--tag", fmt.Sprintf("%s=staging", rev1)) + e2e.ServiceUpdate(r, serviceName, "--untag", "testing", "--tag", fmt.Sprintf("%s=staging", rev1)) expectedTargets := []TargetFields{newTargetFields("", rev2, 100, true), newTargetFields("staging", rev1, 0, false)} verifyTargets(r, serviceName, expectedTargets, false) - test.ServiceDelete(r, serviceName) + e2e.ServiceDelete(r, serviceName) }, ) // test reducing number of targets from traffic blocked @@ -350,19 +351,19 @@ func TestTrafficSplit(t *testing.T) { serviceCreateWithOptions(r, serviceName, "--revision-name", rev1) rev2 := fmt.Sprintf("%s-rev-2", serviceName) - test.ServiceUpdate(r, serviceName, "--env", "TARGET=v2", "--revision-name", rev2) + e2e.ServiceUpdate(r, serviceName, "--env", "TARGET=v2", "--revision-name", rev2) // existing state: traffic block having a revision with tag old and some traffic - test.ServiceUpdate(r, serviceName, + e2e.ServiceUpdate(r, serviceName, "--tag", fmt.Sprintf("%s=old", rev1), "--traffic", "old=2,@latest=98") // desired state: remove revision with tag old - test.ServiceUpdate(r, serviceName, "--untag", "old", "--traffic", "@latest=100") + e2e.ServiceUpdate(r, serviceName, "--untag", "old", "--traffic", "@latest=100") expectedTargets := []TargetFields{newTargetFields("", rev2, 100, true)} verifyTargets(r, serviceName, expectedTargets, false) - test.ServiceDelete(r, serviceName) + e2e.ServiceDelete(r, serviceName) }, ) t.Run("TagStable:50:50", @@ -376,16 +377,16 @@ func TestTrafficSplit(t *testing.T) { serviceCreateWithOptions(r, serviceName, "--revision-name", rev1) // existing state: traffic block having two targets - test.ServiceUpdate(r, serviceName, "--env", "TARGET=v2", "--revision-name", serviceName+"-rev-2") + e2e.ServiceUpdate(r, serviceName, "--env", "TARGET=v2", "--revision-name", serviceName+"-rev-2") // desired state: tag non-@latest revision with two tags and 50-50% traffic each - test.ServiceUpdate(r, serviceName, + e2e.ServiceUpdate(r, serviceName, "--tag", fmt.Sprintf("%s=stable,%s=current", rev1, rev1), "--traffic", "stable=50%,current=50%") expectedTargets := []TargetFields{newTargetFields("stable", rev1, 50, false), newTargetFields("current", rev1, 50, false)} verifyTargets(r, serviceName, expectedTargets, false) - test.ServiceDelete(r, serviceName) + e2e.ServiceDelete(r, serviceName) }, ) t.Run("RevertToLatest", @@ -399,17 +400,17 @@ func TestTrafficSplit(t *testing.T) { serviceCreateWithOptions(r, serviceName, "--revision-name", rev1) rev2 := fmt.Sprintf("%s-rev-2", serviceName) - test.ServiceUpdate(r, serviceName, "--env", "TARGET=v2", "--revision-name", rev2) + e2e.ServiceUpdate(r, serviceName, "--env", "TARGET=v2", "--revision-name", rev2) // existing state: latest ready revision not getting any traffic - test.ServiceUpdate(r, serviceName, "--traffic", fmt.Sprintf("%s=100", rev1)) + e2e.ServiceUpdate(r, serviceName, "--traffic", fmt.Sprintf("%s=100", rev1)) // desired state: revert traffic to latest ready revision - test.ServiceUpdate(r, serviceName, "--traffic", "@latest=100") + e2e.ServiceUpdate(r, serviceName, "--traffic", "@latest=100") expectedTargets := []TargetFields{newTargetFields("", rev2, 100, true)} verifyTargets(r, serviceName, expectedTargets, false) - test.ServiceDelete(r, serviceName) + e2e.ServiceDelete(r, serviceName) }, ) t.Run("TagLatestAsCurrent", @@ -424,11 +425,11 @@ func TestTrafficSplit(t *testing.T) { serviceCreateWithOptions(r, serviceName, "--revision-name", rev1) // desired state: tag latest ready revision as 'current' - test.ServiceUpdate(r, serviceName, "--tag", "@latest=current") + e2e.ServiceUpdate(r, serviceName, "--tag", "@latest=current") expectedTargets := []TargetFields{newTargetFields("current", rev1, 100, true)} verifyTargets(r, serviceName, expectedTargets, false) - test.ServiceDelete(r, serviceName) + e2e.ServiceDelete(r, serviceName) }, ) t.Run("TagLatestAsCurrentWithoutKey", @@ -443,11 +444,11 @@ func TestTrafficSplit(t *testing.T) { serviceCreateWithOptions(r, serviceName, "--revision-name", rev1) // desired state: tag latest ready revision as 'current' - test.ServiceUpdate(r, serviceName, "--tag", "current") + e2e.ServiceUpdate(r, serviceName, "--tag", "current") expectedTargets := []TargetFields{newTargetFields("current", rev1, 100, true)} verifyTargets(r, serviceName, expectedTargets, false) - test.ServiceDelete(r, serviceName) + e2e.ServiceDelete(r, serviceName) }, ) t.Run("TagMisspelledLatestAsCurrent", @@ -462,11 +463,11 @@ func TestTrafficSplit(t *testing.T) { serviceCreateWithOptions(r, serviceName, "--revision-name", rev1) // desired state: tag latest ready revision as 'current' - test.ServiceUpdateWithError(r, serviceName, "--tag", "@ltest=current") + e2e.ServiceUpdateWithError(r, serviceName, "--tag", "@ltest=current") expectedTargets := []TargetFields{newTargetFields("", rev1, 100, true)} verifyTargets(r, serviceName, expectedTargets, true) - test.ServiceDelete(r, serviceName) + e2e.ServiceDelete(r, serviceName) }, ) t.Run("UpdateTag:100:0", @@ -480,23 +481,23 @@ func TestTrafficSplit(t *testing.T) { serviceCreateWithOptions(r, serviceName, "--revision-name", rev1) rev2 := fmt.Sprintf("%s-rev-2", serviceName) - test.ServiceUpdate(r, serviceName, "--env", "TARGET=v2", "--revision-name", rev2) + e2e.ServiceUpdate(r, serviceName, "--env", "TARGET=v2", "--revision-name", rev2) // existing state: two revision exists with traffic share and // each revision has tag and traffic portions - test.ServiceUpdate(r, serviceName, + e2e.ServiceUpdate(r, serviceName, "--tag", fmt.Sprintf("@latest=current,%s=candidate", rev1), "--traffic", "current=90,candidate=10") // desired state: update tag for rev1 as testing (from candidate) with 100% traffic - test.ServiceUpdate(r, serviceName, + e2e.ServiceUpdate(r, serviceName, "--untag", "candidate", "--tag", fmt.Sprintf("%s=testing", rev1), "--traffic", "testing=100") expectedTargets := []TargetFields{newTargetFields("current", rev2, 0, true), newTargetFields("testing", rev1, 100, false)} verifyTargets(r, serviceName, expectedTargets, false) - test.ServiceDelete(r, serviceName) + e2e.ServiceDelete(r, serviceName) }, ) t.Run("TagReplace", @@ -510,13 +511,13 @@ func TestTrafficSplit(t *testing.T) { serviceCreateWithOptions(r, serviceName, "--revision-name", rev1) rev2 := fmt.Sprintf("%s-rev-2", serviceName) - test.ServiceUpdate(r, serviceName, "--env", "TARGET=v2", "--revision-name", rev2) + e2e.ServiceUpdate(r, serviceName, "--env", "TARGET=v2", "--revision-name", rev2) // existing state: a revision exist with latest tag - test.ServiceUpdate(r, serviceName, "--tag", fmt.Sprintf("%s=latest", rev1)) + e2e.ServiceUpdate(r, serviceName, "--tag", fmt.Sprintf("%s=latest", rev1)) // desired state of revision tags: rev1=old rev2=latest - test.ServiceUpdate(r, serviceName, + e2e.ServiceUpdate(r, serviceName, "--untag", "latest", "--tag", fmt.Sprintf("%s=old,%s=latest", rev1, rev2)) @@ -528,7 +529,7 @@ func TestTrafficSplit(t *testing.T) { newTargetFields("latest", rev2, 0, false)} verifyTargets(r, serviceName, expectedTargets, false) - test.ServiceDelete(r, serviceName) + e2e.ServiceDelete(r, serviceName) }, ) t.Run("CreateWithTag", @@ -546,7 +547,7 @@ func TestTrafficSplit(t *testing.T) { } verifyTargets(r, serviceName, expectedTargets, true) - test.ServiceDelete(r, serviceName) + e2e.ServiceDelete(r, serviceName) }, ) t.Run("UntagNonExistentTag", @@ -560,11 +561,11 @@ func TestTrafficSplit(t *testing.T) { serviceCreateWithOptions(r, serviceName, "--revision-name", rev1) // existing state: a revision exist with latest tag - test.ServiceUpdate(r, serviceName, "--tag", fmt.Sprintf("%s=latest", rev1)) + e2e.ServiceUpdate(r, serviceName, "--tag", fmt.Sprintf("%s=latest", rev1)) // desired state of revision tags: rev1=latest // attempt to untag a tag that does not exist for the service's revisions - test.ServiceUpdateWithError(r, serviceName, "--untag", "foo") + e2e.ServiceUpdateWithError(r, serviceName, "--untag", "foo") // state should remain the same as error from --untag will stop service update expectedTargets := []TargetFields{ @@ -573,7 +574,7 @@ func TestTrafficSplit(t *testing.T) { } verifyTargets(r, serviceName, expectedTargets, true) - test.ServiceDelete(r, serviceName) + e2e.ServiceDelete(r, serviceName) }, ) t.Run("UntagNonExistentTagAndValidTag", @@ -587,12 +588,12 @@ func TestTrafficSplit(t *testing.T) { serviceCreateWithOptions(r, serviceName, "--revision-name", rev1) // existing state: a revision exist with latest tag - test.ServiceUpdate(r, serviceName, "--tag", fmt.Sprintf("%s=latest", rev1)) + e2e.ServiceUpdate(r, serviceName, "--tag", fmt.Sprintf("%s=latest", rev1)) // desired state of revision tags: rev1=latest // attempt to untag a tag that does not exist for the service's revisions (foo) // and also untag a tag that exists (latest) - test.ServiceUpdateWithError(r, serviceName, "--untag", "latest", "--untag", "foo") + e2e.ServiceUpdateWithError(r, serviceName, "--untag", "latest", "--untag", "foo") // state should remain the same as error from --untag will stop service update expectedTargets := []TargetFields{ @@ -601,13 +602,13 @@ func TestTrafficSplit(t *testing.T) { } verifyTargets(r, serviceName, expectedTargets, true) - test.ServiceDelete(r, serviceName) + e2e.ServiceDelete(r, serviceName) }, ) } func verifyTargets(r *test.KnRunResultCollector, serviceName string, expectedTargets []TargetFields, expectErr bool) { - out := test.ServiceDescribeWithJSONPath(r, serviceName, targetsJsonPath) + out := e2e.ServiceDescribeWithJSONPath(r, serviceName, targetsJsonPath) assert.Check(r.T(), out != "") actualTargets, err := splitTargets(out, targetsSeparator, len(expectedTargets)) if !expectErr { diff --git a/test/e2e/trigger_inject_broker_test.go b/test/e2e/trigger_inject_broker_test.go index 46e7868a39..944ed77e2f 100644 --- a/test/e2e/trigger_inject_broker_test.go +++ b/test/e2e/trigger_inject_broker_test.go @@ -18,6 +18,7 @@ package e2e import ( + "knative.dev/client/lib/test/e2e" "testing" "gotest.tools/v3/assert" @@ -39,8 +40,8 @@ func TestInjectBrokerTrigger(t *testing.T) { assert.NilError(t, err) - test.ServiceCreate(r, "sinksvc0") - test.ServiceCreate(r, "sinksvc1") + e2e.ServiceCreate(r, "sinksvc0") + e2e.ServiceCreate(r, "sinksvc1") t.Log("create triggers and list them") triggerCreateWithInject(r, "trigger1", "sinksvc0", []string{"a=b"}) diff --git a/test/e2e/trigger_test.go b/test/e2e/trigger_test.go index df037117ea..3bb1bd09ed 100644 --- a/test/e2e/trigger_test.go +++ b/test/e2e/trigger_test.go @@ -18,6 +18,7 @@ package e2e import ( + "knative.dev/client/lib/test/e2e" "testing" "gotest.tools/v3/assert" @@ -40,8 +41,8 @@ func TestBrokerTrigger(t *testing.T) { test.BrokerCreate(r, "default") defer test.BrokerDelete(r, "default", false) - test.ServiceCreate(r, "sinksvc0") - test.ServiceCreate(r, "sinksvc1") + e2e.ServiceCreate(r, "sinksvc0") + e2e.ServiceCreate(r, "sinksvc1") t.Log("create triggers and list them") triggerCreate(r, "trigger1", "sinksvc0", []string{"a=b"}) diff --git a/vendor/github.com/Microsoft/go-winio/.gitattributes b/vendor/github.com/Microsoft/go-winio/.gitattributes new file mode 100644 index 0000000000..94f480de94 --- /dev/null +++ b/vendor/github.com/Microsoft/go-winio/.gitattributes @@ -0,0 +1 @@ +* text=auto eol=lf \ No newline at end of file diff --git a/vendor/github.com/Microsoft/go-winio/.gitignore b/vendor/github.com/Microsoft/go-winio/.gitignore new file mode 100644 index 0000000000..815e20660e --- /dev/null +++ b/vendor/github.com/Microsoft/go-winio/.gitignore @@ -0,0 +1,10 @@ +.vscode/ + +*.exe + +# testing +testdata + +# go workspaces +go.work +go.work.sum diff --git a/vendor/github.com/Microsoft/go-winio/.golangci.yml b/vendor/github.com/Microsoft/go-winio/.golangci.yml new file mode 100644 index 0000000000..7b503d26a3 --- /dev/null +++ b/vendor/github.com/Microsoft/go-winio/.golangci.yml @@ -0,0 +1,149 @@ +run: + skip-dirs: + - pkg/etw/sample + +linters: + enable: + # style + - containedctx # struct contains a context + - dupl # duplicate code + - errname # erorrs are named correctly + - nolintlint # "//nolint" directives are properly explained + - revive # golint replacement + - unconvert # unnecessary conversions + - wastedassign + + # bugs, performance, unused, etc ... + - contextcheck # function uses a non-inherited context + - errorlint # errors not wrapped for 1.13 + - exhaustive # check exhaustiveness of enum switch statements + - gofmt # files are gofmt'ed + - gosec # security + - nilerr # returns nil even with non-nil error + - unparam # unused function params + +issues: + exclude-rules: + # err is very often shadowed in nested scopes + - linters: + - govet + text: '^shadow: declaration of "err" shadows declaration' + + # ignore long lines for skip autogen directives + - linters: + - revive + text: "^line-length-limit: " + source: "^//(go:generate|sys) " + + #TODO: remove after upgrading to go1.18 + # ignore comment spacing for nolint and sys directives + - linters: + - revive + text: "^comment-spacings: no space between comment delimiter and comment text" + source: "//(cspell:|nolint:|sys |todo)" + + # not on go 1.18 yet, so no any + - linters: + - revive + text: "^use-any: since GO 1.18 'interface{}' can be replaced by 'any'" + + # allow unjustified ignores of error checks in defer statements + - linters: + - nolintlint + text: "^directive `//nolint:errcheck` should provide explanation" + source: '^\s*defer ' + + # allow unjustified ignores of error lints for io.EOF + - linters: + - nolintlint + text: "^directive `//nolint:errorlint` should provide explanation" + source: '[=|!]= io.EOF' + + +linters-settings: + exhaustive: + default-signifies-exhaustive: true + govet: + enable-all: true + disable: + # struct order is often for Win32 compat + # also, ignore pointer bytes/GC issues for now until performance becomes an issue + - fieldalignment + check-shadowing: true + nolintlint: + allow-leading-space: false + require-explanation: true + require-specific: true + revive: + # revive is more configurable than static check, so likely the preferred alternative to static-check + # (once the perf issue is solved: https://github.com/golangci/golangci-lint/issues/2997) + enable-all-rules: + true + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md + rules: + # rules with required arguments + - name: argument-limit + disabled: true + - name: banned-characters + disabled: true + - name: cognitive-complexity + disabled: true + - name: cyclomatic + disabled: true + - name: file-header + disabled: true + - name: function-length + disabled: true + - name: function-result-limit + disabled: true + - name: max-public-structs + disabled: true + # geneally annoying rules + - name: add-constant # complains about any and all strings and integers + disabled: true + - name: confusing-naming # we frequently use "Foo()" and "foo()" together + disabled: true + - name: flag-parameter # excessive, and a common idiom we use + disabled: true + - name: unhandled-error # warns over common fmt.Print* and io.Close; rely on errcheck instead + disabled: true + # general config + - name: line-length-limit + arguments: + - 140 + - name: var-naming + arguments: + - [] + - - CID + - CRI + - CTRD + - DACL + - DLL + - DOS + - ETW + - FSCTL + - GCS + - GMSA + - HCS + - HV + - IO + - LCOW + - LDAP + - LPAC + - LTSC + - MMIO + - NT + - OCI + - PMEM + - PWSH + - RX + - SACl + - SID + - SMB + - TX + - VHD + - VHDX + - VMID + - VPCI + - WCOW + - WIM diff --git a/vendor/github.com/Microsoft/go-winio/CODEOWNERS b/vendor/github.com/Microsoft/go-winio/CODEOWNERS new file mode 100644 index 0000000000..ae1b4942b9 --- /dev/null +++ b/vendor/github.com/Microsoft/go-winio/CODEOWNERS @@ -0,0 +1 @@ + * @microsoft/containerplat diff --git a/vendor/github.com/Microsoft/go-winio/LICENSE b/vendor/github.com/Microsoft/go-winio/LICENSE new file mode 100644 index 0000000000..b8b569d774 --- /dev/null +++ b/vendor/github.com/Microsoft/go-winio/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2015 Microsoft + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/vendor/github.com/Microsoft/go-winio/README.md b/vendor/github.com/Microsoft/go-winio/README.md new file mode 100644 index 0000000000..7474b4f0b6 --- /dev/null +++ b/vendor/github.com/Microsoft/go-winio/README.md @@ -0,0 +1,89 @@ +# go-winio [![Build Status](https://github.com/microsoft/go-winio/actions/workflows/ci.yml/badge.svg)](https://github.com/microsoft/go-winio/actions/workflows/ci.yml) + +This repository contains utilities for efficiently performing Win32 IO operations in +Go. Currently, this is focused on accessing named pipes and other file handles, and +for using named pipes as a net transport. + +This code relies on IO completion ports to avoid blocking IO on system threads, allowing Go +to reuse the thread to schedule another goroutine. This limits support to Windows Vista and +newer operating systems. This is similar to the implementation of network sockets in Go's net +package. + +Please see the LICENSE file for licensing information. + +## Contributing + +This project welcomes contributions and suggestions. +Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that +you have the right to, and actually do, grant us the rights to use your contribution. +For details, visit [Microsoft CLA](https://cla.microsoft.com). + +When you submit a pull request, a CLA-bot will automatically determine whether you need to +provide a CLA and decorate the PR appropriately (e.g., label, comment). +Simply follow the instructions provided by the bot. +You will only need to do this once across all repos using our CLA. + +Additionally, the pull request pipeline requires the following steps to be performed before +mergining. + +### Code Sign-Off + +We require that contributors sign their commits using [`git commit --signoff`][git-commit-s] +to certify they either authored the work themselves or otherwise have permission to use it in this project. + +A range of commits can be signed off using [`git rebase --signoff`][git-rebase-s]. + +Please see [the developer certificate](https://developercertificate.org) for more info, +as well as to make sure that you can attest to the rules listed. +Our CI uses the DCO Github app to ensure that all commits in a given PR are signed-off. + +### Linting + +Code must pass a linting stage, which uses [`golangci-lint`][lint]. +The linting settings are stored in [`.golangci.yaml`](./.golangci.yaml), and can be run +automatically with VSCode by adding the following to your workspace or folder settings: + +```json + "go.lintTool": "golangci-lint", + "go.lintOnSave": "package", +``` + +Additional editor [integrations options are also available][lint-ide]. + +Alternatively, `golangci-lint` can be [installed locally][lint-install] and run from the repo root: + +```shell +# use . or specify a path to only lint a package +# to show all lint errors, use flags "--max-issues-per-linter=0 --max-same-issues=0" +> golangci-lint run ./... +``` + +### Go Generate + +The pipeline checks that auto-generated code, via `go generate`, are up to date. + +This can be done for the entire repo: + +```shell +> go generate ./... +``` + +## Code of Conduct + +This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). +For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or +contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. + +## Special Thanks + +Thanks to [natefinch][natefinch] for the inspiration for this library. +See [npipe](https://github.com/natefinch/npipe) for another named pipe implementation. + +[lint]: https://golangci-lint.run/ +[lint-ide]: https://golangci-lint.run/usage/integrations/#editor-integration +[lint-install]: https://golangci-lint.run/usage/install/#local-installation + +[git-commit-s]: https://git-scm.com/docs/git-commit#Documentation/git-commit.txt--s +[git-rebase-s]: https://git-scm.com/docs/git-rebase#Documentation/git-rebase.txt---signoff + +[natefinch]: https://github.com/natefinch diff --git a/vendor/github.com/Microsoft/go-winio/SECURITY.md b/vendor/github.com/Microsoft/go-winio/SECURITY.md new file mode 100644 index 0000000000..869fdfe2b2 --- /dev/null +++ b/vendor/github.com/Microsoft/go-winio/SECURITY.md @@ -0,0 +1,41 @@ + + +## Security + +Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). + +If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below. + +## Reporting Security Issues + +**Please do not report security vulnerabilities through public GitHub issues.** + +Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report). + +If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey). + +You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc). + +Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: + + * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) + * Full paths of source file(s) related to the manifestation of the issue + * The location of the affected source code (tag/branch/commit or direct URL) + * Any special configuration required to reproduce the issue + * Step-by-step instructions to reproduce the issue + * Proof-of-concept or exploit code (if possible) + * Impact of the issue, including how an attacker might exploit the issue + +This information will help us triage your report more quickly. + +If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs. + +## Preferred Languages + +We prefer all communications to be in English. + +## Policy + +Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd). + + diff --git a/vendor/github.com/Microsoft/go-winio/backup.go b/vendor/github.com/Microsoft/go-winio/backup.go new file mode 100644 index 0000000000..09621c8846 --- /dev/null +++ b/vendor/github.com/Microsoft/go-winio/backup.go @@ -0,0 +1,290 @@ +//go:build windows +// +build windows + +package winio + +import ( + "encoding/binary" + "errors" + "fmt" + "io" + "os" + "runtime" + "syscall" + "unicode/utf16" + + "golang.org/x/sys/windows" +) + +//sys backupRead(h syscall.Handle, b []byte, bytesRead *uint32, abort bool, processSecurity bool, context *uintptr) (err error) = BackupRead +//sys backupWrite(h syscall.Handle, b []byte, bytesWritten *uint32, abort bool, processSecurity bool, context *uintptr) (err error) = BackupWrite + +const ( + BackupData = uint32(iota + 1) + BackupEaData + BackupSecurity + BackupAlternateData + BackupLink + BackupPropertyData + BackupObjectId //revive:disable-line:var-naming ID, not Id + BackupReparseData + BackupSparseBlock + BackupTxfsData +) + +const ( + StreamSparseAttributes = uint32(8) +) + +//nolint:revive // var-naming: ALL_CAPS +const ( + WRITE_DAC = windows.WRITE_DAC + WRITE_OWNER = windows.WRITE_OWNER + ACCESS_SYSTEM_SECURITY = windows.ACCESS_SYSTEM_SECURITY +) + +// BackupHeader represents a backup stream of a file. +type BackupHeader struct { + //revive:disable-next-line:var-naming ID, not Id + Id uint32 // The backup stream ID + Attributes uint32 // Stream attributes + Size int64 // The size of the stream in bytes + Name string // The name of the stream (for BackupAlternateData only). + Offset int64 // The offset of the stream in the file (for BackupSparseBlock only). +} + +type win32StreamID struct { + StreamID uint32 + Attributes uint32 + Size uint64 + NameSize uint32 +} + +// BackupStreamReader reads from a stream produced by the BackupRead Win32 API and produces a series +// of BackupHeader values. +type BackupStreamReader struct { + r io.Reader + bytesLeft int64 +} + +// NewBackupStreamReader produces a BackupStreamReader from any io.Reader. +func NewBackupStreamReader(r io.Reader) *BackupStreamReader { + return &BackupStreamReader{r, 0} +} + +// Next returns the next backup stream and prepares for calls to Read(). It skips the remainder of the current stream if +// it was not completely read. +func (r *BackupStreamReader) Next() (*BackupHeader, error) { + if r.bytesLeft > 0 { //nolint:nestif // todo: flatten this + if s, ok := r.r.(io.Seeker); ok { + // Make sure Seek on io.SeekCurrent sometimes succeeds + // before trying the actual seek. + if _, err := s.Seek(0, io.SeekCurrent); err == nil { + if _, err = s.Seek(r.bytesLeft, io.SeekCurrent); err != nil { + return nil, err + } + r.bytesLeft = 0 + } + } + if _, err := io.Copy(io.Discard, r); err != nil { + return nil, err + } + } + var wsi win32StreamID + if err := binary.Read(r.r, binary.LittleEndian, &wsi); err != nil { + return nil, err + } + hdr := &BackupHeader{ + Id: wsi.StreamID, + Attributes: wsi.Attributes, + Size: int64(wsi.Size), + } + if wsi.NameSize != 0 { + name := make([]uint16, int(wsi.NameSize/2)) + if err := binary.Read(r.r, binary.LittleEndian, name); err != nil { + return nil, err + } + hdr.Name = syscall.UTF16ToString(name) + } + if wsi.StreamID == BackupSparseBlock { + if err := binary.Read(r.r, binary.LittleEndian, &hdr.Offset); err != nil { + return nil, err + } + hdr.Size -= 8 + } + r.bytesLeft = hdr.Size + return hdr, nil +} + +// Read reads from the current backup stream. +func (r *BackupStreamReader) Read(b []byte) (int, error) { + if r.bytesLeft == 0 { + return 0, io.EOF + } + if int64(len(b)) > r.bytesLeft { + b = b[:r.bytesLeft] + } + n, err := r.r.Read(b) + r.bytesLeft -= int64(n) + if err == io.EOF { + err = io.ErrUnexpectedEOF + } else if r.bytesLeft == 0 && err == nil { + err = io.EOF + } + return n, err +} + +// BackupStreamWriter writes a stream compatible with the BackupWrite Win32 API. +type BackupStreamWriter struct { + w io.Writer + bytesLeft int64 +} + +// NewBackupStreamWriter produces a BackupStreamWriter on top of an io.Writer. +func NewBackupStreamWriter(w io.Writer) *BackupStreamWriter { + return &BackupStreamWriter{w, 0} +} + +// WriteHeader writes the next backup stream header and prepares for calls to Write(). +func (w *BackupStreamWriter) WriteHeader(hdr *BackupHeader) error { + if w.bytesLeft != 0 { + return fmt.Errorf("missing %d bytes", w.bytesLeft) + } + name := utf16.Encode([]rune(hdr.Name)) + wsi := win32StreamID{ + StreamID: hdr.Id, + Attributes: hdr.Attributes, + Size: uint64(hdr.Size), + NameSize: uint32(len(name) * 2), + } + if hdr.Id == BackupSparseBlock { + // Include space for the int64 block offset + wsi.Size += 8 + } + if err := binary.Write(w.w, binary.LittleEndian, &wsi); err != nil { + return err + } + if len(name) != 0 { + if err := binary.Write(w.w, binary.LittleEndian, name); err != nil { + return err + } + } + if hdr.Id == BackupSparseBlock { + if err := binary.Write(w.w, binary.LittleEndian, hdr.Offset); err != nil { + return err + } + } + w.bytesLeft = hdr.Size + return nil +} + +// Write writes to the current backup stream. +func (w *BackupStreamWriter) Write(b []byte) (int, error) { + if w.bytesLeft < int64(len(b)) { + return 0, fmt.Errorf("too many bytes by %d", int64(len(b))-w.bytesLeft) + } + n, err := w.w.Write(b) + w.bytesLeft -= int64(n) + return n, err +} + +// BackupFileReader provides an io.ReadCloser interface on top of the BackupRead Win32 API. +type BackupFileReader struct { + f *os.File + includeSecurity bool + ctx uintptr +} + +// NewBackupFileReader returns a new BackupFileReader from a file handle. If includeSecurity is true, +// Read will attempt to read the security descriptor of the file. +func NewBackupFileReader(f *os.File, includeSecurity bool) *BackupFileReader { + r := &BackupFileReader{f, includeSecurity, 0} + return r +} + +// Read reads a backup stream from the file by calling the Win32 API BackupRead(). +func (r *BackupFileReader) Read(b []byte) (int, error) { + var bytesRead uint32 + err := backupRead(syscall.Handle(r.f.Fd()), b, &bytesRead, false, r.includeSecurity, &r.ctx) + if err != nil { + return 0, &os.PathError{Op: "BackupRead", Path: r.f.Name(), Err: err} + } + runtime.KeepAlive(r.f) + if bytesRead == 0 { + return 0, io.EOF + } + return int(bytesRead), nil +} + +// Close frees Win32 resources associated with the BackupFileReader. It does not close +// the underlying file. +func (r *BackupFileReader) Close() error { + if r.ctx != 0 { + _ = backupRead(syscall.Handle(r.f.Fd()), nil, nil, true, false, &r.ctx) + runtime.KeepAlive(r.f) + r.ctx = 0 + } + return nil +} + +// BackupFileWriter provides an io.WriteCloser interface on top of the BackupWrite Win32 API. +type BackupFileWriter struct { + f *os.File + includeSecurity bool + ctx uintptr +} + +// NewBackupFileWriter returns a new BackupFileWriter from a file handle. If includeSecurity is true, +// Write() will attempt to restore the security descriptor from the stream. +func NewBackupFileWriter(f *os.File, includeSecurity bool) *BackupFileWriter { + w := &BackupFileWriter{f, includeSecurity, 0} + return w +} + +// Write restores a portion of the file using the provided backup stream. +func (w *BackupFileWriter) Write(b []byte) (int, error) { + var bytesWritten uint32 + err := backupWrite(syscall.Handle(w.f.Fd()), b, &bytesWritten, false, w.includeSecurity, &w.ctx) + if err != nil { + return 0, &os.PathError{Op: "BackupWrite", Path: w.f.Name(), Err: err} + } + runtime.KeepAlive(w.f) + if int(bytesWritten) != len(b) { + return int(bytesWritten), errors.New("not all bytes could be written") + } + return len(b), nil +} + +// Close frees Win32 resources associated with the BackupFileWriter. It does not +// close the underlying file. +func (w *BackupFileWriter) Close() error { + if w.ctx != 0 { + _ = backupWrite(syscall.Handle(w.f.Fd()), nil, nil, true, false, &w.ctx) + runtime.KeepAlive(w.f) + w.ctx = 0 + } + return nil +} + +// OpenForBackup opens a file or directory, potentially skipping access checks if the backup +// or restore privileges have been acquired. +// +// If the file opened was a directory, it cannot be used with Readdir(). +func OpenForBackup(path string, access uint32, share uint32, createmode uint32) (*os.File, error) { + winPath, err := syscall.UTF16FromString(path) + if err != nil { + return nil, err + } + h, err := syscall.CreateFile(&winPath[0], + access, + share, + nil, + createmode, + syscall.FILE_FLAG_BACKUP_SEMANTICS|syscall.FILE_FLAG_OPEN_REPARSE_POINT, + 0) + if err != nil { + err = &os.PathError{Op: "open", Path: path, Err: err} + return nil, err + } + return os.NewFile(uintptr(h), path), nil +} diff --git a/vendor/github.com/Microsoft/go-winio/doc.go b/vendor/github.com/Microsoft/go-winio/doc.go new file mode 100644 index 0000000000..1f5bfe2d54 --- /dev/null +++ b/vendor/github.com/Microsoft/go-winio/doc.go @@ -0,0 +1,22 @@ +// This package provides utilities for efficiently performing Win32 IO operations in Go. +// Currently, this package is provides support for genreal IO and management of +// - named pipes +// - files +// - [Hyper-V sockets] +// +// This code is similar to Go's [net] package, and uses IO completion ports to avoid +// blocking IO on system threads, allowing Go to reuse the thread to schedule other goroutines. +// +// This limits support to Windows Vista and newer operating systems. +// +// Additionally, this package provides support for: +// - creating and managing GUIDs +// - writing to [ETW] +// - opening and manageing VHDs +// - parsing [Windows Image files] +// - auto-generating Win32 API code +// +// [Hyper-V sockets]: https://docs.microsoft.com/en-us/virtualization/hyper-v-on-windows/user-guide/make-integration-service +// [ETW]: https://docs.microsoft.com/en-us/windows-hardware/drivers/devtest/event-tracing-for-windows--etw- +// [Windows Image files]: https://docs.microsoft.com/en-us/windows-hardware/manufacture/desktop/work-with-windows-images +package winio diff --git a/vendor/github.com/Microsoft/go-winio/ea.go b/vendor/github.com/Microsoft/go-winio/ea.go new file mode 100644 index 0000000000..e104dbdfdf --- /dev/null +++ b/vendor/github.com/Microsoft/go-winio/ea.go @@ -0,0 +1,137 @@ +package winio + +import ( + "bytes" + "encoding/binary" + "errors" +) + +type fileFullEaInformation struct { + NextEntryOffset uint32 + Flags uint8 + NameLength uint8 + ValueLength uint16 +} + +var ( + fileFullEaInformationSize = binary.Size(&fileFullEaInformation{}) + + errInvalidEaBuffer = errors.New("invalid extended attribute buffer") + errEaNameTooLarge = errors.New("extended attribute name too large") + errEaValueTooLarge = errors.New("extended attribute value too large") +) + +// ExtendedAttribute represents a single Windows EA. +type ExtendedAttribute struct { + Name string + Value []byte + Flags uint8 +} + +func parseEa(b []byte) (ea ExtendedAttribute, nb []byte, err error) { + var info fileFullEaInformation + err = binary.Read(bytes.NewReader(b), binary.LittleEndian, &info) + if err != nil { + err = errInvalidEaBuffer + return ea, nb, err + } + + nameOffset := fileFullEaInformationSize + nameLen := int(info.NameLength) + valueOffset := nameOffset + int(info.NameLength) + 1 + valueLen := int(info.ValueLength) + nextOffset := int(info.NextEntryOffset) + if valueLen+valueOffset > len(b) || nextOffset < 0 || nextOffset > len(b) { + err = errInvalidEaBuffer + return ea, nb, err + } + + ea.Name = string(b[nameOffset : nameOffset+nameLen]) + ea.Value = b[valueOffset : valueOffset+valueLen] + ea.Flags = info.Flags + if info.NextEntryOffset != 0 { + nb = b[info.NextEntryOffset:] + } + return ea, nb, err +} + +// DecodeExtendedAttributes decodes a list of EAs from a FILE_FULL_EA_INFORMATION +// buffer retrieved from BackupRead, ZwQueryEaFile, etc. +func DecodeExtendedAttributes(b []byte) (eas []ExtendedAttribute, err error) { + for len(b) != 0 { + ea, nb, err := parseEa(b) + if err != nil { + return nil, err + } + + eas = append(eas, ea) + b = nb + } + return eas, err +} + +func writeEa(buf *bytes.Buffer, ea *ExtendedAttribute, last bool) error { + if int(uint8(len(ea.Name))) != len(ea.Name) { + return errEaNameTooLarge + } + if int(uint16(len(ea.Value))) != len(ea.Value) { + return errEaValueTooLarge + } + entrySize := uint32(fileFullEaInformationSize + len(ea.Name) + 1 + len(ea.Value)) + withPadding := (entrySize + 3) &^ 3 + nextOffset := uint32(0) + if !last { + nextOffset = withPadding + } + info := fileFullEaInformation{ + NextEntryOffset: nextOffset, + Flags: ea.Flags, + NameLength: uint8(len(ea.Name)), + ValueLength: uint16(len(ea.Value)), + } + + err := binary.Write(buf, binary.LittleEndian, &info) + if err != nil { + return err + } + + _, err = buf.Write([]byte(ea.Name)) + if err != nil { + return err + } + + err = buf.WriteByte(0) + if err != nil { + return err + } + + _, err = buf.Write(ea.Value) + if err != nil { + return err + } + + _, err = buf.Write([]byte{0, 0, 0}[0 : withPadding-entrySize]) + if err != nil { + return err + } + + return nil +} + +// EncodeExtendedAttributes encodes a list of EAs into a FILE_FULL_EA_INFORMATION +// buffer for use with BackupWrite, ZwSetEaFile, etc. +func EncodeExtendedAttributes(eas []ExtendedAttribute) ([]byte, error) { + var buf bytes.Buffer + for i := range eas { + last := false + if i == len(eas)-1 { + last = true + } + + err := writeEa(&buf, &eas[i], last) + if err != nil { + return nil, err + } + } + return buf.Bytes(), nil +} diff --git a/vendor/github.com/Microsoft/go-winio/file.go b/vendor/github.com/Microsoft/go-winio/file.go new file mode 100644 index 0000000000..175a99d3f4 --- /dev/null +++ b/vendor/github.com/Microsoft/go-winio/file.go @@ -0,0 +1,331 @@ +//go:build windows +// +build windows + +package winio + +import ( + "errors" + "io" + "runtime" + "sync" + "sync/atomic" + "syscall" + "time" + + "golang.org/x/sys/windows" +) + +//sys cancelIoEx(file syscall.Handle, o *syscall.Overlapped) (err error) = CancelIoEx +//sys createIoCompletionPort(file syscall.Handle, port syscall.Handle, key uintptr, threadCount uint32) (newport syscall.Handle, err error) = CreateIoCompletionPort +//sys getQueuedCompletionStatus(port syscall.Handle, bytes *uint32, key *uintptr, o **ioOperation, timeout uint32) (err error) = GetQueuedCompletionStatus +//sys setFileCompletionNotificationModes(h syscall.Handle, flags uint8) (err error) = SetFileCompletionNotificationModes +//sys wsaGetOverlappedResult(h syscall.Handle, o *syscall.Overlapped, bytes *uint32, wait bool, flags *uint32) (err error) = ws2_32.WSAGetOverlappedResult + +type atomicBool int32 + +func (b *atomicBool) isSet() bool { return atomic.LoadInt32((*int32)(b)) != 0 } +func (b *atomicBool) setFalse() { atomic.StoreInt32((*int32)(b), 0) } +func (b *atomicBool) setTrue() { atomic.StoreInt32((*int32)(b), 1) } + +//revive:disable-next-line:predeclared Keep "new" to maintain consistency with "atomic" pkg +func (b *atomicBool) swap(new bool) bool { + var newInt int32 + if new { + newInt = 1 + } + return atomic.SwapInt32((*int32)(b), newInt) == 1 +} + +var ( + ErrFileClosed = errors.New("file has already been closed") + ErrTimeout = &timeoutError{} +) + +type timeoutError struct{} + +func (*timeoutError) Error() string { return "i/o timeout" } +func (*timeoutError) Timeout() bool { return true } +func (*timeoutError) Temporary() bool { return true } + +type timeoutChan chan struct{} + +var ioInitOnce sync.Once +var ioCompletionPort syscall.Handle + +// ioResult contains the result of an asynchronous IO operation. +type ioResult struct { + bytes uint32 + err error +} + +// ioOperation represents an outstanding asynchronous Win32 IO. +type ioOperation struct { + o syscall.Overlapped + ch chan ioResult +} + +func initIO() { + h, err := createIoCompletionPort(syscall.InvalidHandle, 0, 0, 0xffffffff) + if err != nil { + panic(err) + } + ioCompletionPort = h + go ioCompletionProcessor(h) +} + +// win32File implements Reader, Writer, and Closer on a Win32 handle without blocking in a syscall. +// It takes ownership of this handle and will close it if it is garbage collected. +type win32File struct { + handle syscall.Handle + wg sync.WaitGroup + wgLock sync.RWMutex + closing atomicBool + socket bool + readDeadline deadlineHandler + writeDeadline deadlineHandler +} + +type deadlineHandler struct { + setLock sync.Mutex + channel timeoutChan + channelLock sync.RWMutex + timer *time.Timer + timedout atomicBool +} + +// makeWin32File makes a new win32File from an existing file handle. +func makeWin32File(h syscall.Handle) (*win32File, error) { + f := &win32File{handle: h} + ioInitOnce.Do(initIO) + _, err := createIoCompletionPort(h, ioCompletionPort, 0, 0xffffffff) + if err != nil { + return nil, err + } + err = setFileCompletionNotificationModes(h, windows.FILE_SKIP_COMPLETION_PORT_ON_SUCCESS|windows.FILE_SKIP_SET_EVENT_ON_HANDLE) + if err != nil { + return nil, err + } + f.readDeadline.channel = make(timeoutChan) + f.writeDeadline.channel = make(timeoutChan) + return f, nil +} + +func MakeOpenFile(h syscall.Handle) (io.ReadWriteCloser, error) { + // If we return the result of makeWin32File directly, it can result in an + // interface-wrapped nil, rather than a nil interface value. + f, err := makeWin32File(h) + if err != nil { + return nil, err + } + return f, nil +} + +// closeHandle closes the resources associated with a Win32 handle. +func (f *win32File) closeHandle() { + f.wgLock.Lock() + // Atomically set that we are closing, releasing the resources only once. + if !f.closing.swap(true) { + f.wgLock.Unlock() + // cancel all IO and wait for it to complete + _ = cancelIoEx(f.handle, nil) + f.wg.Wait() + // at this point, no new IO can start + syscall.Close(f.handle) + f.handle = 0 + } else { + f.wgLock.Unlock() + } +} + +// Close closes a win32File. +func (f *win32File) Close() error { + f.closeHandle() + return nil +} + +// IsClosed checks if the file has been closed. +func (f *win32File) IsClosed() bool { + return f.closing.isSet() +} + +// prepareIO prepares for a new IO operation. +// The caller must call f.wg.Done() when the IO is finished, prior to Close() returning. +func (f *win32File) prepareIO() (*ioOperation, error) { + f.wgLock.RLock() + if f.closing.isSet() { + f.wgLock.RUnlock() + return nil, ErrFileClosed + } + f.wg.Add(1) + f.wgLock.RUnlock() + c := &ioOperation{} + c.ch = make(chan ioResult) + return c, nil +} + +// ioCompletionProcessor processes completed async IOs forever. +func ioCompletionProcessor(h syscall.Handle) { + for { + var bytes uint32 + var key uintptr + var op *ioOperation + err := getQueuedCompletionStatus(h, &bytes, &key, &op, syscall.INFINITE) + if op == nil { + panic(err) + } + op.ch <- ioResult{bytes, err} + } +} + +// todo: helsaawy - create an asyncIO version that takes a context + +// asyncIO processes the return value from ReadFile or WriteFile, blocking until +// the operation has actually completed. +func (f *win32File) asyncIO(c *ioOperation, d *deadlineHandler, bytes uint32, err error) (int, error) { + if err != syscall.ERROR_IO_PENDING { //nolint:errorlint // err is Errno + return int(bytes), err + } + + if f.closing.isSet() { + _ = cancelIoEx(f.handle, &c.o) + } + + var timeout timeoutChan + if d != nil { + d.channelLock.Lock() + timeout = d.channel + d.channelLock.Unlock() + } + + var r ioResult + select { + case r = <-c.ch: + err = r.err + if err == syscall.ERROR_OPERATION_ABORTED { //nolint:errorlint // err is Errno + if f.closing.isSet() { + err = ErrFileClosed + } + } else if err != nil && f.socket { + // err is from Win32. Query the overlapped structure to get the winsock error. + var bytes, flags uint32 + err = wsaGetOverlappedResult(f.handle, &c.o, &bytes, false, &flags) + } + case <-timeout: + _ = cancelIoEx(f.handle, &c.o) + r = <-c.ch + err = r.err + if err == syscall.ERROR_OPERATION_ABORTED { //nolint:errorlint // err is Errno + err = ErrTimeout + } + } + + // runtime.KeepAlive is needed, as c is passed via native + // code to ioCompletionProcessor, c must remain alive + // until the channel read is complete. + // todo: (de)allocate *ioOperation via win32 heap functions, instead of needing to KeepAlive? + runtime.KeepAlive(c) + return int(r.bytes), err +} + +// Read reads from a file handle. +func (f *win32File) Read(b []byte) (int, error) { + c, err := f.prepareIO() + if err != nil { + return 0, err + } + defer f.wg.Done() + + if f.readDeadline.timedout.isSet() { + return 0, ErrTimeout + } + + var bytes uint32 + err = syscall.ReadFile(f.handle, b, &bytes, &c.o) + n, err := f.asyncIO(c, &f.readDeadline, bytes, err) + runtime.KeepAlive(b) + + // Handle EOF conditions. + if err == nil && n == 0 && len(b) != 0 { + return 0, io.EOF + } else if err == syscall.ERROR_BROKEN_PIPE { //nolint:errorlint // err is Errno + return 0, io.EOF + } else { + return n, err + } +} + +// Write writes to a file handle. +func (f *win32File) Write(b []byte) (int, error) { + c, err := f.prepareIO() + if err != nil { + return 0, err + } + defer f.wg.Done() + + if f.writeDeadline.timedout.isSet() { + return 0, ErrTimeout + } + + var bytes uint32 + err = syscall.WriteFile(f.handle, b, &bytes, &c.o) + n, err := f.asyncIO(c, &f.writeDeadline, bytes, err) + runtime.KeepAlive(b) + return n, err +} + +func (f *win32File) SetReadDeadline(deadline time.Time) error { + return f.readDeadline.set(deadline) +} + +func (f *win32File) SetWriteDeadline(deadline time.Time) error { + return f.writeDeadline.set(deadline) +} + +func (f *win32File) Flush() error { + return syscall.FlushFileBuffers(f.handle) +} + +func (f *win32File) Fd() uintptr { + return uintptr(f.handle) +} + +func (d *deadlineHandler) set(deadline time.Time) error { + d.setLock.Lock() + defer d.setLock.Unlock() + + if d.timer != nil { + if !d.timer.Stop() { + <-d.channel + } + d.timer = nil + } + d.timedout.setFalse() + + select { + case <-d.channel: + d.channelLock.Lock() + d.channel = make(chan struct{}) + d.channelLock.Unlock() + default: + } + + if deadline.IsZero() { + return nil + } + + timeoutIO := func() { + d.timedout.setTrue() + close(d.channel) + } + + now := time.Now() + duration := deadline.Sub(now) + if deadline.After(now) { + // Deadline is in the future, set a timer to wait + d.timer = time.AfterFunc(duration, timeoutIO) + } else { + // Deadline is in the past. Cancel all pending IO now. + timeoutIO() + } + return nil +} diff --git a/vendor/github.com/Microsoft/go-winio/fileinfo.go b/vendor/github.com/Microsoft/go-winio/fileinfo.go new file mode 100644 index 0000000000..702950e72a --- /dev/null +++ b/vendor/github.com/Microsoft/go-winio/fileinfo.go @@ -0,0 +1,92 @@ +//go:build windows +// +build windows + +package winio + +import ( + "os" + "runtime" + "unsafe" + + "golang.org/x/sys/windows" +) + +// FileBasicInfo contains file access time and file attributes information. +type FileBasicInfo struct { + CreationTime, LastAccessTime, LastWriteTime, ChangeTime windows.Filetime + FileAttributes uint32 + _ uint32 // padding +} + +// GetFileBasicInfo retrieves times and attributes for a file. +func GetFileBasicInfo(f *os.File) (*FileBasicInfo, error) { + bi := &FileBasicInfo{} + if err := windows.GetFileInformationByHandleEx( + windows.Handle(f.Fd()), + windows.FileBasicInfo, + (*byte)(unsafe.Pointer(bi)), + uint32(unsafe.Sizeof(*bi)), + ); err != nil { + return nil, &os.PathError{Op: "GetFileInformationByHandleEx", Path: f.Name(), Err: err} + } + runtime.KeepAlive(f) + return bi, nil +} + +// SetFileBasicInfo sets times and attributes for a file. +func SetFileBasicInfo(f *os.File, bi *FileBasicInfo) error { + if err := windows.SetFileInformationByHandle( + windows.Handle(f.Fd()), + windows.FileBasicInfo, + (*byte)(unsafe.Pointer(bi)), + uint32(unsafe.Sizeof(*bi)), + ); err != nil { + return &os.PathError{Op: "SetFileInformationByHandle", Path: f.Name(), Err: err} + } + runtime.KeepAlive(f) + return nil +} + +// FileStandardInfo contains extended information for the file. +// FILE_STANDARD_INFO in WinBase.h +// https://docs.microsoft.com/en-us/windows/win32/api/winbase/ns-winbase-file_standard_info +type FileStandardInfo struct { + AllocationSize, EndOfFile int64 + NumberOfLinks uint32 + DeletePending, Directory bool +} + +// GetFileStandardInfo retrieves ended information for the file. +func GetFileStandardInfo(f *os.File) (*FileStandardInfo, error) { + si := &FileStandardInfo{} + if err := windows.GetFileInformationByHandleEx(windows.Handle(f.Fd()), + windows.FileStandardInfo, + (*byte)(unsafe.Pointer(si)), + uint32(unsafe.Sizeof(*si))); err != nil { + return nil, &os.PathError{Op: "GetFileInformationByHandleEx", Path: f.Name(), Err: err} + } + runtime.KeepAlive(f) + return si, nil +} + +// FileIDInfo contains the volume serial number and file ID for a file. This pair should be +// unique on a system. +type FileIDInfo struct { + VolumeSerialNumber uint64 + FileID [16]byte +} + +// GetFileID retrieves the unique (volume, file ID) pair for a file. +func GetFileID(f *os.File) (*FileIDInfo, error) { + fileID := &FileIDInfo{} + if err := windows.GetFileInformationByHandleEx( + windows.Handle(f.Fd()), + windows.FileIdInfo, + (*byte)(unsafe.Pointer(fileID)), + uint32(unsafe.Sizeof(*fileID)), + ); err != nil { + return nil, &os.PathError{Op: "GetFileInformationByHandleEx", Path: f.Name(), Err: err} + } + runtime.KeepAlive(f) + return fileID, nil +} diff --git a/vendor/github.com/Microsoft/go-winio/hvsock.go b/vendor/github.com/Microsoft/go-winio/hvsock.go new file mode 100644 index 0000000000..c881916583 --- /dev/null +++ b/vendor/github.com/Microsoft/go-winio/hvsock.go @@ -0,0 +1,575 @@ +//go:build windows +// +build windows + +package winio + +import ( + "context" + "errors" + "fmt" + "io" + "net" + "os" + "syscall" + "time" + "unsafe" + + "golang.org/x/sys/windows" + + "github.com/Microsoft/go-winio/internal/socket" + "github.com/Microsoft/go-winio/pkg/guid" +) + +const afHVSock = 34 // AF_HYPERV + +// Well known Service and VM IDs +// https://docs.microsoft.com/en-us/virtualization/hyper-v-on-windows/user-guide/make-integration-service#vmid-wildcards + +// HvsockGUIDWildcard is the wildcard VmId for accepting connections from all partitions. +func HvsockGUIDWildcard() guid.GUID { // 00000000-0000-0000-0000-000000000000 + return guid.GUID{} +} + +// HvsockGUIDBroadcast is the wildcard VmId for broadcasting sends to all partitions. +func HvsockGUIDBroadcast() guid.GUID { // ffffffff-ffff-ffff-ffff-ffffffffffff + return guid.GUID{ + Data1: 0xffffffff, + Data2: 0xffff, + Data3: 0xffff, + Data4: [8]uint8{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + } +} + +// HvsockGUIDLoopback is the Loopback VmId for accepting connections to the same partition as the connector. +func HvsockGUIDLoopback() guid.GUID { // e0e16197-dd56-4a10-9195-5ee7a155a838 + return guid.GUID{ + Data1: 0xe0e16197, + Data2: 0xdd56, + Data3: 0x4a10, + Data4: [8]uint8{0x91, 0x95, 0x5e, 0xe7, 0xa1, 0x55, 0xa8, 0x38}, + } +} + +// HvsockGUIDSiloHost is the address of a silo's host partition: +// - The silo host of a hosted silo is the utility VM. +// - The silo host of a silo on a physical host is the physical host. +func HvsockGUIDSiloHost() guid.GUID { // 36bd0c5c-7276-4223-88ba-7d03b654c568 + return guid.GUID{ + Data1: 0x36bd0c5c, + Data2: 0x7276, + Data3: 0x4223, + Data4: [8]byte{0x88, 0xba, 0x7d, 0x03, 0xb6, 0x54, 0xc5, 0x68}, + } +} + +// HvsockGUIDChildren is the wildcard VmId for accepting connections from the connector's child partitions. +func HvsockGUIDChildren() guid.GUID { // 90db8b89-0d35-4f79-8ce9-49ea0ac8b7cd + return guid.GUID{ + Data1: 0x90db8b89, + Data2: 0xd35, + Data3: 0x4f79, + Data4: [8]uint8{0x8c, 0xe9, 0x49, 0xea, 0xa, 0xc8, 0xb7, 0xcd}, + } +} + +// HvsockGUIDParent is the wildcard VmId for accepting connections from the connector's parent partition. +// Listening on this VmId accepts connection from: +// - Inside silos: silo host partition. +// - Inside hosted silo: host of the VM. +// - Inside VM: VM host. +// - Physical host: Not supported. +func HvsockGUIDParent() guid.GUID { // a42e7cda-d03f-480c-9cc2-a4de20abb878 + return guid.GUID{ + Data1: 0xa42e7cda, + Data2: 0xd03f, + Data3: 0x480c, + Data4: [8]uint8{0x9c, 0xc2, 0xa4, 0xde, 0x20, 0xab, 0xb8, 0x78}, + } +} + +// hvsockVsockServiceTemplate is the Service GUID used for the VSOCK protocol. +func hvsockVsockServiceTemplate() guid.GUID { // 00000000-facb-11e6-bd58-64006a7986d3 + return guid.GUID{ + Data2: 0xfacb, + Data3: 0x11e6, + Data4: [8]uint8{0xbd, 0x58, 0x64, 0x00, 0x6a, 0x79, 0x86, 0xd3}, + } +} + +// An HvsockAddr is an address for a AF_HYPERV socket. +type HvsockAddr struct { + VMID guid.GUID + ServiceID guid.GUID +} + +type rawHvsockAddr struct { + Family uint16 + _ uint16 + VMID guid.GUID + ServiceID guid.GUID +} + +var _ socket.RawSockaddr = &rawHvsockAddr{} + +// Network returns the address's network name, "hvsock". +func (*HvsockAddr) Network() string { + return "hvsock" +} + +func (addr *HvsockAddr) String() string { + return fmt.Sprintf("%s:%s", &addr.VMID, &addr.ServiceID) +} + +// VsockServiceID returns an hvsock service ID corresponding to the specified AF_VSOCK port. +func VsockServiceID(port uint32) guid.GUID { + g := hvsockVsockServiceTemplate() // make a copy + g.Data1 = port + return g +} + +func (addr *HvsockAddr) raw() rawHvsockAddr { + return rawHvsockAddr{ + Family: afHVSock, + VMID: addr.VMID, + ServiceID: addr.ServiceID, + } +} + +func (addr *HvsockAddr) fromRaw(raw *rawHvsockAddr) { + addr.VMID = raw.VMID + addr.ServiceID = raw.ServiceID +} + +// Sockaddr returns a pointer to and the size of this struct. +// +// Implements the [socket.RawSockaddr] interface, and allows use in +// [socket.Bind] and [socket.ConnectEx]. +func (r *rawHvsockAddr) Sockaddr() (unsafe.Pointer, int32, error) { + return unsafe.Pointer(r), int32(unsafe.Sizeof(rawHvsockAddr{})), nil +} + +// Sockaddr interface allows use with `sockets.Bind()` and `.ConnectEx()`. +func (r *rawHvsockAddr) FromBytes(b []byte) error { + n := int(unsafe.Sizeof(rawHvsockAddr{})) + + if len(b) < n { + return fmt.Errorf("got %d, want %d: %w", len(b), n, socket.ErrBufferSize) + } + + copy(unsafe.Slice((*byte)(unsafe.Pointer(r)), n), b[:n]) + if r.Family != afHVSock { + return fmt.Errorf("got %d, want %d: %w", r.Family, afHVSock, socket.ErrAddrFamily) + } + + return nil +} + +// HvsockListener is a socket listener for the AF_HYPERV address family. +type HvsockListener struct { + sock *win32File + addr HvsockAddr +} + +var _ net.Listener = &HvsockListener{} + +// HvsockConn is a connected socket of the AF_HYPERV address family. +type HvsockConn struct { + sock *win32File + local, remote HvsockAddr +} + +var _ net.Conn = &HvsockConn{} + +func newHVSocket() (*win32File, error) { + fd, err := syscall.Socket(afHVSock, syscall.SOCK_STREAM, 1) + if err != nil { + return nil, os.NewSyscallError("socket", err) + } + f, err := makeWin32File(fd) + if err != nil { + syscall.Close(fd) + return nil, err + } + f.socket = true + return f, nil +} + +// ListenHvsock listens for connections on the specified hvsock address. +func ListenHvsock(addr *HvsockAddr) (_ *HvsockListener, err error) { + l := &HvsockListener{addr: *addr} + sock, err := newHVSocket() + if err != nil { + return nil, l.opErr("listen", err) + } + sa := addr.raw() + err = socket.Bind(windows.Handle(sock.handle), &sa) + if err != nil { + return nil, l.opErr("listen", os.NewSyscallError("socket", err)) + } + err = syscall.Listen(sock.handle, 16) + if err != nil { + return nil, l.opErr("listen", os.NewSyscallError("listen", err)) + } + return &HvsockListener{sock: sock, addr: *addr}, nil +} + +func (l *HvsockListener) opErr(op string, err error) error { + return &net.OpError{Op: op, Net: "hvsock", Addr: &l.addr, Err: err} +} + +// Addr returns the listener's network address. +func (l *HvsockListener) Addr() net.Addr { + return &l.addr +} + +// Accept waits for the next connection and returns it. +func (l *HvsockListener) Accept() (_ net.Conn, err error) { + sock, err := newHVSocket() + if err != nil { + return nil, l.opErr("accept", err) + } + defer func() { + if sock != nil { + sock.Close() + } + }() + c, err := l.sock.prepareIO() + if err != nil { + return nil, l.opErr("accept", err) + } + defer l.sock.wg.Done() + + // AcceptEx, per documentation, requires an extra 16 bytes per address. + // + // https://docs.microsoft.com/en-us/windows/win32/api/mswsock/nf-mswsock-acceptex + const addrlen = uint32(16 + unsafe.Sizeof(rawHvsockAddr{})) + var addrbuf [addrlen * 2]byte + + var bytes uint32 + err = syscall.AcceptEx(l.sock.handle, sock.handle, &addrbuf[0], 0 /* rxdatalen */, addrlen, addrlen, &bytes, &c.o) + if _, err = l.sock.asyncIO(c, nil, bytes, err); err != nil { + return nil, l.opErr("accept", os.NewSyscallError("acceptex", err)) + } + + conn := &HvsockConn{ + sock: sock, + } + // The local address returned in the AcceptEx buffer is the same as the Listener socket's + // address. However, the service GUID reported by GetSockName is different from the Listeners + // socket, and is sometimes the same as the local address of the socket that dialed the + // address, with the service GUID.Data1 incremented, but othertimes is different. + // todo: does the local address matter? is the listener's address or the actual address appropriate? + conn.local.fromRaw((*rawHvsockAddr)(unsafe.Pointer(&addrbuf[0]))) + conn.remote.fromRaw((*rawHvsockAddr)(unsafe.Pointer(&addrbuf[addrlen]))) + + // initialize the accepted socket and update its properties with those of the listening socket + if err = windows.Setsockopt(windows.Handle(sock.handle), + windows.SOL_SOCKET, windows.SO_UPDATE_ACCEPT_CONTEXT, + (*byte)(unsafe.Pointer(&l.sock.handle)), int32(unsafe.Sizeof(l.sock.handle))); err != nil { + return nil, conn.opErr("accept", os.NewSyscallError("setsockopt", err)) + } + + sock = nil + return conn, nil +} + +// Close closes the listener, causing any pending Accept calls to fail. +func (l *HvsockListener) Close() error { + return l.sock.Close() +} + +// HvsockDialer configures and dials a Hyper-V Socket (ie, [HvsockConn]). +type HvsockDialer struct { + // Deadline is the time the Dial operation must connect before erroring. + Deadline time.Time + + // Retries is the number of additional connects to try if the connection times out, is refused, + // or the host is unreachable + Retries uint + + // RetryWait is the time to wait after a connection error to retry + RetryWait time.Duration + + rt *time.Timer // redial wait timer +} + +// Dial the Hyper-V socket at addr. +// +// See [HvsockDialer.Dial] for more information. +func Dial(ctx context.Context, addr *HvsockAddr) (conn *HvsockConn, err error) { + return (&HvsockDialer{}).Dial(ctx, addr) +} + +// Dial attempts to connect to the Hyper-V socket at addr, and returns a connection if successful. +// Will attempt (HvsockDialer).Retries if dialing fails, waiting (HvsockDialer).RetryWait between +// retries. +// +// Dialing can be cancelled either by providing (HvsockDialer).Deadline, or cancelling ctx. +func (d *HvsockDialer) Dial(ctx context.Context, addr *HvsockAddr) (conn *HvsockConn, err error) { + op := "dial" + // create the conn early to use opErr() + conn = &HvsockConn{ + remote: *addr, + } + + if !d.Deadline.IsZero() { + var cancel context.CancelFunc + ctx, cancel = context.WithDeadline(ctx, d.Deadline) + defer cancel() + } + + // preemptive timeout/cancellation check + if err = ctx.Err(); err != nil { + return nil, conn.opErr(op, err) + } + + sock, err := newHVSocket() + if err != nil { + return nil, conn.opErr(op, err) + } + defer func() { + if sock != nil { + sock.Close() + } + }() + + sa := addr.raw() + err = socket.Bind(windows.Handle(sock.handle), &sa) + if err != nil { + return nil, conn.opErr(op, os.NewSyscallError("bind", err)) + } + + c, err := sock.prepareIO() + if err != nil { + return nil, conn.opErr(op, err) + } + defer sock.wg.Done() + var bytes uint32 + for i := uint(0); i <= d.Retries; i++ { + err = socket.ConnectEx( + windows.Handle(sock.handle), + &sa, + nil, // sendBuf + 0, // sendDataLen + &bytes, + (*windows.Overlapped)(unsafe.Pointer(&c.o))) + _, err = sock.asyncIO(c, nil, bytes, err) + if i < d.Retries && canRedial(err) { + if err = d.redialWait(ctx); err == nil { + continue + } + } + break + } + if err != nil { + return nil, conn.opErr(op, os.NewSyscallError("connectex", err)) + } + + // update the connection properties, so shutdown can be used + if err = windows.Setsockopt( + windows.Handle(sock.handle), + windows.SOL_SOCKET, + windows.SO_UPDATE_CONNECT_CONTEXT, + nil, // optvalue + 0, // optlen + ); err != nil { + return nil, conn.opErr(op, os.NewSyscallError("setsockopt", err)) + } + + // get the local name + var sal rawHvsockAddr + err = socket.GetSockName(windows.Handle(sock.handle), &sal) + if err != nil { + return nil, conn.opErr(op, os.NewSyscallError("getsockname", err)) + } + conn.local.fromRaw(&sal) + + // one last check for timeout, since asyncIO doesn't check the context + if err = ctx.Err(); err != nil { + return nil, conn.opErr(op, err) + } + + conn.sock = sock + sock = nil + + return conn, nil +} + +// redialWait waits before attempting to redial, resetting the timer as appropriate. +func (d *HvsockDialer) redialWait(ctx context.Context) (err error) { + if d.RetryWait == 0 { + return nil + } + + if d.rt == nil { + d.rt = time.NewTimer(d.RetryWait) + } else { + // should already be stopped and drained + d.rt.Reset(d.RetryWait) + } + + select { + case <-ctx.Done(): + case <-d.rt.C: + return nil + } + + // stop and drain the timer + if !d.rt.Stop() { + <-d.rt.C + } + return ctx.Err() +} + +// assumes error is a plain, unwrapped syscall.Errno provided by direct syscall. +func canRedial(err error) bool { + //nolint:errorlint // guaranteed to be an Errno + switch err { + case windows.WSAECONNREFUSED, windows.WSAENETUNREACH, windows.WSAETIMEDOUT, + windows.ERROR_CONNECTION_REFUSED, windows.ERROR_CONNECTION_UNAVAIL: + return true + default: + return false + } +} + +func (conn *HvsockConn) opErr(op string, err error) error { + // translate from "file closed" to "socket closed" + if errors.Is(err, ErrFileClosed) { + err = socket.ErrSocketClosed + } + return &net.OpError{Op: op, Net: "hvsock", Source: &conn.local, Addr: &conn.remote, Err: err} +} + +func (conn *HvsockConn) Read(b []byte) (int, error) { + c, err := conn.sock.prepareIO() + if err != nil { + return 0, conn.opErr("read", err) + } + defer conn.sock.wg.Done() + buf := syscall.WSABuf{Buf: &b[0], Len: uint32(len(b))} + var flags, bytes uint32 + err = syscall.WSARecv(conn.sock.handle, &buf, 1, &bytes, &flags, &c.o, nil) + n, err := conn.sock.asyncIO(c, &conn.sock.readDeadline, bytes, err) + if err != nil { + var eno windows.Errno + if errors.As(err, &eno) { + err = os.NewSyscallError("wsarecv", eno) + } + return 0, conn.opErr("read", err) + } else if n == 0 { + err = io.EOF + } + return n, err +} + +func (conn *HvsockConn) Write(b []byte) (int, error) { + t := 0 + for len(b) != 0 { + n, err := conn.write(b) + if err != nil { + return t + n, err + } + t += n + b = b[n:] + } + return t, nil +} + +func (conn *HvsockConn) write(b []byte) (int, error) { + c, err := conn.sock.prepareIO() + if err != nil { + return 0, conn.opErr("write", err) + } + defer conn.sock.wg.Done() + buf := syscall.WSABuf{Buf: &b[0], Len: uint32(len(b))} + var bytes uint32 + err = syscall.WSASend(conn.sock.handle, &buf, 1, &bytes, 0, &c.o, nil) + n, err := conn.sock.asyncIO(c, &conn.sock.writeDeadline, bytes, err) + if err != nil { + var eno windows.Errno + if errors.As(err, &eno) { + err = os.NewSyscallError("wsasend", eno) + } + return 0, conn.opErr("write", err) + } + return n, err +} + +// Close closes the socket connection, failing any pending read or write calls. +func (conn *HvsockConn) Close() error { + return conn.sock.Close() +} + +func (conn *HvsockConn) IsClosed() bool { + return conn.sock.IsClosed() +} + +// shutdown disables sending or receiving on a socket. +func (conn *HvsockConn) shutdown(how int) error { + if conn.IsClosed() { + return socket.ErrSocketClosed + } + + err := syscall.Shutdown(conn.sock.handle, how) + if err != nil { + // If the connection was closed, shutdowns fail with "not connected" + if errors.Is(err, windows.WSAENOTCONN) || + errors.Is(err, windows.WSAESHUTDOWN) { + err = socket.ErrSocketClosed + } + return os.NewSyscallError("shutdown", err) + } + return nil +} + +// CloseRead shuts down the read end of the socket, preventing future read operations. +func (conn *HvsockConn) CloseRead() error { + err := conn.shutdown(syscall.SHUT_RD) + if err != nil { + return conn.opErr("closeread", err) + } + return nil +} + +// CloseWrite shuts down the write end of the socket, preventing future write operations and +// notifying the other endpoint that no more data will be written. +func (conn *HvsockConn) CloseWrite() error { + err := conn.shutdown(syscall.SHUT_WR) + if err != nil { + return conn.opErr("closewrite", err) + } + return nil +} + +// LocalAddr returns the local address of the connection. +func (conn *HvsockConn) LocalAddr() net.Addr { + return &conn.local +} + +// RemoteAddr returns the remote address of the connection. +func (conn *HvsockConn) RemoteAddr() net.Addr { + return &conn.remote +} + +// SetDeadline implements the net.Conn SetDeadline method. +func (conn *HvsockConn) SetDeadline(t time.Time) error { + // todo: implement `SetDeadline` for `win32File` + if err := conn.SetReadDeadline(t); err != nil { + return fmt.Errorf("set read deadline: %w", err) + } + if err := conn.SetWriteDeadline(t); err != nil { + return fmt.Errorf("set write deadline: %w", err) + } + return nil +} + +// SetReadDeadline implements the net.Conn SetReadDeadline method. +func (conn *HvsockConn) SetReadDeadline(t time.Time) error { + return conn.sock.SetReadDeadline(t) +} + +// SetWriteDeadline implements the net.Conn SetWriteDeadline method. +func (conn *HvsockConn) SetWriteDeadline(t time.Time) error { + return conn.sock.SetWriteDeadline(t) +} diff --git a/vendor/github.com/Microsoft/go-winio/internal/fs/doc.go b/vendor/github.com/Microsoft/go-winio/internal/fs/doc.go new file mode 100644 index 0000000000..1f65388178 --- /dev/null +++ b/vendor/github.com/Microsoft/go-winio/internal/fs/doc.go @@ -0,0 +1,2 @@ +// This package contains Win32 filesystem functionality. +package fs diff --git a/vendor/github.com/Microsoft/go-winio/internal/fs/fs.go b/vendor/github.com/Microsoft/go-winio/internal/fs/fs.go new file mode 100644 index 0000000000..509b3ec641 --- /dev/null +++ b/vendor/github.com/Microsoft/go-winio/internal/fs/fs.go @@ -0,0 +1,202 @@ +//go:build windows + +package fs + +import ( + "golang.org/x/sys/windows" + + "github.com/Microsoft/go-winio/internal/stringbuffer" +) + +//go:generate go run github.com/Microsoft/go-winio/tools/mkwinsyscall -output zsyscall_windows.go fs.go + +// https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew +//sys CreateFile(name string, access AccessMask, mode FileShareMode, sa *syscall.SecurityAttributes, createmode FileCreationDisposition, attrs FileFlagOrAttribute, templatefile windows.Handle) (handle windows.Handle, err error) [failretval==windows.InvalidHandle] = CreateFileW + +const NullHandle windows.Handle = 0 + +// AccessMask defines standard, specific, and generic rights. +// +// Bitmask: +// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 +// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 +// +---------------+---------------+-------------------------------+ +// |G|G|G|G|Resvd|A| StandardRights| SpecificRights | +// |R|W|E|A| |S| | | +// +-+-------------+---------------+-------------------------------+ +// +// GR Generic Read +// GW Generic Write +// GE Generic Exectue +// GA Generic All +// Resvd Reserved +// AS Access Security System +// +// https://learn.microsoft.com/en-us/windows/win32/secauthz/access-mask +// +// https://learn.microsoft.com/en-us/windows/win32/secauthz/generic-access-rights +// +// https://learn.microsoft.com/en-us/windows/win32/fileio/file-access-rights-constants +type AccessMask = windows.ACCESS_MASK + +//nolint:revive // SNAKE_CASE is not idiomatic in Go, but aligned with Win32 API. +const ( + // Not actually any. + // + // For CreateFile: "query certain metadata such as file, directory, or device attributes without accessing that file or device" + // https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew#parameters + FILE_ANY_ACCESS AccessMask = 0 + + // Specific Object Access + // from ntioapi.h + + FILE_READ_DATA AccessMask = (0x0001) // file & pipe + FILE_LIST_DIRECTORY AccessMask = (0x0001) // directory + + FILE_WRITE_DATA AccessMask = (0x0002) // file & pipe + FILE_ADD_FILE AccessMask = (0x0002) // directory + + FILE_APPEND_DATA AccessMask = (0x0004) // file + FILE_ADD_SUBDIRECTORY AccessMask = (0x0004) // directory + FILE_CREATE_PIPE_INSTANCE AccessMask = (0x0004) // named pipe + + FILE_READ_EA AccessMask = (0x0008) // file & directory + FILE_READ_PROPERTIES AccessMask = FILE_READ_EA + + FILE_WRITE_EA AccessMask = (0x0010) // file & directory + FILE_WRITE_PROPERTIES AccessMask = FILE_WRITE_EA + + FILE_EXECUTE AccessMask = (0x0020) // file + FILE_TRAVERSE AccessMask = (0x0020) // directory + + FILE_DELETE_CHILD AccessMask = (0x0040) // directory + + FILE_READ_ATTRIBUTES AccessMask = (0x0080) // all + + FILE_WRITE_ATTRIBUTES AccessMask = (0x0100) // all + + FILE_ALL_ACCESS AccessMask = (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x1FF) + FILE_GENERIC_READ AccessMask = (STANDARD_RIGHTS_READ | FILE_READ_DATA | FILE_READ_ATTRIBUTES | FILE_READ_EA | SYNCHRONIZE) + FILE_GENERIC_WRITE AccessMask = (STANDARD_RIGHTS_WRITE | FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | FILE_APPEND_DATA | SYNCHRONIZE) + FILE_GENERIC_EXECUTE AccessMask = (STANDARD_RIGHTS_EXECUTE | FILE_READ_ATTRIBUTES | FILE_EXECUTE | SYNCHRONIZE) + + SPECIFIC_RIGHTS_ALL AccessMask = 0x0000FFFF + + // Standard Access + // from ntseapi.h + + DELETE AccessMask = 0x0001_0000 + READ_CONTROL AccessMask = 0x0002_0000 + WRITE_DAC AccessMask = 0x0004_0000 + WRITE_OWNER AccessMask = 0x0008_0000 + SYNCHRONIZE AccessMask = 0x0010_0000 + + STANDARD_RIGHTS_REQUIRED AccessMask = 0x000F_0000 + + STANDARD_RIGHTS_READ AccessMask = READ_CONTROL + STANDARD_RIGHTS_WRITE AccessMask = READ_CONTROL + STANDARD_RIGHTS_EXECUTE AccessMask = READ_CONTROL + + STANDARD_RIGHTS_ALL AccessMask = 0x001F_0000 +) + +type FileShareMode uint32 + +//nolint:revive // SNAKE_CASE is not idiomatic in Go, but aligned with Win32 API. +const ( + FILE_SHARE_NONE FileShareMode = 0x00 + FILE_SHARE_READ FileShareMode = 0x01 + FILE_SHARE_WRITE FileShareMode = 0x02 + FILE_SHARE_DELETE FileShareMode = 0x04 + FILE_SHARE_VALID_FLAGS FileShareMode = 0x07 +) + +type FileCreationDisposition uint32 + +//nolint:revive // SNAKE_CASE is not idiomatic in Go, but aligned with Win32 API. +const ( + // from winbase.h + + CREATE_NEW FileCreationDisposition = 0x01 + CREATE_ALWAYS FileCreationDisposition = 0x02 + OPEN_EXISTING FileCreationDisposition = 0x03 + OPEN_ALWAYS FileCreationDisposition = 0x04 + TRUNCATE_EXISTING FileCreationDisposition = 0x05 +) + +// CreateFile and co. take flags or attributes together as one parameter. +// Define alias until we can use generics to allow both + +// https://learn.microsoft.com/en-us/windows/win32/fileio/file-attribute-constants +type FileFlagOrAttribute uint32 + +//nolint:revive // SNAKE_CASE is not idiomatic in Go, but aligned with Win32 API. +const ( // from winnt.h + FILE_FLAG_WRITE_THROUGH FileFlagOrAttribute = 0x8000_0000 + FILE_FLAG_OVERLAPPED FileFlagOrAttribute = 0x4000_0000 + FILE_FLAG_NO_BUFFERING FileFlagOrAttribute = 0x2000_0000 + FILE_FLAG_RANDOM_ACCESS FileFlagOrAttribute = 0x1000_0000 + FILE_FLAG_SEQUENTIAL_SCAN FileFlagOrAttribute = 0x0800_0000 + FILE_FLAG_DELETE_ON_CLOSE FileFlagOrAttribute = 0x0400_0000 + FILE_FLAG_BACKUP_SEMANTICS FileFlagOrAttribute = 0x0200_0000 + FILE_FLAG_POSIX_SEMANTICS FileFlagOrAttribute = 0x0100_0000 + FILE_FLAG_OPEN_REPARSE_POINT FileFlagOrAttribute = 0x0020_0000 + FILE_FLAG_OPEN_NO_RECALL FileFlagOrAttribute = 0x0010_0000 + FILE_FLAG_FIRST_PIPE_INSTANCE FileFlagOrAttribute = 0x0008_0000 +) + +type FileSQSFlag = FileFlagOrAttribute + +//nolint:revive // SNAKE_CASE is not idiomatic in Go, but aligned with Win32 API. +const ( // from winbase.h + SECURITY_ANONYMOUS FileSQSFlag = FileSQSFlag(SecurityAnonymous << 16) + SECURITY_IDENTIFICATION FileSQSFlag = FileSQSFlag(SecurityIdentification << 16) + SECURITY_IMPERSONATION FileSQSFlag = FileSQSFlag(SecurityImpersonation << 16) + SECURITY_DELEGATION FileSQSFlag = FileSQSFlag(SecurityDelegation << 16) + + SECURITY_SQOS_PRESENT FileSQSFlag = 0x00100000 + SECURITY_VALID_SQOS_FLAGS FileSQSFlag = 0x001F0000 +) + +// GetFinalPathNameByHandle flags +// +// https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfinalpathnamebyhandlew#parameters +type GetFinalPathFlag uint32 + +//nolint:revive // SNAKE_CASE is not idiomatic in Go, but aligned with Win32 API. +const ( + GetFinalPathDefaultFlag GetFinalPathFlag = 0x0 + + FILE_NAME_NORMALIZED GetFinalPathFlag = 0x0 + FILE_NAME_OPENED GetFinalPathFlag = 0x8 + + VOLUME_NAME_DOS GetFinalPathFlag = 0x0 + VOLUME_NAME_GUID GetFinalPathFlag = 0x1 + VOLUME_NAME_NT GetFinalPathFlag = 0x2 + VOLUME_NAME_NONE GetFinalPathFlag = 0x4 +) + +// getFinalPathNameByHandle facilitates calling the Windows API GetFinalPathNameByHandle +// with the given handle and flags. It transparently takes care of creating a buffer of the +// correct size for the call. +// +// https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfinalpathnamebyhandlew +func GetFinalPathNameByHandle(h windows.Handle, flags GetFinalPathFlag) (string, error) { + b := stringbuffer.NewWString() + //TODO: can loop infinitely if Win32 keeps returning the same (or a larger) n? + for { + n, err := windows.GetFinalPathNameByHandle(h, b.Pointer(), b.Cap(), uint32(flags)) + if err != nil { + return "", err + } + // If the buffer wasn't large enough, n will be the total size needed (including null terminator). + // Resize and try again. + if n > b.Cap() { + b.ResizeTo(n) + continue + } + // If the buffer is large enough, n will be the size not including the null terminator. + // Convert to a Go string and return. + return b.String(), nil + } +} diff --git a/vendor/github.com/Microsoft/go-winio/internal/fs/security.go b/vendor/github.com/Microsoft/go-winio/internal/fs/security.go new file mode 100644 index 0000000000..81760ac67e --- /dev/null +++ b/vendor/github.com/Microsoft/go-winio/internal/fs/security.go @@ -0,0 +1,12 @@ +package fs + +// https://learn.microsoft.com/en-us/windows/win32/api/winnt/ne-winnt-security_impersonation_level +type SecurityImpersonationLevel int32 // C default enums underlying type is `int`, which is Go `int32` + +// Impersonation levels +const ( + SecurityAnonymous SecurityImpersonationLevel = 0 + SecurityIdentification SecurityImpersonationLevel = 1 + SecurityImpersonation SecurityImpersonationLevel = 2 + SecurityDelegation SecurityImpersonationLevel = 3 +) diff --git a/vendor/github.com/Microsoft/go-winio/internal/fs/zsyscall_windows.go b/vendor/github.com/Microsoft/go-winio/internal/fs/zsyscall_windows.go new file mode 100644 index 0000000000..e2f7bb24e5 --- /dev/null +++ b/vendor/github.com/Microsoft/go-winio/internal/fs/zsyscall_windows.go @@ -0,0 +1,64 @@ +//go:build windows + +// Code generated by 'go generate' using "github.com/Microsoft/go-winio/tools/mkwinsyscall"; DO NOT EDIT. + +package fs + +import ( + "syscall" + "unsafe" + + "golang.org/x/sys/windows" +) + +var _ unsafe.Pointer + +// Do the interface allocations only once for common +// Errno values. +const ( + errnoERROR_IO_PENDING = 997 +) + +var ( + errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING) + errERROR_EINVAL error = syscall.EINVAL +) + +// errnoErr returns common boxed Errno values, to prevent +// allocations at runtime. +func errnoErr(e syscall.Errno) error { + switch e { + case 0: + return errERROR_EINVAL + case errnoERROR_IO_PENDING: + return errERROR_IO_PENDING + } + // TODO: add more here, after collecting data on the common + // error values see on Windows. (perhaps when running + // all.bat?) + return e +} + +var ( + modkernel32 = windows.NewLazySystemDLL("kernel32.dll") + + procCreateFileW = modkernel32.NewProc("CreateFileW") +) + +func CreateFile(name string, access AccessMask, mode FileShareMode, sa *syscall.SecurityAttributes, createmode FileCreationDisposition, attrs FileFlagOrAttribute, templatefile windows.Handle) (handle windows.Handle, err error) { + var _p0 *uint16 + _p0, err = syscall.UTF16PtrFromString(name) + if err != nil { + return + } + return _CreateFile(_p0, access, mode, sa, createmode, attrs, templatefile) +} + +func _CreateFile(name *uint16, access AccessMask, mode FileShareMode, sa *syscall.SecurityAttributes, createmode FileCreationDisposition, attrs FileFlagOrAttribute, templatefile windows.Handle) (handle windows.Handle, err error) { + r0, _, e1 := syscall.Syscall9(procCreateFileW.Addr(), 7, uintptr(unsafe.Pointer(name)), uintptr(access), uintptr(mode), uintptr(unsafe.Pointer(sa)), uintptr(createmode), uintptr(attrs), uintptr(templatefile), 0, 0) + handle = windows.Handle(r0) + if handle == windows.InvalidHandle { + err = errnoErr(e1) + } + return +} diff --git a/vendor/github.com/Microsoft/go-winio/internal/socket/rawaddr.go b/vendor/github.com/Microsoft/go-winio/internal/socket/rawaddr.go new file mode 100644 index 0000000000..7e82f9afa9 --- /dev/null +++ b/vendor/github.com/Microsoft/go-winio/internal/socket/rawaddr.go @@ -0,0 +1,20 @@ +package socket + +import ( + "unsafe" +) + +// RawSockaddr allows structs to be used with [Bind] and [ConnectEx]. The +// struct must meet the Win32 sockaddr requirements specified here: +// https://docs.microsoft.com/en-us/windows/win32/winsock/sockaddr-2 +// +// Specifically, the struct size must be least larger than an int16 (unsigned short) +// for the address family. +type RawSockaddr interface { + // Sockaddr returns a pointer to the RawSockaddr and its struct size, allowing + // for the RawSockaddr's data to be overwritten by syscalls (if necessary). + // + // It is the callers responsibility to validate that the values are valid; invalid + // pointers or size can cause a panic. + Sockaddr() (unsafe.Pointer, int32, error) +} diff --git a/vendor/github.com/Microsoft/go-winio/internal/socket/socket.go b/vendor/github.com/Microsoft/go-winio/internal/socket/socket.go new file mode 100644 index 0000000000..aeb7b7250f --- /dev/null +++ b/vendor/github.com/Microsoft/go-winio/internal/socket/socket.go @@ -0,0 +1,179 @@ +//go:build windows + +package socket + +import ( + "errors" + "fmt" + "net" + "sync" + "syscall" + "unsafe" + + "github.com/Microsoft/go-winio/pkg/guid" + "golang.org/x/sys/windows" +) + +//go:generate go run github.com/Microsoft/go-winio/tools/mkwinsyscall -output zsyscall_windows.go socket.go + +//sys getsockname(s windows.Handle, name unsafe.Pointer, namelen *int32) (err error) [failretval==socketError] = ws2_32.getsockname +//sys getpeername(s windows.Handle, name unsafe.Pointer, namelen *int32) (err error) [failretval==socketError] = ws2_32.getpeername +//sys bind(s windows.Handle, name unsafe.Pointer, namelen int32) (err error) [failretval==socketError] = ws2_32.bind + +const socketError = uintptr(^uint32(0)) + +var ( + // todo(helsaawy): create custom error types to store the desired vs actual size and addr family? + + ErrBufferSize = errors.New("buffer size") + ErrAddrFamily = errors.New("address family") + ErrInvalidPointer = errors.New("invalid pointer") + ErrSocketClosed = fmt.Errorf("socket closed: %w", net.ErrClosed) +) + +// todo(helsaawy): replace these with generics, ie: GetSockName[S RawSockaddr](s windows.Handle) (S, error) + +// GetSockName writes the local address of socket s to the [RawSockaddr] rsa. +// If rsa is not large enough, the [windows.WSAEFAULT] is returned. +func GetSockName(s windows.Handle, rsa RawSockaddr) error { + ptr, l, err := rsa.Sockaddr() + if err != nil { + return fmt.Errorf("could not retrieve socket pointer and size: %w", err) + } + + // although getsockname returns WSAEFAULT if the buffer is too small, it does not set + // &l to the correct size, so--apart from doubling the buffer repeatedly--there is no remedy + return getsockname(s, ptr, &l) +} + +// GetPeerName returns the remote address the socket is connected to. +// +// See [GetSockName] for more information. +func GetPeerName(s windows.Handle, rsa RawSockaddr) error { + ptr, l, err := rsa.Sockaddr() + if err != nil { + return fmt.Errorf("could not retrieve socket pointer and size: %w", err) + } + + return getpeername(s, ptr, &l) +} + +func Bind(s windows.Handle, rsa RawSockaddr) (err error) { + ptr, l, err := rsa.Sockaddr() + if err != nil { + return fmt.Errorf("could not retrieve socket pointer and size: %w", err) + } + + return bind(s, ptr, l) +} + +// "golang.org/x/sys/windows".ConnectEx and .Bind only accept internal implementations of the +// their sockaddr interface, so they cannot be used with HvsockAddr +// Replicate functionality here from +// https://cs.opensource.google/go/x/sys/+/master:windows/syscall_windows.go + +// The function pointers to `AcceptEx`, `ConnectEx` and `GetAcceptExSockaddrs` must be loaded at +// runtime via a WSAIoctl call: +// https://docs.microsoft.com/en-us/windows/win32/api/Mswsock/nc-mswsock-lpfn_connectex#remarks + +type runtimeFunc struct { + id guid.GUID + once sync.Once + addr uintptr + err error +} + +func (f *runtimeFunc) Load() error { + f.once.Do(func() { + var s windows.Handle + s, f.err = windows.Socket(windows.AF_INET, windows.SOCK_STREAM, windows.IPPROTO_TCP) + if f.err != nil { + return + } + defer windows.CloseHandle(s) //nolint:errcheck + + var n uint32 + f.err = windows.WSAIoctl(s, + windows.SIO_GET_EXTENSION_FUNCTION_POINTER, + (*byte)(unsafe.Pointer(&f.id)), + uint32(unsafe.Sizeof(f.id)), + (*byte)(unsafe.Pointer(&f.addr)), + uint32(unsafe.Sizeof(f.addr)), + &n, + nil, // overlapped + 0, // completionRoutine + ) + }) + return f.err +} + +var ( + // todo: add `AcceptEx` and `GetAcceptExSockaddrs` + WSAID_CONNECTEX = guid.GUID{ //revive:disable-line:var-naming ALL_CAPS + Data1: 0x25a207b9, + Data2: 0xddf3, + Data3: 0x4660, + Data4: [8]byte{0x8e, 0xe9, 0x76, 0xe5, 0x8c, 0x74, 0x06, 0x3e}, + } + + connectExFunc = runtimeFunc{id: WSAID_CONNECTEX} +) + +func ConnectEx( + fd windows.Handle, + rsa RawSockaddr, + sendBuf *byte, + sendDataLen uint32, + bytesSent *uint32, + overlapped *windows.Overlapped, +) error { + if err := connectExFunc.Load(); err != nil { + return fmt.Errorf("failed to load ConnectEx function pointer: %w", err) + } + ptr, n, err := rsa.Sockaddr() + if err != nil { + return err + } + return connectEx(fd, ptr, n, sendBuf, sendDataLen, bytesSent, overlapped) +} + +// BOOL LpfnConnectex( +// [in] SOCKET s, +// [in] const sockaddr *name, +// [in] int namelen, +// [in, optional] PVOID lpSendBuffer, +// [in] DWORD dwSendDataLength, +// [out] LPDWORD lpdwBytesSent, +// [in] LPOVERLAPPED lpOverlapped +// ) + +func connectEx( + s windows.Handle, + name unsafe.Pointer, + namelen int32, + sendBuf *byte, + sendDataLen uint32, + bytesSent *uint32, + overlapped *windows.Overlapped, +) (err error) { + // todo: after upgrading to 1.18, switch from syscall.Syscall9 to syscall.SyscallN + r1, _, e1 := syscall.Syscall9(connectExFunc.addr, + 7, + uintptr(s), + uintptr(name), + uintptr(namelen), + uintptr(unsafe.Pointer(sendBuf)), + uintptr(sendDataLen), + uintptr(unsafe.Pointer(bytesSent)), + uintptr(unsafe.Pointer(overlapped)), + 0, + 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return err +} diff --git a/vendor/github.com/Microsoft/go-winio/internal/socket/zsyscall_windows.go b/vendor/github.com/Microsoft/go-winio/internal/socket/zsyscall_windows.go new file mode 100644 index 0000000000..6d2e1a9e44 --- /dev/null +++ b/vendor/github.com/Microsoft/go-winio/internal/socket/zsyscall_windows.go @@ -0,0 +1,72 @@ +//go:build windows + +// Code generated by 'go generate' using "github.com/Microsoft/go-winio/tools/mkwinsyscall"; DO NOT EDIT. + +package socket + +import ( + "syscall" + "unsafe" + + "golang.org/x/sys/windows" +) + +var _ unsafe.Pointer + +// Do the interface allocations only once for common +// Errno values. +const ( + errnoERROR_IO_PENDING = 997 +) + +var ( + errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING) + errERROR_EINVAL error = syscall.EINVAL +) + +// errnoErr returns common boxed Errno values, to prevent +// allocations at runtime. +func errnoErr(e syscall.Errno) error { + switch e { + case 0: + return errERROR_EINVAL + case errnoERROR_IO_PENDING: + return errERROR_IO_PENDING + } + // TODO: add more here, after collecting data on the common + // error values see on Windows. (perhaps when running + // all.bat?) + return e +} + +var ( + modws2_32 = windows.NewLazySystemDLL("ws2_32.dll") + + procbind = modws2_32.NewProc("bind") + procgetpeername = modws2_32.NewProc("getpeername") + procgetsockname = modws2_32.NewProc("getsockname") +) + +func bind(s windows.Handle, name unsafe.Pointer, namelen int32) (err error) { + r1, _, e1 := syscall.Syscall(procbind.Addr(), 3, uintptr(s), uintptr(name), uintptr(namelen)) + if r1 == socketError { + err = errnoErr(e1) + } + return +} + +func getpeername(s windows.Handle, name unsafe.Pointer, namelen *int32) (err error) { + r1, _, e1 := syscall.Syscall(procgetpeername.Addr(), 3, uintptr(s), uintptr(name), uintptr(unsafe.Pointer(namelen))) + if r1 == socketError { + err = errnoErr(e1) + } + return +} + +func getsockname(s windows.Handle, name unsafe.Pointer, namelen *int32) (err error) { + r1, _, e1 := syscall.Syscall(procgetsockname.Addr(), 3, uintptr(s), uintptr(name), uintptr(unsafe.Pointer(namelen))) + if r1 == socketError { + err = errnoErr(e1) + } + return +} diff --git a/vendor/github.com/Microsoft/go-winio/internal/stringbuffer/wstring.go b/vendor/github.com/Microsoft/go-winio/internal/stringbuffer/wstring.go new file mode 100644 index 0000000000..7ad5057024 --- /dev/null +++ b/vendor/github.com/Microsoft/go-winio/internal/stringbuffer/wstring.go @@ -0,0 +1,132 @@ +package stringbuffer + +import ( + "sync" + "unicode/utf16" +) + +// TODO: worth exporting and using in mkwinsyscall? + +// Uint16BufferSize is the buffer size in the pool, chosen somewhat arbitrarily to accommodate +// large path strings: +// MAX_PATH (260) + size of volume GUID prefix (49) + null terminator = 310. +const MinWStringCap = 310 + +// use *[]uint16 since []uint16 creates an extra allocation where the slice header +// is copied to heap and then referenced via pointer in the interface header that sync.Pool +// stores. +var pathPool = sync.Pool{ // if go1.18+ adds Pool[T], use that to store []uint16 directly + New: func() interface{} { + b := make([]uint16, MinWStringCap) + return &b + }, +} + +func newBuffer() []uint16 { return *(pathPool.Get().(*[]uint16)) } + +// freeBuffer copies the slice header data, and puts a pointer to that in the pool. +// This avoids taking a pointer to the slice header in WString, which can be set to nil. +func freeBuffer(b []uint16) { pathPool.Put(&b) } + +// WString is a wide string buffer ([]uint16) meant for storing UTF-16 encoded strings +// for interacting with Win32 APIs. +// Sizes are specified as uint32 and not int. +// +// It is not thread safe. +type WString struct { + // type-def allows casting to []uint16 directly, use struct to prevent that and allow adding fields in the future. + + // raw buffer + b []uint16 +} + +// NewWString returns a [WString] allocated from a shared pool with an +// initial capacity of at least [MinWStringCap]. +// Since the buffer may have been previously used, its contents are not guaranteed to be empty. +// +// The buffer should be freed via [WString.Free] +func NewWString() *WString { + return &WString{ + b: newBuffer(), + } +} + +func (b *WString) Free() { + if b.empty() { + return + } + freeBuffer(b.b) + b.b = nil +} + +// ResizeTo grows the buffer to at least c and returns the new capacity, freeing the +// previous buffer back into pool. +func (b *WString) ResizeTo(c uint32) uint32 { + // allready sufficient (or n is 0) + if c <= b.Cap() { + return b.Cap() + } + + if c <= MinWStringCap { + c = MinWStringCap + } + // allocate at-least double buffer size, as is done in [bytes.Buffer] and other places + if c <= 2*b.Cap() { + c = 2 * b.Cap() + } + + b2 := make([]uint16, c) + if !b.empty() { + copy(b2, b.b) + freeBuffer(b.b) + } + b.b = b2 + return c +} + +// Buffer returns the underlying []uint16 buffer. +func (b *WString) Buffer() []uint16 { + if b.empty() { + return nil + } + return b.b +} + +// Pointer returns a pointer to the first uint16 in the buffer. +// If the [WString.Free] has already been called, the pointer will be nil. +func (b *WString) Pointer() *uint16 { + if b.empty() { + return nil + } + return &b.b[0] +} + +// String returns the returns the UTF-8 encoding of the UTF-16 string in the buffer. +// +// It assumes that the data is null-terminated. +func (b *WString) String() string { + // Using [windows.UTF16ToString] would require importing "golang.org/x/sys/windows" + // and would make this code Windows-only, which makes no sense. + // So copy UTF16ToString code into here. + // If other windows-specific code is added, switch to [windows.UTF16ToString] + + s := b.b + for i, v := range s { + if v == 0 { + s = s[:i] + break + } + } + return string(utf16.Decode(s)) +} + +// Cap returns the underlying buffer capacity. +func (b *WString) Cap() uint32 { + if b.empty() { + return 0 + } + return b.cap() +} + +func (b *WString) cap() uint32 { return uint32(cap(b.b)) } +func (b *WString) empty() bool { return b == nil || b.cap() == 0 } diff --git a/vendor/github.com/Microsoft/go-winio/pipe.go b/vendor/github.com/Microsoft/go-winio/pipe.go new file mode 100644 index 0000000000..25cc811031 --- /dev/null +++ b/vendor/github.com/Microsoft/go-winio/pipe.go @@ -0,0 +1,525 @@ +//go:build windows +// +build windows + +package winio + +import ( + "context" + "errors" + "fmt" + "io" + "net" + "os" + "runtime" + "syscall" + "time" + "unsafe" + + "golang.org/x/sys/windows" + + "github.com/Microsoft/go-winio/internal/fs" +) + +//sys connectNamedPipe(pipe syscall.Handle, o *syscall.Overlapped) (err error) = ConnectNamedPipe +//sys createNamedPipe(name string, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *syscall.SecurityAttributes) (handle syscall.Handle, err error) [failretval==syscall.InvalidHandle] = CreateNamedPipeW +//sys getNamedPipeInfo(pipe syscall.Handle, flags *uint32, outSize *uint32, inSize *uint32, maxInstances *uint32) (err error) = GetNamedPipeInfo +//sys getNamedPipeHandleState(pipe syscall.Handle, state *uint32, curInstances *uint32, maxCollectionCount *uint32, collectDataTimeout *uint32, userName *uint16, maxUserNameSize uint32) (err error) = GetNamedPipeHandleStateW +//sys localAlloc(uFlags uint32, length uint32) (ptr uintptr) = LocalAlloc +//sys ntCreateNamedPipeFile(pipe *syscall.Handle, access uint32, oa *objectAttributes, iosb *ioStatusBlock, share uint32, disposition uint32, options uint32, typ uint32, readMode uint32, completionMode uint32, maxInstances uint32, inboundQuota uint32, outputQuota uint32, timeout *int64) (status ntStatus) = ntdll.NtCreateNamedPipeFile +//sys rtlNtStatusToDosError(status ntStatus) (winerr error) = ntdll.RtlNtStatusToDosErrorNoTeb +//sys rtlDosPathNameToNtPathName(name *uint16, ntName *unicodeString, filePart uintptr, reserved uintptr) (status ntStatus) = ntdll.RtlDosPathNameToNtPathName_U +//sys rtlDefaultNpAcl(dacl *uintptr) (status ntStatus) = ntdll.RtlDefaultNpAcl + +type ioStatusBlock struct { + Status, Information uintptr +} + +type objectAttributes struct { + Length uintptr + RootDirectory uintptr + ObjectName *unicodeString + Attributes uintptr + SecurityDescriptor *securityDescriptor + SecurityQoS uintptr +} + +type unicodeString struct { + Length uint16 + MaximumLength uint16 + Buffer uintptr +} + +type securityDescriptor struct { + Revision byte + Sbz1 byte + Control uint16 + Owner uintptr + Group uintptr + Sacl uintptr //revive:disable-line:var-naming SACL, not Sacl + Dacl uintptr //revive:disable-line:var-naming DACL, not Dacl +} + +type ntStatus int32 + +func (status ntStatus) Err() error { + if status >= 0 { + return nil + } + return rtlNtStatusToDosError(status) +} + +var ( + // ErrPipeListenerClosed is returned for pipe operations on listeners that have been closed. + ErrPipeListenerClosed = net.ErrClosed + + errPipeWriteClosed = errors.New("pipe has been closed for write") +) + +type win32Pipe struct { + *win32File + path string +} + +type win32MessageBytePipe struct { + win32Pipe + writeClosed bool + readEOF bool +} + +type pipeAddress string + +func (f *win32Pipe) LocalAddr() net.Addr { + return pipeAddress(f.path) +} + +func (f *win32Pipe) RemoteAddr() net.Addr { + return pipeAddress(f.path) +} + +func (f *win32Pipe) SetDeadline(t time.Time) error { + if err := f.SetReadDeadline(t); err != nil { + return err + } + return f.SetWriteDeadline(t) +} + +// CloseWrite closes the write side of a message pipe in byte mode. +func (f *win32MessageBytePipe) CloseWrite() error { + if f.writeClosed { + return errPipeWriteClosed + } + err := f.win32File.Flush() + if err != nil { + return err + } + _, err = f.win32File.Write(nil) + if err != nil { + return err + } + f.writeClosed = true + return nil +} + +// Write writes bytes to a message pipe in byte mode. Zero-byte writes are ignored, since +// they are used to implement CloseWrite(). +func (f *win32MessageBytePipe) Write(b []byte) (int, error) { + if f.writeClosed { + return 0, errPipeWriteClosed + } + if len(b) == 0 { + return 0, nil + } + return f.win32File.Write(b) +} + +// Read reads bytes from a message pipe in byte mode. A read of a zero-byte message on a message +// mode pipe will return io.EOF, as will all subsequent reads. +func (f *win32MessageBytePipe) Read(b []byte) (int, error) { + if f.readEOF { + return 0, io.EOF + } + n, err := f.win32File.Read(b) + if err == io.EOF { //nolint:errorlint + // If this was the result of a zero-byte read, then + // it is possible that the read was due to a zero-size + // message. Since we are simulating CloseWrite with a + // zero-byte message, ensure that all future Read() calls + // also return EOF. + f.readEOF = true + } else if err == syscall.ERROR_MORE_DATA { //nolint:errorlint // err is Errno + // ERROR_MORE_DATA indicates that the pipe's read mode is message mode + // and the message still has more bytes. Treat this as a success, since + // this package presents all named pipes as byte streams. + err = nil + } + return n, err +} + +func (pipeAddress) Network() string { + return "pipe" +} + +func (s pipeAddress) String() string { + return string(s) +} + +// tryDialPipe attempts to dial the pipe at `path` until `ctx` cancellation or timeout. +func tryDialPipe(ctx context.Context, path *string, access fs.AccessMask) (syscall.Handle, error) { + for { + select { + case <-ctx.Done(): + return syscall.Handle(0), ctx.Err() + default: + wh, err := fs.CreateFile(*path, + access, + 0, // mode + nil, // security attributes + fs.OPEN_EXISTING, + fs.FILE_FLAG_OVERLAPPED|fs.SECURITY_SQOS_PRESENT|fs.SECURITY_ANONYMOUS, + 0, // template file handle + ) + h := syscall.Handle(wh) + if err == nil { + return h, nil + } + if err != windows.ERROR_PIPE_BUSY { //nolint:errorlint // err is Errno + return h, &os.PathError{Err: err, Op: "open", Path: *path} + } + // Wait 10 msec and try again. This is a rather simplistic + // view, as we always try each 10 milliseconds. + time.Sleep(10 * time.Millisecond) + } + } +} + +// DialPipe connects to a named pipe by path, timing out if the connection +// takes longer than the specified duration. If timeout is nil, then we use +// a default timeout of 2 seconds. (We do not use WaitNamedPipe.) +func DialPipe(path string, timeout *time.Duration) (net.Conn, error) { + var absTimeout time.Time + if timeout != nil { + absTimeout = time.Now().Add(*timeout) + } else { + absTimeout = time.Now().Add(2 * time.Second) + } + ctx, cancel := context.WithDeadline(context.Background(), absTimeout) + defer cancel() + conn, err := DialPipeContext(ctx, path) + if errors.Is(err, context.DeadlineExceeded) { + return nil, ErrTimeout + } + return conn, err +} + +// DialPipeContext attempts to connect to a named pipe by `path` until `ctx` +// cancellation or timeout. +func DialPipeContext(ctx context.Context, path string) (net.Conn, error) { + return DialPipeAccess(ctx, path, syscall.GENERIC_READ|syscall.GENERIC_WRITE) +} + +// DialPipeAccess attempts to connect to a named pipe by `path` with `access` until `ctx` +// cancellation or timeout. +func DialPipeAccess(ctx context.Context, path string, access uint32) (net.Conn, error) { + var err error + var h syscall.Handle + h, err = tryDialPipe(ctx, &path, fs.AccessMask(access)) + if err != nil { + return nil, err + } + + var flags uint32 + err = getNamedPipeInfo(h, &flags, nil, nil, nil) + if err != nil { + return nil, err + } + + f, err := makeWin32File(h) + if err != nil { + syscall.Close(h) + return nil, err + } + + // If the pipe is in message mode, return a message byte pipe, which + // supports CloseWrite(). + if flags&windows.PIPE_TYPE_MESSAGE != 0 { + return &win32MessageBytePipe{ + win32Pipe: win32Pipe{win32File: f, path: path}, + }, nil + } + return &win32Pipe{win32File: f, path: path}, nil +} + +type acceptResponse struct { + f *win32File + err error +} + +type win32PipeListener struct { + firstHandle syscall.Handle + path string + config PipeConfig + acceptCh chan (chan acceptResponse) + closeCh chan int + doneCh chan int +} + +func makeServerPipeHandle(path string, sd []byte, c *PipeConfig, first bool) (syscall.Handle, error) { + path16, err := syscall.UTF16FromString(path) + if err != nil { + return 0, &os.PathError{Op: "open", Path: path, Err: err} + } + + var oa objectAttributes + oa.Length = unsafe.Sizeof(oa) + + var ntPath unicodeString + if err := rtlDosPathNameToNtPathName(&path16[0], + &ntPath, + 0, + 0, + ).Err(); err != nil { + return 0, &os.PathError{Op: "open", Path: path, Err: err} + } + defer localFree(ntPath.Buffer) + oa.ObjectName = &ntPath + oa.Attributes = windows.OBJ_CASE_INSENSITIVE + + // The security descriptor is only needed for the first pipe. + if first { + if sd != nil { + l := uint32(len(sd)) + sdb := localAlloc(0, l) + defer localFree(sdb) + copy((*[0xffff]byte)(unsafe.Pointer(sdb))[:], sd) + oa.SecurityDescriptor = (*securityDescriptor)(unsafe.Pointer(sdb)) + } else { + // Construct the default named pipe security descriptor. + var dacl uintptr + if err := rtlDefaultNpAcl(&dacl).Err(); err != nil { + return 0, fmt.Errorf("getting default named pipe ACL: %w", err) + } + defer localFree(dacl) + + sdb := &securityDescriptor{ + Revision: 1, + Control: windows.SE_DACL_PRESENT, + Dacl: dacl, + } + oa.SecurityDescriptor = sdb + } + } + + typ := uint32(windows.FILE_PIPE_REJECT_REMOTE_CLIENTS) + if c.MessageMode { + typ |= windows.FILE_PIPE_MESSAGE_TYPE + } + + disposition := uint32(windows.FILE_OPEN) + access := uint32(syscall.GENERIC_READ | syscall.GENERIC_WRITE | syscall.SYNCHRONIZE) + if first { + disposition = windows.FILE_CREATE + // By not asking for read or write access, the named pipe file system + // will put this pipe into an initially disconnected state, blocking + // client connections until the next call with first == false. + access = syscall.SYNCHRONIZE + } + + timeout := int64(-50 * 10000) // 50ms + + var ( + h syscall.Handle + iosb ioStatusBlock + ) + err = ntCreateNamedPipeFile(&h, + access, + &oa, + &iosb, + syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE, + disposition, + 0, + typ, + 0, + 0, + 0xffffffff, + uint32(c.InputBufferSize), + uint32(c.OutputBufferSize), + &timeout).Err() + if err != nil { + return 0, &os.PathError{Op: "open", Path: path, Err: err} + } + + runtime.KeepAlive(ntPath) + return h, nil +} + +func (l *win32PipeListener) makeServerPipe() (*win32File, error) { + h, err := makeServerPipeHandle(l.path, nil, &l.config, false) + if err != nil { + return nil, err + } + f, err := makeWin32File(h) + if err != nil { + syscall.Close(h) + return nil, err + } + return f, nil +} + +func (l *win32PipeListener) makeConnectedServerPipe() (*win32File, error) { + p, err := l.makeServerPipe() + if err != nil { + return nil, err + } + + // Wait for the client to connect. + ch := make(chan error) + go func(p *win32File) { + ch <- connectPipe(p) + }(p) + + select { + case err = <-ch: + if err != nil { + p.Close() + p = nil + } + case <-l.closeCh: + // Abort the connect request by closing the handle. + p.Close() + p = nil + err = <-ch + if err == nil || err == ErrFileClosed { //nolint:errorlint // err is Errno + err = ErrPipeListenerClosed + } + } + return p, err +} + +func (l *win32PipeListener) listenerRoutine() { + closed := false + for !closed { + select { + case <-l.closeCh: + closed = true + case responseCh := <-l.acceptCh: + var ( + p *win32File + err error + ) + for { + p, err = l.makeConnectedServerPipe() + // If the connection was immediately closed by the client, try + // again. + if err != windows.ERROR_NO_DATA { //nolint:errorlint // err is Errno + break + } + } + responseCh <- acceptResponse{p, err} + closed = err == ErrPipeListenerClosed //nolint:errorlint // err is Errno + } + } + syscall.Close(l.firstHandle) + l.firstHandle = 0 + // Notify Close() and Accept() callers that the handle has been closed. + close(l.doneCh) +} + +// PipeConfig contain configuration for the pipe listener. +type PipeConfig struct { + // SecurityDescriptor contains a Windows security descriptor in SDDL format. + SecurityDescriptor string + + // MessageMode determines whether the pipe is in byte or message mode. In either + // case the pipe is read in byte mode by default. The only practical difference in + // this implementation is that CloseWrite() is only supported for message mode pipes; + // CloseWrite() is implemented as a zero-byte write, but zero-byte writes are only + // transferred to the reader (and returned as io.EOF in this implementation) + // when the pipe is in message mode. + MessageMode bool + + // InputBufferSize specifies the size of the input buffer, in bytes. + InputBufferSize int32 + + // OutputBufferSize specifies the size of the output buffer, in bytes. + OutputBufferSize int32 +} + +// ListenPipe creates a listener on a Windows named pipe path, e.g. \\.\pipe\mypipe. +// The pipe must not already exist. +func ListenPipe(path string, c *PipeConfig) (net.Listener, error) { + var ( + sd []byte + err error + ) + if c == nil { + c = &PipeConfig{} + } + if c.SecurityDescriptor != "" { + sd, err = SddlToSecurityDescriptor(c.SecurityDescriptor) + if err != nil { + return nil, err + } + } + h, err := makeServerPipeHandle(path, sd, c, true) + if err != nil { + return nil, err + } + l := &win32PipeListener{ + firstHandle: h, + path: path, + config: *c, + acceptCh: make(chan (chan acceptResponse)), + closeCh: make(chan int), + doneCh: make(chan int), + } + go l.listenerRoutine() + return l, nil +} + +func connectPipe(p *win32File) error { + c, err := p.prepareIO() + if err != nil { + return err + } + defer p.wg.Done() + + err = connectNamedPipe(p.handle, &c.o) + _, err = p.asyncIO(c, nil, 0, err) + if err != nil && err != windows.ERROR_PIPE_CONNECTED { //nolint:errorlint // err is Errno + return err + } + return nil +} + +func (l *win32PipeListener) Accept() (net.Conn, error) { + ch := make(chan acceptResponse) + select { + case l.acceptCh <- ch: + response := <-ch + err := response.err + if err != nil { + return nil, err + } + if l.config.MessageMode { + return &win32MessageBytePipe{ + win32Pipe: win32Pipe{win32File: response.f, path: l.path}, + }, nil + } + return &win32Pipe{win32File: response.f, path: l.path}, nil + case <-l.doneCh: + return nil, ErrPipeListenerClosed + } +} + +func (l *win32PipeListener) Close() error { + select { + case l.closeCh <- 1: + <-l.doneCh + case <-l.doneCh: + } + return nil +} + +func (l *win32PipeListener) Addr() net.Addr { + return pipeAddress(l.path) +} diff --git a/vendor/github.com/Microsoft/go-winio/pkg/guid/guid.go b/vendor/github.com/Microsoft/go-winio/pkg/guid/guid.go new file mode 100644 index 0000000000..48ce4e9243 --- /dev/null +++ b/vendor/github.com/Microsoft/go-winio/pkg/guid/guid.go @@ -0,0 +1,232 @@ +// Package guid provides a GUID type. The backing structure for a GUID is +// identical to that used by the golang.org/x/sys/windows GUID type. +// There are two main binary encodings used for a GUID, the big-endian encoding, +// and the Windows (mixed-endian) encoding. See here for details: +// https://en.wikipedia.org/wiki/Universally_unique_identifier#Encoding +package guid + +import ( + "crypto/rand" + "crypto/sha1" //nolint:gosec // not used for secure application + "encoding" + "encoding/binary" + "fmt" + "strconv" +) + +//go:generate go run golang.org/x/tools/cmd/stringer -type=Variant -trimprefix=Variant -linecomment + +// Variant specifies which GUID variant (or "type") of the GUID. It determines +// how the entirety of the rest of the GUID is interpreted. +type Variant uint8 + +// The variants specified by RFC 4122 section 4.1.1. +const ( + // VariantUnknown specifies a GUID variant which does not conform to one of + // the variant encodings specified in RFC 4122. + VariantUnknown Variant = iota + VariantNCS + VariantRFC4122 // RFC 4122 + VariantMicrosoft + VariantFuture +) + +// Version specifies how the bits in the GUID were generated. For instance, a +// version 4 GUID is randomly generated, and a version 5 is generated from the +// hash of an input string. +type Version uint8 + +func (v Version) String() string { + return strconv.FormatUint(uint64(v), 10) +} + +var _ = (encoding.TextMarshaler)(GUID{}) +var _ = (encoding.TextUnmarshaler)(&GUID{}) + +// NewV4 returns a new version 4 (pseudorandom) GUID, as defined by RFC 4122. +func NewV4() (GUID, error) { + var b [16]byte + if _, err := rand.Read(b[:]); err != nil { + return GUID{}, err + } + + g := FromArray(b) + g.setVersion(4) // Version 4 means randomly generated. + g.setVariant(VariantRFC4122) + + return g, nil +} + +// NewV5 returns a new version 5 (generated from a string via SHA-1 hashing) +// GUID, as defined by RFC 4122. The RFC is unclear on the encoding of the name, +// and the sample code treats it as a series of bytes, so we do the same here. +// +// Some implementations, such as those found on Windows, treat the name as a +// big-endian UTF16 stream of bytes. If that is desired, the string can be +// encoded as such before being passed to this function. +func NewV5(namespace GUID, name []byte) (GUID, error) { + b := sha1.New() //nolint:gosec // not used for secure application + namespaceBytes := namespace.ToArray() + b.Write(namespaceBytes[:]) + b.Write(name) + + a := [16]byte{} + copy(a[:], b.Sum(nil)) + + g := FromArray(a) + g.setVersion(5) // Version 5 means generated from a string. + g.setVariant(VariantRFC4122) + + return g, nil +} + +func fromArray(b [16]byte, order binary.ByteOrder) GUID { + var g GUID + g.Data1 = order.Uint32(b[0:4]) + g.Data2 = order.Uint16(b[4:6]) + g.Data3 = order.Uint16(b[6:8]) + copy(g.Data4[:], b[8:16]) + return g +} + +func (g GUID) toArray(order binary.ByteOrder) [16]byte { + b := [16]byte{} + order.PutUint32(b[0:4], g.Data1) + order.PutUint16(b[4:6], g.Data2) + order.PutUint16(b[6:8], g.Data3) + copy(b[8:16], g.Data4[:]) + return b +} + +// FromArray constructs a GUID from a big-endian encoding array of 16 bytes. +func FromArray(b [16]byte) GUID { + return fromArray(b, binary.BigEndian) +} + +// ToArray returns an array of 16 bytes representing the GUID in big-endian +// encoding. +func (g GUID) ToArray() [16]byte { + return g.toArray(binary.BigEndian) +} + +// FromWindowsArray constructs a GUID from a Windows encoding array of bytes. +func FromWindowsArray(b [16]byte) GUID { + return fromArray(b, binary.LittleEndian) +} + +// ToWindowsArray returns an array of 16 bytes representing the GUID in Windows +// encoding. +func (g GUID) ToWindowsArray() [16]byte { + return g.toArray(binary.LittleEndian) +} + +func (g GUID) String() string { + return fmt.Sprintf( + "%08x-%04x-%04x-%04x-%012x", + g.Data1, + g.Data2, + g.Data3, + g.Data4[:2], + g.Data4[2:]) +} + +// FromString parses a string containing a GUID and returns the GUID. The only +// format currently supported is the `xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx` +// format. +func FromString(s string) (GUID, error) { + if len(s) != 36 { + return GUID{}, fmt.Errorf("invalid GUID %q", s) + } + if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' { + return GUID{}, fmt.Errorf("invalid GUID %q", s) + } + + var g GUID + + data1, err := strconv.ParseUint(s[0:8], 16, 32) + if err != nil { + return GUID{}, fmt.Errorf("invalid GUID %q", s) + } + g.Data1 = uint32(data1) + + data2, err := strconv.ParseUint(s[9:13], 16, 16) + if err != nil { + return GUID{}, fmt.Errorf("invalid GUID %q", s) + } + g.Data2 = uint16(data2) + + data3, err := strconv.ParseUint(s[14:18], 16, 16) + if err != nil { + return GUID{}, fmt.Errorf("invalid GUID %q", s) + } + g.Data3 = uint16(data3) + + for i, x := range []int{19, 21, 24, 26, 28, 30, 32, 34} { + v, err := strconv.ParseUint(s[x:x+2], 16, 8) + if err != nil { + return GUID{}, fmt.Errorf("invalid GUID %q", s) + } + g.Data4[i] = uint8(v) + } + + return g, nil +} + +func (g *GUID) setVariant(v Variant) { + d := g.Data4[0] + switch v { + case VariantNCS: + d = (d & 0x7f) + case VariantRFC4122: + d = (d & 0x3f) | 0x80 + case VariantMicrosoft: + d = (d & 0x1f) | 0xc0 + case VariantFuture: + d = (d & 0x0f) | 0xe0 + case VariantUnknown: + fallthrough + default: + panic(fmt.Sprintf("invalid variant: %d", v)) + } + g.Data4[0] = d +} + +// Variant returns the GUID variant, as defined in RFC 4122. +func (g GUID) Variant() Variant { + b := g.Data4[0] + if b&0x80 == 0 { + return VariantNCS + } else if b&0xc0 == 0x80 { + return VariantRFC4122 + } else if b&0xe0 == 0xc0 { + return VariantMicrosoft + } else if b&0xe0 == 0xe0 { + return VariantFuture + } + return VariantUnknown +} + +func (g *GUID) setVersion(v Version) { + g.Data3 = (g.Data3 & 0x0fff) | (uint16(v) << 12) +} + +// Version returns the GUID version, as defined in RFC 4122. +func (g GUID) Version() Version { + return Version((g.Data3 & 0xF000) >> 12) +} + +// MarshalText returns the textual representation of the GUID. +func (g GUID) MarshalText() ([]byte, error) { + return []byte(g.String()), nil +} + +// UnmarshalText takes the textual representation of a GUID, and unmarhals it +// into this GUID. +func (g *GUID) UnmarshalText(text []byte) error { + g2, err := FromString(string(text)) + if err != nil { + return err + } + *g = g2 + return nil +} diff --git a/vendor/github.com/Microsoft/go-winio/pkg/guid/guid_nonwindows.go b/vendor/github.com/Microsoft/go-winio/pkg/guid/guid_nonwindows.go new file mode 100644 index 0000000000..805bd35484 --- /dev/null +++ b/vendor/github.com/Microsoft/go-winio/pkg/guid/guid_nonwindows.go @@ -0,0 +1,16 @@ +//go:build !windows +// +build !windows + +package guid + +// GUID represents a GUID/UUID. It has the same structure as +// golang.org/x/sys/windows.GUID so that it can be used with functions expecting +// that type. It is defined as its own type as that is only available to builds +// targeted at `windows`. The representation matches that used by native Windows +// code. +type GUID struct { + Data1 uint32 + Data2 uint16 + Data3 uint16 + Data4 [8]byte +} diff --git a/vendor/github.com/Microsoft/go-winio/pkg/guid/guid_windows.go b/vendor/github.com/Microsoft/go-winio/pkg/guid/guid_windows.go new file mode 100644 index 0000000000..27e45ee5cc --- /dev/null +++ b/vendor/github.com/Microsoft/go-winio/pkg/guid/guid_windows.go @@ -0,0 +1,13 @@ +//go:build windows +// +build windows + +package guid + +import "golang.org/x/sys/windows" + +// GUID represents a GUID/UUID. It has the same structure as +// golang.org/x/sys/windows.GUID so that it can be used with functions expecting +// that type. It is defined as its own type so that stringification and +// marshaling can be supported. The representation matches that used by native +// Windows code. +type GUID windows.GUID diff --git a/vendor/github.com/Microsoft/go-winio/pkg/guid/variant_string.go b/vendor/github.com/Microsoft/go-winio/pkg/guid/variant_string.go new file mode 100644 index 0000000000..4076d3132f --- /dev/null +++ b/vendor/github.com/Microsoft/go-winio/pkg/guid/variant_string.go @@ -0,0 +1,27 @@ +// Code generated by "stringer -type=Variant -trimprefix=Variant -linecomment"; DO NOT EDIT. + +package guid + +import "strconv" + +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[VariantUnknown-0] + _ = x[VariantNCS-1] + _ = x[VariantRFC4122-2] + _ = x[VariantMicrosoft-3] + _ = x[VariantFuture-4] +} + +const _Variant_name = "UnknownNCSRFC 4122MicrosoftFuture" + +var _Variant_index = [...]uint8{0, 7, 10, 18, 27, 33} + +func (i Variant) String() string { + if i >= Variant(len(_Variant_index)-1) { + return "Variant(" + strconv.FormatInt(int64(i), 10) + ")" + } + return _Variant_name[_Variant_index[i]:_Variant_index[i+1]] +} diff --git a/vendor/github.com/Microsoft/go-winio/privilege.go b/vendor/github.com/Microsoft/go-winio/privilege.go new file mode 100644 index 0000000000..0ff9dac906 --- /dev/null +++ b/vendor/github.com/Microsoft/go-winio/privilege.go @@ -0,0 +1,197 @@ +//go:build windows +// +build windows + +package winio + +import ( + "bytes" + "encoding/binary" + "fmt" + "runtime" + "sync" + "syscall" + "unicode/utf16" + + "golang.org/x/sys/windows" +) + +//sys adjustTokenPrivileges(token windows.Token, releaseAll bool, input *byte, outputSize uint32, output *byte, requiredSize *uint32) (success bool, err error) [true] = advapi32.AdjustTokenPrivileges +//sys impersonateSelf(level uint32) (err error) = advapi32.ImpersonateSelf +//sys revertToSelf() (err error) = advapi32.RevertToSelf +//sys openThreadToken(thread syscall.Handle, accessMask uint32, openAsSelf bool, token *windows.Token) (err error) = advapi32.OpenThreadToken +//sys getCurrentThread() (h syscall.Handle) = GetCurrentThread +//sys lookupPrivilegeValue(systemName string, name string, luid *uint64) (err error) = advapi32.LookupPrivilegeValueW +//sys lookupPrivilegeName(systemName string, luid *uint64, buffer *uint16, size *uint32) (err error) = advapi32.LookupPrivilegeNameW +//sys lookupPrivilegeDisplayName(systemName string, name *uint16, buffer *uint16, size *uint32, languageId *uint32) (err error) = advapi32.LookupPrivilegeDisplayNameW + +const ( + //revive:disable-next-line:var-naming ALL_CAPS + SE_PRIVILEGE_ENABLED = windows.SE_PRIVILEGE_ENABLED + + //revive:disable-next-line:var-naming ALL_CAPS + ERROR_NOT_ALL_ASSIGNED syscall.Errno = windows.ERROR_NOT_ALL_ASSIGNED + + SeBackupPrivilege = "SeBackupPrivilege" + SeRestorePrivilege = "SeRestorePrivilege" + SeSecurityPrivilege = "SeSecurityPrivilege" +) + +var ( + privNames = make(map[string]uint64) + privNameMutex sync.Mutex +) + +// PrivilegeError represents an error enabling privileges. +type PrivilegeError struct { + privileges []uint64 +} + +func (e *PrivilegeError) Error() string { + s := "Could not enable privilege " + if len(e.privileges) > 1 { + s = "Could not enable privileges " + } + for i, p := range e.privileges { + if i != 0 { + s += ", " + } + s += `"` + s += getPrivilegeName(p) + s += `"` + } + return s +} + +// RunWithPrivilege enables a single privilege for a function call. +func RunWithPrivilege(name string, fn func() error) error { + return RunWithPrivileges([]string{name}, fn) +} + +// RunWithPrivileges enables privileges for a function call. +func RunWithPrivileges(names []string, fn func() error) error { + privileges, err := mapPrivileges(names) + if err != nil { + return err + } + runtime.LockOSThread() + defer runtime.UnlockOSThread() + token, err := newThreadToken() + if err != nil { + return err + } + defer releaseThreadToken(token) + err = adjustPrivileges(token, privileges, SE_PRIVILEGE_ENABLED) + if err != nil { + return err + } + return fn() +} + +func mapPrivileges(names []string) ([]uint64, error) { + privileges := make([]uint64, 0, len(names)) + privNameMutex.Lock() + defer privNameMutex.Unlock() + for _, name := range names { + p, ok := privNames[name] + if !ok { + err := lookupPrivilegeValue("", name, &p) + if err != nil { + return nil, err + } + privNames[name] = p + } + privileges = append(privileges, p) + } + return privileges, nil +} + +// EnableProcessPrivileges enables privileges globally for the process. +func EnableProcessPrivileges(names []string) error { + return enableDisableProcessPrivilege(names, SE_PRIVILEGE_ENABLED) +} + +// DisableProcessPrivileges disables privileges globally for the process. +func DisableProcessPrivileges(names []string) error { + return enableDisableProcessPrivilege(names, 0) +} + +func enableDisableProcessPrivilege(names []string, action uint32) error { + privileges, err := mapPrivileges(names) + if err != nil { + return err + } + + p := windows.CurrentProcess() + var token windows.Token + err = windows.OpenProcessToken(p, windows.TOKEN_ADJUST_PRIVILEGES|windows.TOKEN_QUERY, &token) + if err != nil { + return err + } + + defer token.Close() + return adjustPrivileges(token, privileges, action) +} + +func adjustPrivileges(token windows.Token, privileges []uint64, action uint32) error { + var b bytes.Buffer + _ = binary.Write(&b, binary.LittleEndian, uint32(len(privileges))) + for _, p := range privileges { + _ = binary.Write(&b, binary.LittleEndian, p) + _ = binary.Write(&b, binary.LittleEndian, action) + } + prevState := make([]byte, b.Len()) + reqSize := uint32(0) + success, err := adjustTokenPrivileges(token, false, &b.Bytes()[0], uint32(len(prevState)), &prevState[0], &reqSize) + if !success { + return err + } + if err == ERROR_NOT_ALL_ASSIGNED { //nolint:errorlint // err is Errno + return &PrivilegeError{privileges} + } + return nil +} + +func getPrivilegeName(luid uint64) string { + var nameBuffer [256]uint16 + bufSize := uint32(len(nameBuffer)) + err := lookupPrivilegeName("", &luid, &nameBuffer[0], &bufSize) + if err != nil { + return fmt.Sprintf("", luid) + } + + var displayNameBuffer [256]uint16 + displayBufSize := uint32(len(displayNameBuffer)) + var langID uint32 + err = lookupPrivilegeDisplayName("", &nameBuffer[0], &displayNameBuffer[0], &displayBufSize, &langID) + if err != nil { + return fmt.Sprintf("", string(utf16.Decode(nameBuffer[:bufSize]))) + } + + return string(utf16.Decode(displayNameBuffer[:displayBufSize])) +} + +func newThreadToken() (windows.Token, error) { + err := impersonateSelf(windows.SecurityImpersonation) + if err != nil { + return 0, err + } + + var token windows.Token + err = openThreadToken(getCurrentThread(), syscall.TOKEN_ADJUST_PRIVILEGES|syscall.TOKEN_QUERY, false, &token) + if err != nil { + rerr := revertToSelf() + if rerr != nil { + panic(rerr) + } + return 0, err + } + return token, nil +} + +func releaseThreadToken(h windows.Token) { + err := revertToSelf() + if err != nil { + panic(err) + } + h.Close() +} diff --git a/vendor/github.com/Microsoft/go-winio/reparse.go b/vendor/github.com/Microsoft/go-winio/reparse.go new file mode 100644 index 0000000000..67d1a104a6 --- /dev/null +++ b/vendor/github.com/Microsoft/go-winio/reparse.go @@ -0,0 +1,131 @@ +//go:build windows +// +build windows + +package winio + +import ( + "bytes" + "encoding/binary" + "fmt" + "strings" + "unicode/utf16" + "unsafe" +) + +const ( + reparseTagMountPoint = 0xA0000003 + reparseTagSymlink = 0xA000000C +) + +type reparseDataBuffer struct { + ReparseTag uint32 + ReparseDataLength uint16 + Reserved uint16 + SubstituteNameOffset uint16 + SubstituteNameLength uint16 + PrintNameOffset uint16 + PrintNameLength uint16 +} + +// ReparsePoint describes a Win32 symlink or mount point. +type ReparsePoint struct { + Target string + IsMountPoint bool +} + +// UnsupportedReparsePointError is returned when trying to decode a non-symlink or +// mount point reparse point. +type UnsupportedReparsePointError struct { + Tag uint32 +} + +func (e *UnsupportedReparsePointError) Error() string { + return fmt.Sprintf("unsupported reparse point %x", e.Tag) +} + +// DecodeReparsePoint decodes a Win32 REPARSE_DATA_BUFFER structure containing either a symlink +// or a mount point. +func DecodeReparsePoint(b []byte) (*ReparsePoint, error) { + tag := binary.LittleEndian.Uint32(b[0:4]) + return DecodeReparsePointData(tag, b[8:]) +} + +func DecodeReparsePointData(tag uint32, b []byte) (*ReparsePoint, error) { + isMountPoint := false + switch tag { + case reparseTagMountPoint: + isMountPoint = true + case reparseTagSymlink: + default: + return nil, &UnsupportedReparsePointError{tag} + } + nameOffset := 8 + binary.LittleEndian.Uint16(b[4:6]) + if !isMountPoint { + nameOffset += 4 + } + nameLength := binary.LittleEndian.Uint16(b[6:8]) + name := make([]uint16, nameLength/2) + err := binary.Read(bytes.NewReader(b[nameOffset:nameOffset+nameLength]), binary.LittleEndian, &name) + if err != nil { + return nil, err + } + return &ReparsePoint{string(utf16.Decode(name)), isMountPoint}, nil +} + +func isDriveLetter(c byte) bool { + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') +} + +// EncodeReparsePoint encodes a Win32 REPARSE_DATA_BUFFER structure describing a symlink or +// mount point. +func EncodeReparsePoint(rp *ReparsePoint) []byte { + // Generate an NT path and determine if this is a relative path. + var ntTarget string + relative := false + if strings.HasPrefix(rp.Target, `\\?\`) { + ntTarget = `\??\` + rp.Target[4:] + } else if strings.HasPrefix(rp.Target, `\\`) { + ntTarget = `\??\UNC\` + rp.Target[2:] + } else if len(rp.Target) >= 2 && isDriveLetter(rp.Target[0]) && rp.Target[1] == ':' { + ntTarget = `\??\` + rp.Target + } else { + ntTarget = rp.Target + relative = true + } + + // The paths must be NUL-terminated even though they are counted strings. + target16 := utf16.Encode([]rune(rp.Target + "\x00")) + ntTarget16 := utf16.Encode([]rune(ntTarget + "\x00")) + + size := int(unsafe.Sizeof(reparseDataBuffer{})) - 8 + size += len(ntTarget16)*2 + len(target16)*2 + + tag := uint32(reparseTagMountPoint) + if !rp.IsMountPoint { + tag = reparseTagSymlink + size += 4 // Add room for symlink flags + } + + data := reparseDataBuffer{ + ReparseTag: tag, + ReparseDataLength: uint16(size), + SubstituteNameOffset: 0, + SubstituteNameLength: uint16((len(ntTarget16) - 1) * 2), + PrintNameOffset: uint16(len(ntTarget16) * 2), + PrintNameLength: uint16((len(target16) - 1) * 2), + } + + var b bytes.Buffer + _ = binary.Write(&b, binary.LittleEndian, &data) + if !rp.IsMountPoint { + flags := uint32(0) + if relative { + flags |= 1 + } + _ = binary.Write(&b, binary.LittleEndian, flags) + } + + _ = binary.Write(&b, binary.LittleEndian, ntTarget16) + _ = binary.Write(&b, binary.LittleEndian, target16) + return b.Bytes() +} diff --git a/vendor/github.com/Microsoft/go-winio/sd.go b/vendor/github.com/Microsoft/go-winio/sd.go new file mode 100644 index 0000000000..5550ef6b61 --- /dev/null +++ b/vendor/github.com/Microsoft/go-winio/sd.go @@ -0,0 +1,144 @@ +//go:build windows +// +build windows + +package winio + +import ( + "errors" + "syscall" + "unsafe" + + "golang.org/x/sys/windows" +) + +//sys lookupAccountName(systemName *uint16, accountName string, sid *byte, sidSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) = advapi32.LookupAccountNameW +//sys lookupAccountSid(systemName *uint16, sid *byte, name *uint16, nameSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) = advapi32.LookupAccountSidW +//sys convertSidToStringSid(sid *byte, str **uint16) (err error) = advapi32.ConvertSidToStringSidW +//sys convertStringSidToSid(str *uint16, sid **byte) (err error) = advapi32.ConvertStringSidToSidW +//sys convertStringSecurityDescriptorToSecurityDescriptor(str string, revision uint32, sd *uintptr, size *uint32) (err error) = advapi32.ConvertStringSecurityDescriptorToSecurityDescriptorW +//sys convertSecurityDescriptorToStringSecurityDescriptor(sd *byte, revision uint32, secInfo uint32, sddl **uint16, sddlSize *uint32) (err error) = advapi32.ConvertSecurityDescriptorToStringSecurityDescriptorW +//sys localFree(mem uintptr) = LocalFree +//sys getSecurityDescriptorLength(sd uintptr) (len uint32) = advapi32.GetSecurityDescriptorLength + +type AccountLookupError struct { + Name string + Err error +} + +func (e *AccountLookupError) Error() string { + if e.Name == "" { + return "lookup account: empty account name specified" + } + var s string + switch { + case errors.Is(e.Err, windows.ERROR_INVALID_SID): + s = "the security ID structure is invalid" + case errors.Is(e.Err, windows.ERROR_NONE_MAPPED): + s = "not found" + default: + s = e.Err.Error() + } + return "lookup account " + e.Name + ": " + s +} + +func (e *AccountLookupError) Unwrap() error { return e.Err } + +type SddlConversionError struct { + Sddl string + Err error +} + +func (e *SddlConversionError) Error() string { + return "convert " + e.Sddl + ": " + e.Err.Error() +} + +func (e *SddlConversionError) Unwrap() error { return e.Err } + +// LookupSidByName looks up the SID of an account by name +// +//revive:disable-next-line:var-naming SID, not Sid +func LookupSidByName(name string) (sid string, err error) { + if name == "" { + return "", &AccountLookupError{name, windows.ERROR_NONE_MAPPED} + } + + var sidSize, sidNameUse, refDomainSize uint32 + err = lookupAccountName(nil, name, nil, &sidSize, nil, &refDomainSize, &sidNameUse) + if err != nil && err != syscall.ERROR_INSUFFICIENT_BUFFER { //nolint:errorlint // err is Errno + return "", &AccountLookupError{name, err} + } + sidBuffer := make([]byte, sidSize) + refDomainBuffer := make([]uint16, refDomainSize) + err = lookupAccountName(nil, name, &sidBuffer[0], &sidSize, &refDomainBuffer[0], &refDomainSize, &sidNameUse) + if err != nil { + return "", &AccountLookupError{name, err} + } + var strBuffer *uint16 + err = convertSidToStringSid(&sidBuffer[0], &strBuffer) + if err != nil { + return "", &AccountLookupError{name, err} + } + sid = syscall.UTF16ToString((*[0xffff]uint16)(unsafe.Pointer(strBuffer))[:]) + localFree(uintptr(unsafe.Pointer(strBuffer))) + return sid, nil +} + +// LookupNameBySid looks up the name of an account by SID +// +//revive:disable-next-line:var-naming SID, not Sid +func LookupNameBySid(sid string) (name string, err error) { + if sid == "" { + return "", &AccountLookupError{sid, windows.ERROR_NONE_MAPPED} + } + + sidBuffer, err := windows.UTF16PtrFromString(sid) + if err != nil { + return "", &AccountLookupError{sid, err} + } + + var sidPtr *byte + if err = convertStringSidToSid(sidBuffer, &sidPtr); err != nil { + return "", &AccountLookupError{sid, err} + } + defer localFree(uintptr(unsafe.Pointer(sidPtr))) + + var nameSize, refDomainSize, sidNameUse uint32 + err = lookupAccountSid(nil, sidPtr, nil, &nameSize, nil, &refDomainSize, &sidNameUse) + if err != nil && err != windows.ERROR_INSUFFICIENT_BUFFER { //nolint:errorlint // err is Errno + return "", &AccountLookupError{sid, err} + } + + nameBuffer := make([]uint16, nameSize) + refDomainBuffer := make([]uint16, refDomainSize) + err = lookupAccountSid(nil, sidPtr, &nameBuffer[0], &nameSize, &refDomainBuffer[0], &refDomainSize, &sidNameUse) + if err != nil { + return "", &AccountLookupError{sid, err} + } + + name = windows.UTF16ToString(nameBuffer) + return name, nil +} + +func SddlToSecurityDescriptor(sddl string) ([]byte, error) { + var sdBuffer uintptr + err := convertStringSecurityDescriptorToSecurityDescriptor(sddl, 1, &sdBuffer, nil) + if err != nil { + return nil, &SddlConversionError{sddl, err} + } + defer localFree(sdBuffer) + sd := make([]byte, getSecurityDescriptorLength(sdBuffer)) + copy(sd, (*[0xffff]byte)(unsafe.Pointer(sdBuffer))[:len(sd)]) + return sd, nil +} + +func SecurityDescriptorToSddl(sd []byte) (string, error) { + var sddl *uint16 + // The returned string length seems to include an arbitrary number of terminating NULs. + // Don't use it. + err := convertSecurityDescriptorToStringSecurityDescriptor(&sd[0], 1, 0xff, &sddl, nil) + if err != nil { + return "", err + } + defer localFree(uintptr(unsafe.Pointer(sddl))) + return syscall.UTF16ToString((*[0xffff]uint16)(unsafe.Pointer(sddl))[:]), nil +} diff --git a/vendor/github.com/Microsoft/go-winio/syscall.go b/vendor/github.com/Microsoft/go-winio/syscall.go new file mode 100644 index 0000000000..a6ca111b39 --- /dev/null +++ b/vendor/github.com/Microsoft/go-winio/syscall.go @@ -0,0 +1,5 @@ +//go:build windows + +package winio + +//go:generate go run github.com/Microsoft/go-winio/tools/mkwinsyscall -output zsyscall_windows.go ./*.go diff --git a/vendor/github.com/Microsoft/go-winio/tools.go b/vendor/github.com/Microsoft/go-winio/tools.go new file mode 100644 index 0000000000..2aa045843e --- /dev/null +++ b/vendor/github.com/Microsoft/go-winio/tools.go @@ -0,0 +1,5 @@ +//go:build tools + +package winio + +import _ "golang.org/x/tools/cmd/stringer" diff --git a/vendor/github.com/Microsoft/go-winio/zsyscall_windows.go b/vendor/github.com/Microsoft/go-winio/zsyscall_windows.go new file mode 100644 index 0000000000..469b16f639 --- /dev/null +++ b/vendor/github.com/Microsoft/go-winio/zsyscall_windows.go @@ -0,0 +1,419 @@ +//go:build windows + +// Code generated by 'go generate' using "github.com/Microsoft/go-winio/tools/mkwinsyscall"; DO NOT EDIT. + +package winio + +import ( + "syscall" + "unsafe" + + "golang.org/x/sys/windows" +) + +var _ unsafe.Pointer + +// Do the interface allocations only once for common +// Errno values. +const ( + errnoERROR_IO_PENDING = 997 +) + +var ( + errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING) + errERROR_EINVAL error = syscall.EINVAL +) + +// errnoErr returns common boxed Errno values, to prevent +// allocations at runtime. +func errnoErr(e syscall.Errno) error { + switch e { + case 0: + return errERROR_EINVAL + case errnoERROR_IO_PENDING: + return errERROR_IO_PENDING + } + // TODO: add more here, after collecting data on the common + // error values see on Windows. (perhaps when running + // all.bat?) + return e +} + +var ( + modadvapi32 = windows.NewLazySystemDLL("advapi32.dll") + modkernel32 = windows.NewLazySystemDLL("kernel32.dll") + modntdll = windows.NewLazySystemDLL("ntdll.dll") + modws2_32 = windows.NewLazySystemDLL("ws2_32.dll") + + procAdjustTokenPrivileges = modadvapi32.NewProc("AdjustTokenPrivileges") + procConvertSecurityDescriptorToStringSecurityDescriptorW = modadvapi32.NewProc("ConvertSecurityDescriptorToStringSecurityDescriptorW") + procConvertSidToStringSidW = modadvapi32.NewProc("ConvertSidToStringSidW") + procConvertStringSecurityDescriptorToSecurityDescriptorW = modadvapi32.NewProc("ConvertStringSecurityDescriptorToSecurityDescriptorW") + procConvertStringSidToSidW = modadvapi32.NewProc("ConvertStringSidToSidW") + procGetSecurityDescriptorLength = modadvapi32.NewProc("GetSecurityDescriptorLength") + procImpersonateSelf = modadvapi32.NewProc("ImpersonateSelf") + procLookupAccountNameW = modadvapi32.NewProc("LookupAccountNameW") + procLookupAccountSidW = modadvapi32.NewProc("LookupAccountSidW") + procLookupPrivilegeDisplayNameW = modadvapi32.NewProc("LookupPrivilegeDisplayNameW") + procLookupPrivilegeNameW = modadvapi32.NewProc("LookupPrivilegeNameW") + procLookupPrivilegeValueW = modadvapi32.NewProc("LookupPrivilegeValueW") + procOpenThreadToken = modadvapi32.NewProc("OpenThreadToken") + procRevertToSelf = modadvapi32.NewProc("RevertToSelf") + procBackupRead = modkernel32.NewProc("BackupRead") + procBackupWrite = modkernel32.NewProc("BackupWrite") + procCancelIoEx = modkernel32.NewProc("CancelIoEx") + procConnectNamedPipe = modkernel32.NewProc("ConnectNamedPipe") + procCreateIoCompletionPort = modkernel32.NewProc("CreateIoCompletionPort") + procCreateNamedPipeW = modkernel32.NewProc("CreateNamedPipeW") + procGetCurrentThread = modkernel32.NewProc("GetCurrentThread") + procGetNamedPipeHandleStateW = modkernel32.NewProc("GetNamedPipeHandleStateW") + procGetNamedPipeInfo = modkernel32.NewProc("GetNamedPipeInfo") + procGetQueuedCompletionStatus = modkernel32.NewProc("GetQueuedCompletionStatus") + procLocalAlloc = modkernel32.NewProc("LocalAlloc") + procLocalFree = modkernel32.NewProc("LocalFree") + procSetFileCompletionNotificationModes = modkernel32.NewProc("SetFileCompletionNotificationModes") + procNtCreateNamedPipeFile = modntdll.NewProc("NtCreateNamedPipeFile") + procRtlDefaultNpAcl = modntdll.NewProc("RtlDefaultNpAcl") + procRtlDosPathNameToNtPathName_U = modntdll.NewProc("RtlDosPathNameToNtPathName_U") + procRtlNtStatusToDosErrorNoTeb = modntdll.NewProc("RtlNtStatusToDosErrorNoTeb") + procWSAGetOverlappedResult = modws2_32.NewProc("WSAGetOverlappedResult") +) + +func adjustTokenPrivileges(token windows.Token, releaseAll bool, input *byte, outputSize uint32, output *byte, requiredSize *uint32) (success bool, err error) { + var _p0 uint32 + if releaseAll { + _p0 = 1 + } + r0, _, e1 := syscall.Syscall6(procAdjustTokenPrivileges.Addr(), 6, uintptr(token), uintptr(_p0), uintptr(unsafe.Pointer(input)), uintptr(outputSize), uintptr(unsafe.Pointer(output)), uintptr(unsafe.Pointer(requiredSize))) + success = r0 != 0 + if true { + err = errnoErr(e1) + } + return +} + +func convertSecurityDescriptorToStringSecurityDescriptor(sd *byte, revision uint32, secInfo uint32, sddl **uint16, sddlSize *uint32) (err error) { + r1, _, e1 := syscall.Syscall6(procConvertSecurityDescriptorToStringSecurityDescriptorW.Addr(), 5, uintptr(unsafe.Pointer(sd)), uintptr(revision), uintptr(secInfo), uintptr(unsafe.Pointer(sddl)), uintptr(unsafe.Pointer(sddlSize)), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func convertSidToStringSid(sid *byte, str **uint16) (err error) { + r1, _, e1 := syscall.Syscall(procConvertSidToStringSidW.Addr(), 2, uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(str)), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func convertStringSecurityDescriptorToSecurityDescriptor(str string, revision uint32, sd *uintptr, size *uint32) (err error) { + var _p0 *uint16 + _p0, err = syscall.UTF16PtrFromString(str) + if err != nil { + return + } + return _convertStringSecurityDescriptorToSecurityDescriptor(_p0, revision, sd, size) +} + +func _convertStringSecurityDescriptorToSecurityDescriptor(str *uint16, revision uint32, sd *uintptr, size *uint32) (err error) { + r1, _, e1 := syscall.Syscall6(procConvertStringSecurityDescriptorToSecurityDescriptorW.Addr(), 4, uintptr(unsafe.Pointer(str)), uintptr(revision), uintptr(unsafe.Pointer(sd)), uintptr(unsafe.Pointer(size)), 0, 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func convertStringSidToSid(str *uint16, sid **byte) (err error) { + r1, _, e1 := syscall.Syscall(procConvertStringSidToSidW.Addr(), 2, uintptr(unsafe.Pointer(str)), uintptr(unsafe.Pointer(sid)), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func getSecurityDescriptorLength(sd uintptr) (len uint32) { + r0, _, _ := syscall.Syscall(procGetSecurityDescriptorLength.Addr(), 1, uintptr(sd), 0, 0) + len = uint32(r0) + return +} + +func impersonateSelf(level uint32) (err error) { + r1, _, e1 := syscall.Syscall(procImpersonateSelf.Addr(), 1, uintptr(level), 0, 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func lookupAccountName(systemName *uint16, accountName string, sid *byte, sidSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) { + var _p0 *uint16 + _p0, err = syscall.UTF16PtrFromString(accountName) + if err != nil { + return + } + return _lookupAccountName(systemName, _p0, sid, sidSize, refDomain, refDomainSize, sidNameUse) +} + +func _lookupAccountName(systemName *uint16, accountName *uint16, sid *byte, sidSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) { + r1, _, e1 := syscall.Syscall9(procLookupAccountNameW.Addr(), 7, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(accountName)), uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(sidSize)), uintptr(unsafe.Pointer(refDomain)), uintptr(unsafe.Pointer(refDomainSize)), uintptr(unsafe.Pointer(sidNameUse)), 0, 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func lookupAccountSid(systemName *uint16, sid *byte, name *uint16, nameSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) { + r1, _, e1 := syscall.Syscall9(procLookupAccountSidW.Addr(), 7, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(nameSize)), uintptr(unsafe.Pointer(refDomain)), uintptr(unsafe.Pointer(refDomainSize)), uintptr(unsafe.Pointer(sidNameUse)), 0, 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func lookupPrivilegeDisplayName(systemName string, name *uint16, buffer *uint16, size *uint32, languageId *uint32) (err error) { + var _p0 *uint16 + _p0, err = syscall.UTF16PtrFromString(systemName) + if err != nil { + return + } + return _lookupPrivilegeDisplayName(_p0, name, buffer, size, languageId) +} + +func _lookupPrivilegeDisplayName(systemName *uint16, name *uint16, buffer *uint16, size *uint32, languageId *uint32) (err error) { + r1, _, e1 := syscall.Syscall6(procLookupPrivilegeDisplayNameW.Addr(), 5, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(buffer)), uintptr(unsafe.Pointer(size)), uintptr(unsafe.Pointer(languageId)), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func lookupPrivilegeName(systemName string, luid *uint64, buffer *uint16, size *uint32) (err error) { + var _p0 *uint16 + _p0, err = syscall.UTF16PtrFromString(systemName) + if err != nil { + return + } + return _lookupPrivilegeName(_p0, luid, buffer, size) +} + +func _lookupPrivilegeName(systemName *uint16, luid *uint64, buffer *uint16, size *uint32) (err error) { + r1, _, e1 := syscall.Syscall6(procLookupPrivilegeNameW.Addr(), 4, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(luid)), uintptr(unsafe.Pointer(buffer)), uintptr(unsafe.Pointer(size)), 0, 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func lookupPrivilegeValue(systemName string, name string, luid *uint64) (err error) { + var _p0 *uint16 + _p0, err = syscall.UTF16PtrFromString(systemName) + if err != nil { + return + } + var _p1 *uint16 + _p1, err = syscall.UTF16PtrFromString(name) + if err != nil { + return + } + return _lookupPrivilegeValue(_p0, _p1, luid) +} + +func _lookupPrivilegeValue(systemName *uint16, name *uint16, luid *uint64) (err error) { + r1, _, e1 := syscall.Syscall(procLookupPrivilegeValueW.Addr(), 3, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(luid))) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func openThreadToken(thread syscall.Handle, accessMask uint32, openAsSelf bool, token *windows.Token) (err error) { + var _p0 uint32 + if openAsSelf { + _p0 = 1 + } + r1, _, e1 := syscall.Syscall6(procOpenThreadToken.Addr(), 4, uintptr(thread), uintptr(accessMask), uintptr(_p0), uintptr(unsafe.Pointer(token)), 0, 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func revertToSelf() (err error) { + r1, _, e1 := syscall.Syscall(procRevertToSelf.Addr(), 0, 0, 0, 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func backupRead(h syscall.Handle, b []byte, bytesRead *uint32, abort bool, processSecurity bool, context *uintptr) (err error) { + var _p0 *byte + if len(b) > 0 { + _p0 = &b[0] + } + var _p1 uint32 + if abort { + _p1 = 1 + } + var _p2 uint32 + if processSecurity { + _p2 = 1 + } + r1, _, e1 := syscall.Syscall9(procBackupRead.Addr(), 7, uintptr(h), uintptr(unsafe.Pointer(_p0)), uintptr(len(b)), uintptr(unsafe.Pointer(bytesRead)), uintptr(_p1), uintptr(_p2), uintptr(unsafe.Pointer(context)), 0, 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func backupWrite(h syscall.Handle, b []byte, bytesWritten *uint32, abort bool, processSecurity bool, context *uintptr) (err error) { + var _p0 *byte + if len(b) > 0 { + _p0 = &b[0] + } + var _p1 uint32 + if abort { + _p1 = 1 + } + var _p2 uint32 + if processSecurity { + _p2 = 1 + } + r1, _, e1 := syscall.Syscall9(procBackupWrite.Addr(), 7, uintptr(h), uintptr(unsafe.Pointer(_p0)), uintptr(len(b)), uintptr(unsafe.Pointer(bytesWritten)), uintptr(_p1), uintptr(_p2), uintptr(unsafe.Pointer(context)), 0, 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func cancelIoEx(file syscall.Handle, o *syscall.Overlapped) (err error) { + r1, _, e1 := syscall.Syscall(procCancelIoEx.Addr(), 2, uintptr(file), uintptr(unsafe.Pointer(o)), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func connectNamedPipe(pipe syscall.Handle, o *syscall.Overlapped) (err error) { + r1, _, e1 := syscall.Syscall(procConnectNamedPipe.Addr(), 2, uintptr(pipe), uintptr(unsafe.Pointer(o)), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func createIoCompletionPort(file syscall.Handle, port syscall.Handle, key uintptr, threadCount uint32) (newport syscall.Handle, err error) { + r0, _, e1 := syscall.Syscall6(procCreateIoCompletionPort.Addr(), 4, uintptr(file), uintptr(port), uintptr(key), uintptr(threadCount), 0, 0) + newport = syscall.Handle(r0) + if newport == 0 { + err = errnoErr(e1) + } + return +} + +func createNamedPipe(name string, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *syscall.SecurityAttributes) (handle syscall.Handle, err error) { + var _p0 *uint16 + _p0, err = syscall.UTF16PtrFromString(name) + if err != nil { + return + } + return _createNamedPipe(_p0, flags, pipeMode, maxInstances, outSize, inSize, defaultTimeout, sa) +} + +func _createNamedPipe(name *uint16, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *syscall.SecurityAttributes) (handle syscall.Handle, err error) { + r0, _, e1 := syscall.Syscall9(procCreateNamedPipeW.Addr(), 8, uintptr(unsafe.Pointer(name)), uintptr(flags), uintptr(pipeMode), uintptr(maxInstances), uintptr(outSize), uintptr(inSize), uintptr(defaultTimeout), uintptr(unsafe.Pointer(sa)), 0) + handle = syscall.Handle(r0) + if handle == syscall.InvalidHandle { + err = errnoErr(e1) + } + return +} + +func getCurrentThread() (h syscall.Handle) { + r0, _, _ := syscall.Syscall(procGetCurrentThread.Addr(), 0, 0, 0, 0) + h = syscall.Handle(r0) + return +} + +func getNamedPipeHandleState(pipe syscall.Handle, state *uint32, curInstances *uint32, maxCollectionCount *uint32, collectDataTimeout *uint32, userName *uint16, maxUserNameSize uint32) (err error) { + r1, _, e1 := syscall.Syscall9(procGetNamedPipeHandleStateW.Addr(), 7, uintptr(pipe), uintptr(unsafe.Pointer(state)), uintptr(unsafe.Pointer(curInstances)), uintptr(unsafe.Pointer(maxCollectionCount)), uintptr(unsafe.Pointer(collectDataTimeout)), uintptr(unsafe.Pointer(userName)), uintptr(maxUserNameSize), 0, 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func getNamedPipeInfo(pipe syscall.Handle, flags *uint32, outSize *uint32, inSize *uint32, maxInstances *uint32) (err error) { + r1, _, e1 := syscall.Syscall6(procGetNamedPipeInfo.Addr(), 5, uintptr(pipe), uintptr(unsafe.Pointer(flags)), uintptr(unsafe.Pointer(outSize)), uintptr(unsafe.Pointer(inSize)), uintptr(unsafe.Pointer(maxInstances)), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func getQueuedCompletionStatus(port syscall.Handle, bytes *uint32, key *uintptr, o **ioOperation, timeout uint32) (err error) { + r1, _, e1 := syscall.Syscall6(procGetQueuedCompletionStatus.Addr(), 5, uintptr(port), uintptr(unsafe.Pointer(bytes)), uintptr(unsafe.Pointer(key)), uintptr(unsafe.Pointer(o)), uintptr(timeout), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func localAlloc(uFlags uint32, length uint32) (ptr uintptr) { + r0, _, _ := syscall.Syscall(procLocalAlloc.Addr(), 2, uintptr(uFlags), uintptr(length), 0) + ptr = uintptr(r0) + return +} + +func localFree(mem uintptr) { + syscall.Syscall(procLocalFree.Addr(), 1, uintptr(mem), 0, 0) + return +} + +func setFileCompletionNotificationModes(h syscall.Handle, flags uint8) (err error) { + r1, _, e1 := syscall.Syscall(procSetFileCompletionNotificationModes.Addr(), 2, uintptr(h), uintptr(flags), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func ntCreateNamedPipeFile(pipe *syscall.Handle, access uint32, oa *objectAttributes, iosb *ioStatusBlock, share uint32, disposition uint32, options uint32, typ uint32, readMode uint32, completionMode uint32, maxInstances uint32, inboundQuota uint32, outputQuota uint32, timeout *int64) (status ntStatus) { + r0, _, _ := syscall.Syscall15(procNtCreateNamedPipeFile.Addr(), 14, uintptr(unsafe.Pointer(pipe)), uintptr(access), uintptr(unsafe.Pointer(oa)), uintptr(unsafe.Pointer(iosb)), uintptr(share), uintptr(disposition), uintptr(options), uintptr(typ), uintptr(readMode), uintptr(completionMode), uintptr(maxInstances), uintptr(inboundQuota), uintptr(outputQuota), uintptr(unsafe.Pointer(timeout)), 0) + status = ntStatus(r0) + return +} + +func rtlDefaultNpAcl(dacl *uintptr) (status ntStatus) { + r0, _, _ := syscall.Syscall(procRtlDefaultNpAcl.Addr(), 1, uintptr(unsafe.Pointer(dacl)), 0, 0) + status = ntStatus(r0) + return +} + +func rtlDosPathNameToNtPathName(name *uint16, ntName *unicodeString, filePart uintptr, reserved uintptr) (status ntStatus) { + r0, _, _ := syscall.Syscall6(procRtlDosPathNameToNtPathName_U.Addr(), 4, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(ntName)), uintptr(filePart), uintptr(reserved), 0, 0) + status = ntStatus(r0) + return +} + +func rtlNtStatusToDosError(status ntStatus) (winerr error) { + r0, _, _ := syscall.Syscall(procRtlNtStatusToDosErrorNoTeb.Addr(), 1, uintptr(status), 0, 0) + if r0 != 0 { + winerr = syscall.Errno(r0) + } + return +} + +func wsaGetOverlappedResult(h syscall.Handle, o *syscall.Overlapped, bytes *uint32, wait bool, flags *uint32) (err error) { + var _p0 uint32 + if wait { + _p0 = 1 + } + r1, _, e1 := syscall.Syscall6(procWSAGetOverlappedResult.Addr(), 5, uintptr(h), uintptr(unsafe.Pointer(o)), uintptr(unsafe.Pointer(bytes)), uintptr(_p0), uintptr(unsafe.Pointer(flags)), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} diff --git a/vendor/github.com/docker/distribution/LICENSE b/vendor/github.com/docker/distribution/LICENSE new file mode 100644 index 0000000000..e06d208186 --- /dev/null +++ b/vendor/github.com/docker/distribution/LICENSE @@ -0,0 +1,202 @@ +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/vendor/github.com/docker/distribution/digestset/set.go b/vendor/github.com/docker/distribution/digestset/set.go new file mode 100644 index 0000000000..71327dca72 --- /dev/null +++ b/vendor/github.com/docker/distribution/digestset/set.go @@ -0,0 +1,247 @@ +package digestset + +import ( + "errors" + "sort" + "strings" + "sync" + + digest "github.com/opencontainers/go-digest" +) + +var ( + // ErrDigestNotFound is used when a matching digest + // could not be found in a set. + ErrDigestNotFound = errors.New("digest not found") + + // ErrDigestAmbiguous is used when multiple digests + // are found in a set. None of the matching digests + // should be considered valid matches. + ErrDigestAmbiguous = errors.New("ambiguous digest string") +) + +// Set is used to hold a unique set of digests which +// may be easily referenced by easily referenced by a string +// representation of the digest as well as short representation. +// The uniqueness of the short representation is based on other +// digests in the set. If digests are omitted from this set, +// collisions in a larger set may not be detected, therefore it +// is important to always do short representation lookups on +// the complete set of digests. To mitigate collisions, an +// appropriately long short code should be used. +type Set struct { + mutex sync.RWMutex + entries digestEntries +} + +// NewSet creates an empty set of digests +// which may have digests added. +func NewSet() *Set { + return &Set{ + entries: digestEntries{}, + } +} + +// checkShortMatch checks whether two digests match as either whole +// values or short values. This function does not test equality, +// rather whether the second value could match against the first +// value. +func checkShortMatch(alg digest.Algorithm, hex, shortAlg, shortHex string) bool { + if len(hex) == len(shortHex) { + if hex != shortHex { + return false + } + if len(shortAlg) > 0 && string(alg) != shortAlg { + return false + } + } else if !strings.HasPrefix(hex, shortHex) { + return false + } else if len(shortAlg) > 0 && string(alg) != shortAlg { + return false + } + return true +} + +// Lookup looks for a digest matching the given string representation. +// If no digests could be found ErrDigestNotFound will be returned +// with an empty digest value. If multiple matches are found +// ErrDigestAmbiguous will be returned with an empty digest value. +func (dst *Set) Lookup(d string) (digest.Digest, error) { + dst.mutex.RLock() + defer dst.mutex.RUnlock() + if len(dst.entries) == 0 { + return "", ErrDigestNotFound + } + var ( + searchFunc func(int) bool + alg digest.Algorithm + hex string + ) + dgst, err := digest.Parse(d) + if err == digest.ErrDigestInvalidFormat { + hex = d + searchFunc = func(i int) bool { + return dst.entries[i].val >= d + } + } else { + hex = dgst.Hex() + alg = dgst.Algorithm() + searchFunc = func(i int) bool { + if dst.entries[i].val == hex { + return dst.entries[i].alg >= alg + } + return dst.entries[i].val >= hex + } + } + idx := sort.Search(len(dst.entries), searchFunc) + if idx == len(dst.entries) || !checkShortMatch(dst.entries[idx].alg, dst.entries[idx].val, string(alg), hex) { + return "", ErrDigestNotFound + } + if dst.entries[idx].alg == alg && dst.entries[idx].val == hex { + return dst.entries[idx].digest, nil + } + if idx+1 < len(dst.entries) && checkShortMatch(dst.entries[idx+1].alg, dst.entries[idx+1].val, string(alg), hex) { + return "", ErrDigestAmbiguous + } + + return dst.entries[idx].digest, nil +} + +// Add adds the given digest to the set. An error will be returned +// if the given digest is invalid. If the digest already exists in the +// set, this operation will be a no-op. +func (dst *Set) Add(d digest.Digest) error { + if err := d.Validate(); err != nil { + return err + } + dst.mutex.Lock() + defer dst.mutex.Unlock() + entry := &digestEntry{alg: d.Algorithm(), val: d.Hex(), digest: d} + searchFunc := func(i int) bool { + if dst.entries[i].val == entry.val { + return dst.entries[i].alg >= entry.alg + } + return dst.entries[i].val >= entry.val + } + idx := sort.Search(len(dst.entries), searchFunc) + if idx == len(dst.entries) { + dst.entries = append(dst.entries, entry) + return nil + } else if dst.entries[idx].digest == d { + return nil + } + + entries := append(dst.entries, nil) + copy(entries[idx+1:], entries[idx:len(entries)-1]) + entries[idx] = entry + dst.entries = entries + return nil +} + +// Remove removes the given digest from the set. An err will be +// returned if the given digest is invalid. If the digest does +// not exist in the set, this operation will be a no-op. +func (dst *Set) Remove(d digest.Digest) error { + if err := d.Validate(); err != nil { + return err + } + dst.mutex.Lock() + defer dst.mutex.Unlock() + entry := &digestEntry{alg: d.Algorithm(), val: d.Hex(), digest: d} + searchFunc := func(i int) bool { + if dst.entries[i].val == entry.val { + return dst.entries[i].alg >= entry.alg + } + return dst.entries[i].val >= entry.val + } + idx := sort.Search(len(dst.entries), searchFunc) + // Not found if idx is after or value at idx is not digest + if idx == len(dst.entries) || dst.entries[idx].digest != d { + return nil + } + + entries := dst.entries + copy(entries[idx:], entries[idx+1:]) + entries = entries[:len(entries)-1] + dst.entries = entries + + return nil +} + +// All returns all the digests in the set +func (dst *Set) All() []digest.Digest { + dst.mutex.RLock() + defer dst.mutex.RUnlock() + retValues := make([]digest.Digest, len(dst.entries)) + for i := range dst.entries { + retValues[i] = dst.entries[i].digest + } + + return retValues +} + +// ShortCodeTable returns a map of Digest to unique short codes. The +// length represents the minimum value, the maximum length may be the +// entire value of digest if uniqueness cannot be achieved without the +// full value. This function will attempt to make short codes as short +// as possible to be unique. +func ShortCodeTable(dst *Set, length int) map[digest.Digest]string { + dst.mutex.RLock() + defer dst.mutex.RUnlock() + m := make(map[digest.Digest]string, len(dst.entries)) + l := length + resetIdx := 0 + for i := 0; i < len(dst.entries); i++ { + var short string + extended := true + for extended { + extended = false + if len(dst.entries[i].val) <= l { + short = dst.entries[i].digest.String() + } else { + short = dst.entries[i].val[:l] + for j := i + 1; j < len(dst.entries); j++ { + if checkShortMatch(dst.entries[j].alg, dst.entries[j].val, "", short) { + if j > resetIdx { + resetIdx = j + } + extended = true + } else { + break + } + } + if extended { + l++ + } + } + } + m[dst.entries[i].digest] = short + if i >= resetIdx { + l = length + } + } + return m +} + +type digestEntry struct { + alg digest.Algorithm + val string + digest digest.Digest +} + +type digestEntries []*digestEntry + +func (d digestEntries) Len() int { + return len(d) +} + +func (d digestEntries) Less(i, j int) bool { + if d[i].val != d[j].val { + return d[i].val < d[j].val + } + return d[i].alg < d[j].alg +} + +func (d digestEntries) Swap(i, j int) { + d[i], d[j] = d[j], d[i] +} diff --git a/vendor/github.com/docker/distribution/reference/helpers.go b/vendor/github.com/docker/distribution/reference/helpers.go new file mode 100644 index 0000000000..978df7eabb --- /dev/null +++ b/vendor/github.com/docker/distribution/reference/helpers.go @@ -0,0 +1,42 @@ +package reference + +import "path" + +// IsNameOnly returns true if reference only contains a repo name. +func IsNameOnly(ref Named) bool { + if _, ok := ref.(NamedTagged); ok { + return false + } + if _, ok := ref.(Canonical); ok { + return false + } + return true +} + +// FamiliarName returns the familiar name string +// for the given named, familiarizing if needed. +func FamiliarName(ref Named) string { + if nn, ok := ref.(normalizedNamed); ok { + return nn.Familiar().Name() + } + return ref.Name() +} + +// FamiliarString returns the familiar string representation +// for the given reference, familiarizing if needed. +func FamiliarString(ref Reference) string { + if nn, ok := ref.(normalizedNamed); ok { + return nn.Familiar().String() + } + return ref.String() +} + +// FamiliarMatch reports whether ref matches the specified pattern. +// See https://godoc.org/path#Match for supported patterns. +func FamiliarMatch(pattern string, ref Reference) (bool, error) { + matched, err := path.Match(pattern, FamiliarString(ref)) + if namedRef, isNamed := ref.(Named); isNamed && !matched { + matched, _ = path.Match(pattern, FamiliarName(namedRef)) + } + return matched, err +} diff --git a/vendor/github.com/docker/distribution/reference/normalize.go b/vendor/github.com/docker/distribution/reference/normalize.go new file mode 100644 index 0000000000..b3dfb7a6d7 --- /dev/null +++ b/vendor/github.com/docker/distribution/reference/normalize.go @@ -0,0 +1,199 @@ +package reference + +import ( + "errors" + "fmt" + "strings" + + "github.com/docker/distribution/digestset" + "github.com/opencontainers/go-digest" +) + +var ( + legacyDefaultDomain = "index.docker.io" + defaultDomain = "docker.io" + officialRepoName = "library" + defaultTag = "latest" +) + +// normalizedNamed represents a name which has been +// normalized and has a familiar form. A familiar name +// is what is used in Docker UI. An example normalized +// name is "docker.io/library/ubuntu" and corresponding +// familiar name of "ubuntu". +type normalizedNamed interface { + Named + Familiar() Named +} + +// ParseNormalizedNamed parses a string into a named reference +// transforming a familiar name from Docker UI to a fully +// qualified reference. If the value may be an identifier +// use ParseAnyReference. +func ParseNormalizedNamed(s string) (Named, error) { + if ok := anchoredIdentifierRegexp.MatchString(s); ok { + return nil, fmt.Errorf("invalid repository name (%s), cannot specify 64-byte hexadecimal strings", s) + } + domain, remainder := splitDockerDomain(s) + var remoteName string + if tagSep := strings.IndexRune(remainder, ':'); tagSep > -1 { + remoteName = remainder[:tagSep] + } else { + remoteName = remainder + } + if strings.ToLower(remoteName) != remoteName { + return nil, errors.New("invalid reference format: repository name must be lowercase") + } + + ref, err := Parse(domain + "/" + remainder) + if err != nil { + return nil, err + } + named, isNamed := ref.(Named) + if !isNamed { + return nil, fmt.Errorf("reference %s has no name", ref.String()) + } + return named, nil +} + +// ParseDockerRef normalizes the image reference following the docker convention. This is added +// mainly for backward compatibility. +// The reference returned can only be either tagged or digested. For reference contains both tag +// and digest, the function returns digested reference, e.g. docker.io/library/busybox:latest@ +// sha256:7cc4b5aefd1d0cadf8d97d4350462ba51c694ebca145b08d7d41b41acc8db5aa will be returned as +// docker.io/library/busybox@sha256:7cc4b5aefd1d0cadf8d97d4350462ba51c694ebca145b08d7d41b41acc8db5aa. +func ParseDockerRef(ref string) (Named, error) { + named, err := ParseNormalizedNamed(ref) + if err != nil { + return nil, err + } + if _, ok := named.(NamedTagged); ok { + if canonical, ok := named.(Canonical); ok { + // The reference is both tagged and digested, only + // return digested. + newNamed, err := WithName(canonical.Name()) + if err != nil { + return nil, err + } + newCanonical, err := WithDigest(newNamed, canonical.Digest()) + if err != nil { + return nil, err + } + return newCanonical, nil + } + } + return TagNameOnly(named), nil +} + +// splitDockerDomain splits a repository name to domain and remotename string. +// If no valid domain is found, the default domain is used. Repository name +// needs to be already validated before. +func splitDockerDomain(name string) (domain, remainder string) { + i := strings.IndexRune(name, '/') + if i == -1 || (!strings.ContainsAny(name[:i], ".:") && name[:i] != "localhost") { + domain, remainder = defaultDomain, name + } else { + domain, remainder = name[:i], name[i+1:] + } + if domain == legacyDefaultDomain { + domain = defaultDomain + } + if domain == defaultDomain && !strings.ContainsRune(remainder, '/') { + remainder = officialRepoName + "/" + remainder + } + return +} + +// familiarizeName returns a shortened version of the name familiar +// to to the Docker UI. Familiar names have the default domain +// "docker.io" and "library/" repository prefix removed. +// For example, "docker.io/library/redis" will have the familiar +// name "redis" and "docker.io/dmcgowan/myapp" will be "dmcgowan/myapp". +// Returns a familiarized named only reference. +func familiarizeName(named namedRepository) repository { + repo := repository{ + domain: named.Domain(), + path: named.Path(), + } + + if repo.domain == defaultDomain { + repo.domain = "" + // Handle official repositories which have the pattern "library/" + if split := strings.Split(repo.path, "/"); len(split) == 2 && split[0] == officialRepoName { + repo.path = split[1] + } + } + return repo +} + +func (r reference) Familiar() Named { + return reference{ + namedRepository: familiarizeName(r.namedRepository), + tag: r.tag, + digest: r.digest, + } +} + +func (r repository) Familiar() Named { + return familiarizeName(r) +} + +func (t taggedReference) Familiar() Named { + return taggedReference{ + namedRepository: familiarizeName(t.namedRepository), + tag: t.tag, + } +} + +func (c canonicalReference) Familiar() Named { + return canonicalReference{ + namedRepository: familiarizeName(c.namedRepository), + digest: c.digest, + } +} + +// TagNameOnly adds the default tag "latest" to a reference if it only has +// a repo name. +func TagNameOnly(ref Named) Named { + if IsNameOnly(ref) { + namedTagged, err := WithTag(ref, defaultTag) + if err != nil { + // Default tag must be valid, to create a NamedTagged + // type with non-validated input the WithTag function + // should be used instead + panic(err) + } + return namedTagged + } + return ref +} + +// ParseAnyReference parses a reference string as a possible identifier, +// full digest, or familiar name. +func ParseAnyReference(ref string) (Reference, error) { + if ok := anchoredIdentifierRegexp.MatchString(ref); ok { + return digestReference("sha256:" + ref), nil + } + if dgst, err := digest.Parse(ref); err == nil { + return digestReference(dgst), nil + } + + return ParseNormalizedNamed(ref) +} + +// ParseAnyReferenceWithSet parses a reference string as a possible short +// identifier to be matched in a digest set, a full digest, or familiar name. +func ParseAnyReferenceWithSet(ref string, ds *digestset.Set) (Reference, error) { + if ok := anchoredShortIdentifierRegexp.MatchString(ref); ok { + dgst, err := ds.Lookup(ref) + if err == nil { + return digestReference(dgst), nil + } + } else { + if dgst, err := digest.Parse(ref); err == nil { + return digestReference(dgst), nil + } + } + + return ParseNormalizedNamed(ref) +} diff --git a/vendor/github.com/docker/distribution/reference/reference.go b/vendor/github.com/docker/distribution/reference/reference.go new file mode 100644 index 0000000000..b7cd00b0d6 --- /dev/null +++ b/vendor/github.com/docker/distribution/reference/reference.go @@ -0,0 +1,433 @@ +// Package reference provides a general type to represent any way of referencing images within the registry. +// Its main purpose is to abstract tags and digests (content-addressable hash). +// +// Grammar +// +// reference := name [ ":" tag ] [ "@" digest ] +// name := [domain '/'] path-component ['/' path-component]* +// domain := domain-component ['.' domain-component]* [':' port-number] +// domain-component := /([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])/ +// port-number := /[0-9]+/ +// path-component := alpha-numeric [separator alpha-numeric]* +// alpha-numeric := /[a-z0-9]+/ +// separator := /[_.]|__|[-]*/ +// +// tag := /[\w][\w.-]{0,127}/ +// +// digest := digest-algorithm ":" digest-hex +// digest-algorithm := digest-algorithm-component [ digest-algorithm-separator digest-algorithm-component ]* +// digest-algorithm-separator := /[+.-_]/ +// digest-algorithm-component := /[A-Za-z][A-Za-z0-9]*/ +// digest-hex := /[0-9a-fA-F]{32,}/ ; At least 128 bit digest value +// +// identifier := /[a-f0-9]{64}/ +// short-identifier := /[a-f0-9]{6,64}/ +package reference + +import ( + "errors" + "fmt" + "strings" + + "github.com/opencontainers/go-digest" +) + +const ( + // NameTotalLengthMax is the maximum total number of characters in a repository name. + NameTotalLengthMax = 255 +) + +var ( + // ErrReferenceInvalidFormat represents an error while trying to parse a string as a reference. + ErrReferenceInvalidFormat = errors.New("invalid reference format") + + // ErrTagInvalidFormat represents an error while trying to parse a string as a tag. + ErrTagInvalidFormat = errors.New("invalid tag format") + + // ErrDigestInvalidFormat represents an error while trying to parse a string as a tag. + ErrDigestInvalidFormat = errors.New("invalid digest format") + + // ErrNameContainsUppercase is returned for invalid repository names that contain uppercase characters. + ErrNameContainsUppercase = errors.New("repository name must be lowercase") + + // ErrNameEmpty is returned for empty, invalid repository names. + ErrNameEmpty = errors.New("repository name must have at least one component") + + // ErrNameTooLong is returned when a repository name is longer than NameTotalLengthMax. + ErrNameTooLong = fmt.Errorf("repository name must not be more than %v characters", NameTotalLengthMax) + + // ErrNameNotCanonical is returned when a name is not canonical. + ErrNameNotCanonical = errors.New("repository name must be canonical") +) + +// Reference is an opaque object reference identifier that may include +// modifiers such as a hostname, name, tag, and digest. +type Reference interface { + // String returns the full reference + String() string +} + +// Field provides a wrapper type for resolving correct reference types when +// working with encoding. +type Field struct { + reference Reference +} + +// AsField wraps a reference in a Field for encoding. +func AsField(reference Reference) Field { + return Field{reference} +} + +// Reference unwraps the reference type from the field to +// return the Reference object. This object should be +// of the appropriate type to further check for different +// reference types. +func (f Field) Reference() Reference { + return f.reference +} + +// MarshalText serializes the field to byte text which +// is the string of the reference. +func (f Field) MarshalText() (p []byte, err error) { + return []byte(f.reference.String()), nil +} + +// UnmarshalText parses text bytes by invoking the +// reference parser to ensure the appropriately +// typed reference object is wrapped by field. +func (f *Field) UnmarshalText(p []byte) error { + r, err := Parse(string(p)) + if err != nil { + return err + } + + f.reference = r + return nil +} + +// Named is an object with a full name +type Named interface { + Reference + Name() string +} + +// Tagged is an object which has a tag +type Tagged interface { + Reference + Tag() string +} + +// NamedTagged is an object including a name and tag. +type NamedTagged interface { + Named + Tag() string +} + +// Digested is an object which has a digest +// in which it can be referenced by +type Digested interface { + Reference + Digest() digest.Digest +} + +// Canonical reference is an object with a fully unique +// name including a name with domain and digest +type Canonical interface { + Named + Digest() digest.Digest +} + +// namedRepository is a reference to a repository with a name. +// A namedRepository has both domain and path components. +type namedRepository interface { + Named + Domain() string + Path() string +} + +// Domain returns the domain part of the Named reference +func Domain(named Named) string { + if r, ok := named.(namedRepository); ok { + return r.Domain() + } + domain, _ := splitDomain(named.Name()) + return domain +} + +// Path returns the name without the domain part of the Named reference +func Path(named Named) (name string) { + if r, ok := named.(namedRepository); ok { + return r.Path() + } + _, path := splitDomain(named.Name()) + return path +} + +func splitDomain(name string) (string, string) { + match := anchoredNameRegexp.FindStringSubmatch(name) + if len(match) != 3 { + return "", name + } + return match[1], match[2] +} + +// SplitHostname splits a named reference into a +// hostname and name string. If no valid hostname is +// found, the hostname is empty and the full value +// is returned as name +// DEPRECATED: Use Domain or Path +func SplitHostname(named Named) (string, string) { + if r, ok := named.(namedRepository); ok { + return r.Domain(), r.Path() + } + return splitDomain(named.Name()) +} + +// Parse parses s and returns a syntactically valid Reference. +// If an error was encountered it is returned, along with a nil Reference. +// NOTE: Parse will not handle short digests. +func Parse(s string) (Reference, error) { + matches := ReferenceRegexp.FindStringSubmatch(s) + if matches == nil { + if s == "" { + return nil, ErrNameEmpty + } + if ReferenceRegexp.FindStringSubmatch(strings.ToLower(s)) != nil { + return nil, ErrNameContainsUppercase + } + return nil, ErrReferenceInvalidFormat + } + + if len(matches[1]) > NameTotalLengthMax { + return nil, ErrNameTooLong + } + + var repo repository + + nameMatch := anchoredNameRegexp.FindStringSubmatch(matches[1]) + if len(nameMatch) == 3 { + repo.domain = nameMatch[1] + repo.path = nameMatch[2] + } else { + repo.domain = "" + repo.path = matches[1] + } + + ref := reference{ + namedRepository: repo, + tag: matches[2], + } + if matches[3] != "" { + var err error + ref.digest, err = digest.Parse(matches[3]) + if err != nil { + return nil, err + } + } + + r := getBestReferenceType(ref) + if r == nil { + return nil, ErrNameEmpty + } + + return r, nil +} + +// ParseNamed parses s and returns a syntactically valid reference implementing +// the Named interface. The reference must have a name and be in the canonical +// form, otherwise an error is returned. +// If an error was encountered it is returned, along with a nil Reference. +// NOTE: ParseNamed will not handle short digests. +func ParseNamed(s string) (Named, error) { + named, err := ParseNormalizedNamed(s) + if err != nil { + return nil, err + } + if named.String() != s { + return nil, ErrNameNotCanonical + } + return named, nil +} + +// WithName returns a named object representing the given string. If the input +// is invalid ErrReferenceInvalidFormat will be returned. +func WithName(name string) (Named, error) { + if len(name) > NameTotalLengthMax { + return nil, ErrNameTooLong + } + + match := anchoredNameRegexp.FindStringSubmatch(name) + if match == nil || len(match) != 3 { + return nil, ErrReferenceInvalidFormat + } + return repository{ + domain: match[1], + path: match[2], + }, nil +} + +// WithTag combines the name from "name" and the tag from "tag" to form a +// reference incorporating both the name and the tag. +func WithTag(name Named, tag string) (NamedTagged, error) { + if !anchoredTagRegexp.MatchString(tag) { + return nil, ErrTagInvalidFormat + } + var repo repository + if r, ok := name.(namedRepository); ok { + repo.domain = r.Domain() + repo.path = r.Path() + } else { + repo.path = name.Name() + } + if canonical, ok := name.(Canonical); ok { + return reference{ + namedRepository: repo, + tag: tag, + digest: canonical.Digest(), + }, nil + } + return taggedReference{ + namedRepository: repo, + tag: tag, + }, nil +} + +// WithDigest combines the name from "name" and the digest from "digest" to form +// a reference incorporating both the name and the digest. +func WithDigest(name Named, digest digest.Digest) (Canonical, error) { + if !anchoredDigestRegexp.MatchString(digest.String()) { + return nil, ErrDigestInvalidFormat + } + var repo repository + if r, ok := name.(namedRepository); ok { + repo.domain = r.Domain() + repo.path = r.Path() + } else { + repo.path = name.Name() + } + if tagged, ok := name.(Tagged); ok { + return reference{ + namedRepository: repo, + tag: tagged.Tag(), + digest: digest, + }, nil + } + return canonicalReference{ + namedRepository: repo, + digest: digest, + }, nil +} + +// TrimNamed removes any tag or digest from the named reference. +func TrimNamed(ref Named) Named { + domain, path := SplitHostname(ref) + return repository{ + domain: domain, + path: path, + } +} + +func getBestReferenceType(ref reference) Reference { + if ref.Name() == "" { + // Allow digest only references + if ref.digest != "" { + return digestReference(ref.digest) + } + return nil + } + if ref.tag == "" { + if ref.digest != "" { + return canonicalReference{ + namedRepository: ref.namedRepository, + digest: ref.digest, + } + } + return ref.namedRepository + } + if ref.digest == "" { + return taggedReference{ + namedRepository: ref.namedRepository, + tag: ref.tag, + } + } + + return ref +} + +type reference struct { + namedRepository + tag string + digest digest.Digest +} + +func (r reference) String() string { + return r.Name() + ":" + r.tag + "@" + r.digest.String() +} + +func (r reference) Tag() string { + return r.tag +} + +func (r reference) Digest() digest.Digest { + return r.digest +} + +type repository struct { + domain string + path string +} + +func (r repository) String() string { + return r.Name() +} + +func (r repository) Name() string { + if r.domain == "" { + return r.path + } + return r.domain + "/" + r.path +} + +func (r repository) Domain() string { + return r.domain +} + +func (r repository) Path() string { + return r.path +} + +type digestReference digest.Digest + +func (d digestReference) String() string { + return digest.Digest(d).String() +} + +func (d digestReference) Digest() digest.Digest { + return digest.Digest(d) +} + +type taggedReference struct { + namedRepository + tag string +} + +func (t taggedReference) String() string { + return t.Name() + ":" + t.tag +} + +func (t taggedReference) Tag() string { + return t.tag +} + +type canonicalReference struct { + namedRepository + digest digest.Digest +} + +func (c canonicalReference) String() string { + return c.Name() + "@" + c.digest.String() +} + +func (c canonicalReference) Digest() digest.Digest { + return c.digest +} diff --git a/vendor/github.com/docker/distribution/reference/regexp.go b/vendor/github.com/docker/distribution/reference/regexp.go new file mode 100644 index 0000000000..7860349320 --- /dev/null +++ b/vendor/github.com/docker/distribution/reference/regexp.go @@ -0,0 +1,143 @@ +package reference + +import "regexp" + +var ( + // alphaNumericRegexp defines the alpha numeric atom, typically a + // component of names. This only allows lower case characters and digits. + alphaNumericRegexp = match(`[a-z0-9]+`) + + // separatorRegexp defines the separators allowed to be embedded in name + // components. This allow one period, one or two underscore and multiple + // dashes. + separatorRegexp = match(`(?:[._]|__|[-]*)`) + + // nameComponentRegexp restricts registry path component names to start + // with at least one letter or number, with following parts able to be + // separated by one period, one or two underscore and multiple dashes. + nameComponentRegexp = expression( + alphaNumericRegexp, + optional(repeated(separatorRegexp, alphaNumericRegexp))) + + // domainComponentRegexp restricts the registry domain component of a + // repository name to start with a component as defined by DomainRegexp + // and followed by an optional port. + domainComponentRegexp = match(`(?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])`) + + // DomainRegexp defines the structure of potential domain components + // that may be part of image names. This is purposely a subset of what is + // allowed by DNS to ensure backwards compatibility with Docker image + // names. + DomainRegexp = expression( + domainComponentRegexp, + optional(repeated(literal(`.`), domainComponentRegexp)), + optional(literal(`:`), match(`[0-9]+`))) + + // TagRegexp matches valid tag names. From docker/docker:graph/tags.go. + TagRegexp = match(`[\w][\w.-]{0,127}`) + + // anchoredTagRegexp matches valid tag names, anchored at the start and + // end of the matched string. + anchoredTagRegexp = anchored(TagRegexp) + + // DigestRegexp matches valid digests. + DigestRegexp = match(`[A-Za-z][A-Za-z0-9]*(?:[-_+.][A-Za-z][A-Za-z0-9]*)*[:][[:xdigit:]]{32,}`) + + // anchoredDigestRegexp matches valid digests, anchored at the start and + // end of the matched string. + anchoredDigestRegexp = anchored(DigestRegexp) + + // NameRegexp is the format for the name component of references. The + // regexp has capturing groups for the domain and name part omitting + // the separating forward slash from either. + NameRegexp = expression( + optional(DomainRegexp, literal(`/`)), + nameComponentRegexp, + optional(repeated(literal(`/`), nameComponentRegexp))) + + // anchoredNameRegexp is used to parse a name value, capturing the + // domain and trailing components. + anchoredNameRegexp = anchored( + optional(capture(DomainRegexp), literal(`/`)), + capture(nameComponentRegexp, + optional(repeated(literal(`/`), nameComponentRegexp)))) + + // ReferenceRegexp is the full supported format of a reference. The regexp + // is anchored and has capturing groups for name, tag, and digest + // components. + ReferenceRegexp = anchored(capture(NameRegexp), + optional(literal(":"), capture(TagRegexp)), + optional(literal("@"), capture(DigestRegexp))) + + // IdentifierRegexp is the format for string identifier used as a + // content addressable identifier using sha256. These identifiers + // are like digests without the algorithm, since sha256 is used. + IdentifierRegexp = match(`([a-f0-9]{64})`) + + // ShortIdentifierRegexp is the format used to represent a prefix + // of an identifier. A prefix may be used to match a sha256 identifier + // within a list of trusted identifiers. + ShortIdentifierRegexp = match(`([a-f0-9]{6,64})`) + + // anchoredIdentifierRegexp is used to check or match an + // identifier value, anchored at start and end of string. + anchoredIdentifierRegexp = anchored(IdentifierRegexp) + + // anchoredShortIdentifierRegexp is used to check if a value + // is a possible identifier prefix, anchored at start and end + // of string. + anchoredShortIdentifierRegexp = anchored(ShortIdentifierRegexp) +) + +// match compiles the string to a regular expression. +var match = regexp.MustCompile + +// literal compiles s into a literal regular expression, escaping any regexp +// reserved characters. +func literal(s string) *regexp.Regexp { + re := match(regexp.QuoteMeta(s)) + + if _, complete := re.LiteralPrefix(); !complete { + panic("must be a literal") + } + + return re +} + +// expression defines a full expression, where each regular expression must +// follow the previous. +func expression(res ...*regexp.Regexp) *regexp.Regexp { + var s string + for _, re := range res { + s += re.String() + } + + return match(s) +} + +// optional wraps the expression in a non-capturing group and makes the +// production optional. +func optional(res ...*regexp.Regexp) *regexp.Regexp { + return match(group(expression(res...)).String() + `?`) +} + +// repeated wraps the regexp in a non-capturing group to get one or more +// matches. +func repeated(res ...*regexp.Regexp) *regexp.Regexp { + return match(group(expression(res...)).String() + `+`) +} + +// group wraps the regexp in a non-capturing group. +func group(res ...*regexp.Regexp) *regexp.Regexp { + return match(`(?:` + expression(res...).String() + `)`) +} + +// capture wraps the expression in a capturing group. +func capture(res ...*regexp.Regexp) *regexp.Regexp { + return match(`(` + expression(res...).String() + `)`) +} + +// anchored anchors the regular expression by adding start and end delimiters. +func anchored(res ...*regexp.Regexp) *regexp.Regexp { + return match(`^` + expression(res...).String() + `$`) +} diff --git a/vendor/github.com/docker/docker/AUTHORS b/vendor/github.com/docker/docker/AUTHORS new file mode 100644 index 0000000000..0728bfe18f --- /dev/null +++ b/vendor/github.com/docker/docker/AUTHORS @@ -0,0 +1,2372 @@ +# File @generated by hack/generate-authors.sh. DO NOT EDIT. +# This file lists all contributors to the repository. +# See hack/generate-authors.sh to make modifications. + +Aanand Prasad +Aaron Davidson +Aaron Feng +Aaron Hnatiw +Aaron Huslage +Aaron L. Xu +Aaron Lehmann +Aaron Welch +Abel Muiño +Abhijeet Kasurde +Abhinandan Prativadi +Abhinav Ajgaonkar +Abhishek Chanda +Abhishek Sharma +Abin Shahab +Abirdcfly +Ada Mancini +Adam Avilla +Adam Dobrawy +Adam Eijdenberg +Adam Kunk +Adam Miller +Adam Mills +Adam Pointer +Adam Singer +Adam Walz +Adam Williams +Addam Hardy +Aditi Rajagopal +Aditya +Adnan Khan +Adolfo Ochagavía +Adria Casas +Adrian Moisey +Adrian Mouat +Adrian Oprea +Adrien Folie +Adrien Gallouët +Ahmed Kamal +Ahmet Alp Balkan +Aidan Feldman +Aidan Hobson Sayers +AJ Bowen +Ajey Charantimath +ajneu +Akash Gupta +Akhil Mohan +Akihiro Matsushima +Akihiro Suda +Akim Demaille +Akira Koyasu +Akshay Karle +Akshay Moghe +Al Tobey +alambike +Alan Hoyle +Alan Scherger +Alan Thompson +Albert Callarisa +Albert Zhang +Albin Kerouanton +Alec Benson +Alejandro González Hevia +Aleksa Sarai +Aleksandr Chebotov +Aleksandrs Fadins +Alena Prokharchyk +Alessandro Boch +Alessio Biancalana +Alex Chan +Alex Chen +Alex Coventry +Alex Crawford +Alex Ellis +Alex Gaynor +Alex Goodman +Alex Nordlund +Alex Olshansky +Alex Samorukov +Alex Warhawk +Alexander Artemenko +Alexander Boyd +Alexander Larsson +Alexander Midlash +Alexander Morozov +Alexander Polakov +Alexander Shopov +Alexandre Beslic +Alexandre Garnier +Alexandre González +Alexandre Jomin +Alexandru Sfirlogea +Alexei Margasov +Alexey Guskov +Alexey Kotlyarov +Alexey Shamrin +Alexis Ries +Alexis Thomas +Alfred Landrum +Ali Dehghani +Alicia Lauerman +Alihan Demir +Allen Madsen +Allen Sun +almoehi +Alvaro Saurin +Alvin Deng +Alvin Richards +amangoel +Amen Belayneh +Ameya Gawde +Amir Goldstein +Amit Bakshi +Amit Krishnan +Amit Shukla +Amr Gawish +Amy Lindburg +Anand Patil +AnandkumarPatel +Anatoly Borodin +Anca Iordache +Anchal Agrawal +Anda Xu +Anders Janmyr +Andre Dublin <81dublin@gmail.com> +Andre Granovsky +Andrea Denisse Gómez +Andrea Luzzardi +Andrea Turli +Andreas Elvers +Andreas Köhler +Andreas Savvides +Andreas Tiefenthaler +Andrei Gherzan +Andrei Ushakov +Andrei Vagin +Andrew C. Bodine +Andrew Clay Shafer +Andrew Duckworth +Andrew France +Andrew Gerrand +Andrew Guenther +Andrew He +Andrew Hsu +Andrew Kim +Andrew Kuklewicz +Andrew Macgregor +Andrew Macpherson +Andrew Martin +Andrew McDonnell +Andrew Munsell +Andrew Pennebaker +Andrew Po +Andrew Weiss +Andrew Williams +Andrews Medina +Andrey Kolomentsev +Andrey Petrov +Andrey Stolbovsky +André Martins +Andy Chambers +andy diller +Andy Goldstein +Andy Kipp +Andy Lindeman +Andy Rothfusz +Andy Smith +Andy Wilson +Andy Zhang +Anes Hasicic +Angel Velazquez +Anil Belur +Anil Madhavapeddy +Ankit Jain +Ankush Agarwal +Anonmily +Anran Qiao +Anshul Pundir +Anthon van der Neut +Anthony Baire +Anthony Bishopric +Anthony Dahanne +Anthony Sottile +Anton Löfgren +Anton Nikitin +Anton Polonskiy +Anton Tiurin +Antonio Murdaca +Antonis Kalipetis +Antony Messerli +Anuj Bahuguna +Anuj Varma +Anusha Ragunathan +Anyu Wang +apocas +Arash Deshmeh +ArikaChen +Arko Dasgupta +Arnaud Lefebvre +Arnaud Porterie +Arnaud Rebillout +Artem Khramov +Arthur Barr +Arthur Gautier +Artur Meyster +Arun Gupta +Asad Saeeduddin +Asbjørn Enge +Austin Vazquez +averagehuman +Avi Das +Avi Kivity +Avi Miller +Avi Vaid +ayoshitake +Azat Khuyiyakhmetov +Bao Yonglei +Bardia Keyoumarsi +Barnaby Gray +Barry Allard +Bartłomiej Piotrowski +Bastiaan Bakker +Bastien Pascard +bdevloed +Bearice Ren +Ben Bonnefoy +Ben Firshman +Ben Golub +Ben Gould +Ben Hall +Ben Langfeld +Ben Sargent +Ben Severson +Ben Toews +Ben Wiklund +Benjamin Atkin +Benjamin Baker +Benjamin Boudreau +Benjamin Böhmke +Benjamin Yolken +Benny Ng +Benoit Chesneau +Bernerd Schaefer +Bernhard M. Wiedemann +Bert Goethals +Bertrand Roussel +Bevisy Zhang +Bharath Thiruveedula +Bhiraj Butala +Bhumika Bayani +Bilal Amarni +Bill Wang +Billy Ridgway +Bily Zhang +Bin Liu +Bingshen Wang +Bjorn Neergaard +Blake Geno +Boaz Shuster +bobby abbott +Bojun Zhu +Boqin Qin +Boris Pruessmann +Boshi Lian +Bouke Haarsma +Boyd Hemphill +boynux +Bradley Cicenas +Bradley Wright +Brandon Liu +Brandon Philips +Brandon Rhodes +Brendan Dixon +Brent Salisbury +Brett Higgins +Brett Kochendorfer +Brett Milford +Brett Randall +Brian (bex) Exelbierd +Brian Bland +Brian DeHamer +Brian Dorsey +Brian Flad +Brian Goff +Brian McCallister +Brian Olsen +Brian Schwind +Brian Shumate +Brian Torres-Gil +Brian Trump +Brice Jaglin +Briehan Lombaard +Brielle Broder +Bruno Bigras +Bruno Binet +Bruno Gazzera +Bruno Renié +Bruno Tavares +Bryan Bess +Bryan Boreham +Bryan Matsuo +Bryan Murphy +Burke Libbey +Byung Kang +Caleb Spare +Calen Pennington +Cameron Boehmer +Cameron Sparr +Cameron Spear +Campbell Allen +Candid Dauth +Cao Weiwei +Carl Henrik Lunde +Carl Loa Odin +Carl X. Su +Carlo Mion +Carlos Alexandro Becker +Carlos de Paula +Carlos Sanchez +Carol Fager-Higgins +Cary +Casey Bisson +Catalin Pirvu +Ce Gao +Cedric Davies +Cezar Sa Espinola +Chad Swenson +Chance Zibolski +Chander Govindarajan +Chanhun Jeong +Chao Wang +Charles Chan +Charles Hooper +Charles Law +Charles Lindsay +Charles Merriam +Charles Sarrazin +Charles Smith +Charlie Drage +Charlie Lewis +Chase Bolt +ChaYoung You +Chee Hau Lim +Chen Chao +Chen Chuanliang +Chen Hanxiao +Chen Min +Chen Mingjie +Chen Qiu +Cheng-mean Liu +Chengfei Shang +Chengguang Xu +Chenyang Yan +chenyuzhu +Chetan Birajdar +Chewey +Chia-liang Kao +chli +Cholerae Hu +Chris Alfonso +Chris Armstrong +Chris Dias +Chris Dituri +Chris Fordham +Chris Gavin +Chris Gibson +Chris Khoo +Chris Kreussling (Flatbush Gardener) +Chris McKinnel +Chris McKinnel +Chris Price +Chris Seto +Chris Snow +Chris St. Pierre +Chris Stivers +Chris Swan +Chris Telfer +Chris Wahl +Chris Weyl +Chris White +Christian Becker +Christian Berendt +Christian Brauner +Christian Böhme +Christian Muehlhaeuser +Christian Persson +Christian Rotzoll +Christian Simon +Christian Stefanescu +Christoph Ziebuhr +Christophe Mehay +Christophe Troestler +Christophe Vidal +Christopher Biscardi +Christopher Crone +Christopher Currie +Christopher Jones +Christopher Latham +Christopher Rigor +Christy Norman +Chun Chen +Ciro S. Costa +Clayton Coleman +Clint Armstrong +Clinton Kitson +clubby789 +Cody Roseborough +Coenraad Loubser +Colin Dunklau +Colin Hebert +Colin Panisset +Colin Rice +Colin Walters +Collin Guarino +Colm Hally +companycy +Conor Evans +Corbin Coleman +Corey Farrell +Cory Forsyth +Cory Snider +cressie176 +Cristian Ariza +Cristian Staretu +cristiano balducci +Cristina Yenyxe Gonzalez Garcia +Cruceru Calin-Cristian +CUI Wei +cuishuang +Cuong Manh Le +Cyprian Gracz +Cyril F +Da McGrady +Daan van Berkel +Daehyeok Mun +Dafydd Crosby +dalanlan +Damian Smyth +Damien Nadé +Damien Nozay +Damjan Georgievski +Dan Anolik +Dan Buch +Dan Cotora +Dan Feldman +Dan Griffin +Dan Hirsch +Dan Keder +Dan Levy +Dan McPherson +Dan Plamadeala +Dan Stine +Dan Williams +Dani Hodovic +Dani Louca +Daniel Antlinger +Daniel Black +Daniel Dao +Daniel Exner +Daniel Farrell +Daniel Garcia +Daniel Gasienica +Daniel Grunwell +Daniel Helfand +Daniel Hiltgen +Daniel J Walsh +Daniel Menet +Daniel Mizyrycki +Daniel Nephin +Daniel Norberg +Daniel Nordberg +Daniel P. Berrangé +Daniel Robinson +Daniel S +Daniel Sweet +Daniel Von Fange +Daniel Watkins +Daniel X Moore +Daniel YC Lin +Daniel Zhang +Daniele Rondina +Danny Berger +Danny Milosavljevic +Danny Yates +Danyal Khaliq +Darren Coxall +Darren Shepherd +Darren Stahl +Dattatraya Kumbhar +Davanum Srinivas +Dave Barboza +Dave Goodchild +Dave Henderson +Dave MacDonald +Dave Tucker +David Anderson +David Bellotti +David Calavera +David Chung +David Corking +David Cramer +David Currie +David Davis +David Dooling +David Gageot +David Gebler +David Glasser +David Lawrence +David Lechner +David M. Karr +David Mackey +David Manouchehri +David Mat +David Mcanulty +David McKay +David O'Rourke +David P Hilton +David Pelaez +David R. Jenni +David Röthlisberger +David Sheets +David Sissitka +David Trott +David Wang <00107082@163.com> +David Williamson +David Xia +David Young +Davide Ceretti +Dawn Chen +dbdd +dcylabs +Debayan De +Deborah Gertrude Digges +deed02392 +Deep Debroy +Deng Guangxing +Deni Bertovic +Denis Defreyne +Denis Gladkikh +Denis Ollier +Dennis Chen +Dennis Chen +Dennis Docter +Derek +Derek +Derek Ch +Derek McGowan +Deric Crago +Deshi Xiao +Devon Estes +Devvyn Murphy +Dharmit Shah +Dhawal Yogesh Bhanushali +Dhilip Kumars +Diego Romero +Diego Siqueira +Dieter Reuter +Dillon Dixon +Dima Stopel +Dimitri John Ledkov +Dimitris Mandalidis +Dimitris Rozakis +Dimitry Andric +Dinesh Subhraveti +Ding Fei +dingwei +Diogo Monica +DiuDiugirl +Djibril Koné +Djordje Lukic +dkumor +Dmitri Logvinenko +Dmitri Shuralyov +Dmitry Demeshchuk +Dmitry Gusev +Dmitry Kononenko +Dmitry Sharshakov +Dmitry Shyshkin +Dmitry Smirnov +Dmitry V. Krivenok +Dmitry Vorobev +Dmytro Iakovliev +docker-unir[bot] +Dolph Mathews +Dominic Tubach +Dominic Yin +Dominik Dingel +Dominik Finkbeiner +Dominik Honnef +Don Kirkby +Don Kjer +Don Spaulding +Donald Huang +Dong Chen +Donghwa Kim +Donovan Jones +Doron Podoleanu +Doug Davis +Doug MacEachern +Doug Tangren +Douglas Curtis +Dr Nic Williams +dragon788 +Dražen Lučanin +Drew Erny +Drew Hubl +Dustin Sallings +Ed Costello +Edmund Wagner +Eiichi Tsukata +Eike Herzbach +Eivin Giske Skaaren +Eivind Uggedal +Elan Ruusamäe +Elango Sivanandam +Elena Morozova +Eli Uriegas +Elias Faxö +Elias Koromilas +Elias Probst +Elijah Zupancic +eluck +Elvir Kuric +Emil Davtyan +Emil Hernvall +Emily Maier +Emily Rose +Emir Ozer +Eng Zer Jun +Enguerran +Eohyung Lee +epeterso +Eric Barch +Eric Curtin +Eric G. Noriega +Eric Hanchrow +Eric Lee +Eric Mountain +Eric Myhre +Eric Paris +Eric Rafaloff +Eric Rosenberg +Eric Sage +Eric Soderstrom +Eric Yang +Eric-Olivier Lamey +Erica Windisch +Erich Cordoba +Erik Bray +Erik Dubbelboer +Erik Hollensbe +Erik Inge Bolsø +Erik Kristensen +Erik Sipsma +Erik St. Martin +Erik Weathers +Erno Hopearuoho +Erwin van der Koogh +Espen Suenson +Ethan Bell +Ethan Mosbaugh +Euan Harris +Euan Kemp +Eugen Krizo +Eugene Yakubovich +Evan Allrich +Evan Carmi +Evan Hazlett +Evan Krall +Evan Phoenix +Evan Wies +Evelyn Xu +Everett Toews +Evgeniy Makhrov +Evgeny Shmarnev +Evgeny Vereshchagin +Ewa Czechowska +Eystein Måløy Stenberg +ezbercih +Ezra Silvera +Fabian Kramm +Fabian Lauer +Fabian Raetz +Fabiano Rosas +Fabio Falci +Fabio Kung +Fabio Rapposelli +Fabio Rehm +Fabrizio Regini +Fabrizio Soppelsa +Faiz Khan +falmp +Fangming Fang +Fangyuan Gao <21551127@zju.edu.cn> +fanjiyun +Fareed Dudhia +Fathi Boudra +Federico Gimenez +Felipe Oliveira +Felipe Ruhland +Felix Abecassis +Felix Geisendörfer +Felix Hupfeld +Felix Rabe +Felix Ruess +Felix Schindler +Feng Yan +Fengtu Wang +Ferenc Szabo +Fernando +Fero Volar +Feroz Salam +Ferran Rodenas +Filipe Brandenburger +Filipe Oliveira +Flavio Castelli +Flavio Crisciani +Florian +Florian Klein +Florian Maier +Florian Noeding +Florian Schmaus +Florian Weingarten +Florin Asavoaie +Florin Patan +fonglh +Foysal Iqbal +Francesc Campoy +Francesco Degrassi +Francesco Mari +Francis Chuang +Francisco Carriedo +Francisco Souza +Frank Groeneveld +Frank Herrmann +Frank Macreery +Frank Rosquin +Frank Yang +Fred Lifton +Frederick F. Kautz IV +Frederico F. de Oliveira +Frederik Loeffert +Frederik Nordahl Jul Sabroe +Freek Kalter +Frieder Bluemle +frobnicaty <92033765+frobnicaty@users.noreply.github.com> +Frédéric Dalleau +Fu JinLin +Félix Baylac-Jacqué +Félix Cantournet +Gabe Rosenhouse +Gabor Nagy +Gabriel Goller +Gabriel L. Somlo +Gabriel Linder +Gabriel Monroy +Gabriel Nicolas Avellaneda +Gaetan de Villele +Galen Sampson +Gang Qiao +Gareth Rushgrove +Garrett Barboza +Gary Schaetz +Gaurav +Gaurav Singh +Gaël PORTAY +Genki Takiuchi +GennadySpb +Geoff Levand +Geoffrey Bachelet +Geon Kim +George Kontridze +George MacRorie +George Xie +Georgi Hristozov +Georgy Yakovlev +Gereon Frey +German DZ +Gert van Valkenhoef +Gerwim Feiken +Ghislain Bourgeois +Giampaolo Mancini +Gianluca Borello +Gildas Cuisinier +Giovan Isa Musthofa +gissehel +Giuseppe Mazzotta +Giuseppe Scrivano +Gleb Fotengauer-Malinovskiy +Gleb M Borisov +Glyn Normington +GoBella +Goffert van Gool +Goldwyn Rodrigues +Gopikannan Venugopalsamy +Gosuke Miyashita +Gou Rao +Govinda Fichtner +Grant Millar +Grant Reaber +Graydon Hoare +Greg Fausak +Greg Pflaum +Greg Stephens +Greg Thornton +Grzegorz Jaśkiewicz +Guilhem Lettron +Guilherme Salgado +Guillaume Dufour +Guillaume J. Charmes +Gunadhya S. <6939749+gunadhya@users.noreply.github.com> +Guoqiang QI +guoxiuyan +Guri +Gurjeet Singh +Guruprasad +Gustav Sinder +gwx296173 +Günter Zöchbauer +Haichao Yang +haikuoliu +haining.cao +Hakan Özler +Hamish Hutchings +Hannes Ljungberg +Hans Kristian Flaatten +Hans Rødtang +Hao Shu Wei +Hao Zhang <21521210@zju.edu.cn> +Harald Albers +Harald Niesche +Harley Laue +Harold Cooper +Harrison Turton +Harry Zhang +Harshal Patil +Harshal Patil +He Simei +He Xiaoxi +He Xin +heartlock <21521209@zju.edu.cn> +Hector Castro +Helen Xie +Henning Sprang +Hiroshi Hatake +Hiroyuki Sasagawa +Hobofan +Hollie Teal +Hong Xu +Hongbin Lu +Hongxu Jia +Honza Pokorny +Hsing-Hui Hsu +hsinko <21551195@zju.edu.cn> +Hu Keping +Hu Tao +HuanHuan Ye +Huanzhong Zhang +Huayi Zhang +Hugo Barrera +Hugo Duncan +Hugo Marisco <0x6875676f@gmail.com> +Hui Kang +Hunter Blanks +huqun +Huu Nguyen +Hyeongkyu Lee +Hyzhou Zhy +Iago López Galeiras +Ian Bishop +Ian Bull +Ian Calvert +Ian Campbell +Ian Chen +Ian Lee +Ian Main +Ian Philpot +Ian Truslove +Iavael +Icaro Seara +Ignacio Capurro +Igor Dolzhikov +Igor Karpovich +Iliana Weller +Ilkka Laukkanen +Illo Abdulrahim +Ilya Dmitrichenko +Ilya Gusev +Ilya Khlopotov +imre Fitos +inglesp +Ingo Gottwald +Innovimax +Isaac Dupree +Isabel Jimenez +Isaiah Grace +Isao Jonas +Iskander Sharipov +Ivan Babrou +Ivan Fraixedes +Ivan Grcic +Ivan Markin +J Bruni +J. Nunn +Jack Danger Canty +Jack Laxson +Jacob Atzen +Jacob Edelman +Jacob Tomlinson +Jacob Vallejo +Jacob Wen +Jaime Cepeda +Jaivish Kothari +Jake Champlin +Jake Moshenko +Jake Sanders +Jakub Drahos +Jakub Guzik +James Allen +James Carey +James Carr +James DeFelice +James Harrison Fisher +James Kyburz +James Kyle +James Lal +James Mills +James Nesbitt +James Nugent +James Sanders +James Turnbull +James Watkins-Harvey +Jamie Hannaford +Jamshid Afshar +Jan Breig +Jan Chren +Jan Götte +Jan Keromnes +Jan Koprowski +Jan Pazdziora +Jan Toebes +Jan-Gerd Tenberge +Jan-Jaap Driessen +Jana Radhakrishnan +Jannick Fahlbusch +Januar Wayong +Jared Biel +Jared Hocutt +Jaroslaw Zabiello +Jasmine Hegman +Jason A. Donenfeld +Jason Divock +Jason Giedymin +Jason Green +Jason Hall +Jason Heiss +Jason Livesay +Jason McVetta +Jason Plum +Jason Shepherd +Jason Smith +Jason Sommer +Jason Stangroome +Javier Bassi +jaxgeller +Jay +Jay Kamat +Jay Lim +Jean Rouge +Jean-Baptiste Barth +Jean-Baptiste Dalido +Jean-Christophe Berthon +Jean-Paul Calderone +Jean-Pierre Huynh +Jean-Tiare Le Bigot +Jeeva S. Chelladhurai +Jeff Anderson +Jeff Hajewski +Jeff Johnston +Jeff Lindsay +Jeff Mickey +Jeff Minard +Jeff Nickoloff +Jeff Silberman +Jeff Welch +Jeff Zvier +Jeffrey Bolle +Jeffrey Morgan +Jeffrey van Gogh +Jenny Gebske +Jeremy Chambers +Jeremy Grosser +Jeremy Huntwork +Jeremy Price +Jeremy Qian +Jeremy Unruh +Jeremy Yallop +Jeroen Franse +Jeroen Jacobs +Jesse Dearing +Jesse Dubay +Jessica Frazelle +Jezeniel Zapanta +Jhon Honce +Ji.Zhilong +Jian Liao +Jian Zhang +Jiang Jinyang +Jianyong Wu +Jie Luo +Jie Ma +Jihyun Hwang +Jilles Oldenbeuving +Jim Alateras +Jim Carroll +Jim Ehrismann +Jim Galasyn +Jim Lin +Jim Minter +Jim Perrin +Jimmy Cuadra +Jimmy Puckett +Jimmy Song +Jinsoo Park +Jintao Zhang +Jiri Appl +Jiri Popelka +Jiuyue Ma +Jiří Župka +Joakim Roubert +Joao Fernandes +Joao Trindade +Joe Beda +Joe Doliner +Joe Ferguson +Joe Gordon +Joe Shaw +Joe Van Dyk +Joel Friedly +Joel Handwell +Joel Hansson +Joel Wurtz +Joey Geiger +Joey Geiger +Joey Gibson +Joffrey F +Johan Euphrosine +Johan Rydberg +Johanan Lieberman +Johannes 'fish' Ziemke +John Costa +John Feminella +John Gardiner Myers +John Gossman +John Harris +John Howard +John Laswell +John Maguire +John Mulhausen +John OBrien III +John Starks +John Stephens +John Tims +John V. Martinez +John Warwick +John Willis +Jon Johnson +Jon Surrell +Jon Wedaman +Jonas Dohse +Jonas Heinrich +Jonas Pfenniger +Jonathan A. Schweder +Jonathan A. Sternberg +Jonathan Boulle +Jonathan Camp +Jonathan Choy +Jonathan Dowland +Jonathan Lebon +Jonathan Lomas +Jonathan McCrohan +Jonathan Mueller +Jonathan Pares +Jonathan Rudenberg +Jonathan Stoppani +Jonh Wendell +Joni Sar +Joost Cassee +Jordan Arentsen +Jordan Jennings +Jordan Sissel +Jordi Massaguer Pla +Jorge Marin +Jorit Kleine-Möllhoff +Jose Diaz-Gonzalez +Joseph Anthony Pasquale Holsten +Joseph Hager +Joseph Kern +Joseph Rothrock +Josh +Josh Bodah +Josh Bonczkowski +Josh Chorlton +Josh Eveleth +Josh Hawn +Josh Horwitz +Josh Poimboeuf +Josh Soref +Josh Wilson +Josiah Kiehl +José Tomás Albornoz +Joyce Jang +JP +Julian Taylor +Julien Barbier +Julien Bisconti +Julien Bordellier +Julien Dubois +Julien Kassar +Julien Maitrehenry +Julien Pervillé +Julien Pivotto +Julio Guerra +Julio Montes +Jun Du +Jun-Ru Chang +junxu +Jussi Nummelin +Justas Brazauskas +Justen Martin +Justin Cormack +Justin Force +Justin Keller <85903732+jk-vb@users.noreply.github.com> +Justin Menga +Justin Plock +Justin Simonelis +Justin Terry +Justyn Temme +Jyrki Puttonen +Jérémy Leherpeur +Jérôme Petazzoni +Jörg Thalheim +K. Heller +Kai Blin +Kai Qiang Wu (Kennan) +Kaijie Chen +Kamil Domański +Kamjar Gerami +Kanstantsin Shautsou +Kara Alexandra +Karan Lyons +Kareem Khazem +kargakis +Karl Grzeszczak +Karol Duleba +Karthik Karanth +Karthik Nayak +Kasper Fabæch Brandt +Kate Heddleston +Katie McLaughlin +Kato Kazuyoshi +Katrina Owen +Kawsar Saiyeed +Kay Yan +kayrus +Kazuhiro Sera +Kazuyoshi Kato +Ke Li +Ke Xu +Kei Ohmura +Keith Hudgins +Keli Hu +Ken Cochrane +Ken Herner +Ken ICHIKAWA +Ken Reese +Kenfe-Mickaël Laventure +Kenjiro Nakayama +Kent Johnson +Kenta Tada +Kevin "qwazerty" Houdebert +Kevin Alvarez +Kevin Burke +Kevin Clark +Kevin Feyrer +Kevin J. Lynagh +Kevin Jing Qiu +Kevin Kern +Kevin Menard +Kevin Meredith +Kevin P. Kucharczyk +Kevin Parsons +Kevin Richardson +Kevin Shi +Kevin Wallace +Kevin Yap +Keyvan Fatehi +kies +Kim BKC Carlbacker +Kim Eik +Kimbro Staken +Kir Kolyshkin +Kiran Gangadharan +Kirill SIbirev +knappe +Kohei Tsuruta +Koichi Shiraishi +Konrad Kleine +Konrad Ponichtera +Konstantin Gribov +Konstantin L +Konstantin Pelykh +Kostadin Plachkov +Krasi Georgiev +Krasimir Georgiev +Kris-Mikael Krister +Kristian Haugene +Kristina Zabunova +Krystian Wojcicki +Kunal Kushwaha +Kunal Tyagi +Kyle Conroy +Kyle Linden +Kyle Squizzato +Kyle Wuolle +kyu +Lachlan Coote +Lai Jiangshan +Lajos Papp +Lakshan Perera +Lalatendu Mohanty +Lance Chen +Lance Kinley +Lars Butler +Lars Kellogg-Stedman +Lars R. Damerow +Lars-Magnus Skog +Laszlo Meszaros +Laura Frank +Laurent Bernaille +Laurent Erignoux +Laurie Voss +Leandro Siqueira +Lee Calcote +Lee Chao <932819864@qq.com> +Lee, Meng-Han +Lei Gong +Lei Jitang +Leiiwang +Len Weincier +Lennie +Leo Gallucci +Leonardo Nodari +Leonardo Taccari +Leszek Kowalski +Levi Blackstone +Levi Gross +Levi Harrison +Lewis Daly +Lewis Marshall +Lewis Peckover +Li Yi +Liam Macgillavry +Liana Lo +Liang Mingqiang +Liang-Chi Hsieh +liangwei +Liao Qingwei +Lifubang +Lihua Tang +Lily Guo +limeidan +Lin Lu +LingFaKe +Linus Heckemann +Liran Tal +Liron Levin +Liu Bo +Liu Hua +liwenqi +lixiaobing10051267 +Liz Zhang +LIZAO LI +Lizzie Dixon <_@lizzie.io> +Lloyd Dewolf +Lokesh Mandvekar +longliqiang88 <394564827@qq.com> +Lorenz Leutgeb +Lorenzo Fontana +Lotus Fenn +Louis Delossantos +Louis Opter +Luca Favatella +Luca Marturana +Luca Orlandi +Luca-Bogdan Grigorescu +Lucas Chan +Lucas Chi +Lucas Molas +Lucas Silvestre +Luciano Mores +Luis Henrique Mulinari +Luis Martínez de Bartolomé Izquierdo +Luiz Svoboda +Lukas Heeren +Lukas Waslowski +lukaspustina +Lukasz Zajaczkowski +Luke Marsden +Lyn +Lynda O'Leary +Lénaïc Huard +Ma Müller +Ma Shimiao +Mabin +Madhan Raj Mookkandy +Madhav Puri +Madhu Venugopal +Mageee +Mahesh Tiyyagura +malnick +Malte Janduda +Manfred Touron +Manfred Zabarauskas +Manjunath A Kumatagi +Mansi Nahar +Manuel Meurer +Manuel Rüger +Manuel Woelker +mapk0y +Marc Abramowitz +Marc Kuo +Marc Tamsky +Marcel Edmund Franke +Marcelo Horacio Fortino +Marcelo Salazar +Marco Hennings +Marcus Cobden +Marcus Farkas +Marcus Linke +Marcus Martins +Marcus Ramberg +Marek Goldmann +Marian Marinov +Marianna Tessel +Mario Loriedo +Marius Gundersen +Marius Sturm +Marius Voila +Mark Allen +Mark Feit +Mark Jeromin +Mark McGranaghan +Mark McKinstry +Mark Milstein +Mark Oates +Mark Parker +Mark Vainomaa +Mark West +Markan Patel +Marko Mikulicic +Marko Tibold +Markus Fix +Markus Kortlang +Martijn Dwars +Martijn van Oosterhout +Martin Braun +Martin Dojcak +Martin Honermeyer +Martin Kelly +Martin Mosegaard Amdisen +Martin Muzatko +Martin Redmond +Maru Newby +Mary Anthony +Masahito Zembutsu +Masato Ohba +Masayuki Morita +Mason Malone +Mateusz Sulima +Mathias Monnerville +Mathieu Champlon +Mathieu Le Marec - Pasquet +Mathieu Parent +Mathieu Paturel +Matt Apperson +Matt Bachmann +Matt Bajor +Matt Bentley +Matt Haggard +Matt Hoyle +Matt McCormick +Matt Moore +Matt Morrison <3maven@gmail.com> +Matt Richardson +Matt Rickard +Matt Robenolt +Matt Schurenko +Matt Williams +Matthew Heon +Matthew Lapworth +Matthew Mayer +Matthew Mosesohn +Matthew Mueller +Matthew Riley +Matthias Klumpp +Matthias Kühnle +Matthias Rampke +Matthieu Fronton +Matthieu Hauglustaine +Mattias Jernberg +Mauricio Garavaglia +mauriyouth +Max Harmathy +Max Shytikov +Max Timchenko +Maxim Fedchyshyn +Maxim Ivanov +Maxim Kulkin +Maxim Treskin +Maxime Petazzoni +Maximiliano Maccanti +Maxwell +Meaglith Ma +meejah +Megan Kostick +Mehul Kar +Mei ChunTao +Mengdi Gao +Menghui Chen +Mert Yazıcıoğlu +mgniu +Micah Zoltu +Michael A. Smith +Michael Beskin +Michael Bridgen +Michael Brown +Michael Chiang +Michael Crosby +Michael Currie +Michael Friis +Michael Gorsuch +Michael Grauer +Michael Holzheu +Michael Hudson-Doyle +Michael Huettermann +Michael Irwin +Michael Kuehn +Michael Käufl +Michael Neale +Michael Nussbaum +Michael Prokop +Michael Scharf +Michael Spetsiotis +Michael Stapelberg +Michael Steinert +Michael Thies +Michael Weidmann +Michael West +Michael Zhao +Michal Fojtik +Michal Gebauer +Michal Jemala +Michal Kostrzewa +Michal Minář +Michal Rostecki +Michal Wieczorek +Michaël Pailloncy +Michał Czeraszkiewicz +Michał Gryko +Michał Kosek +Michiel de Jong +Mickaël Fortunato +Mickaël Remars +Miguel Angel Fernández +Miguel Morales +Miguel Perez +Mihai Borobocea +Mihuleacc Sergiu +Mikael Davranche +Mike Brown +Mike Bush +Mike Casas +Mike Chelen +Mike Danese +Mike Dillon +Mike Dougherty +Mike Estes +Mike Gaffney +Mike Goelzer +Mike Leone +Mike Lundy +Mike MacCana +Mike Naberezny +Mike Snitzer +mikelinjie <294893458@qq.com> +Mikhail Sobolev +Miklos Szegedi +Milas Bowman +Milind Chawre +Miloslav Trmač +mingqing +Mingzhen Feng +Misty Stanley-Jones +Mitch Capper +Mizuki Urushida +mlarcher +Mohammad Banikazemi +Mohammad Nasirifar +Mohammed Aaqib Ansari +Mohit Soni +Moorthy RS +Morgan Bauer +Morgante Pell +Morgy93 +Morten Siebuhr +Morton Fox +Moysés Borges +mrfly +Mrunal Patel +Muayyad Alsadi +Muhammad Zohaib Aslam +Mustafa Akın +Muthukumar R +Máximo Cuadros +Médi-Rémi Hashim +Nace Oroz +Nahum Shalman +Nakul Pathak +Nalin Dahyabhai +Nan Monnand Deng +Naoki Orii +Natalie Parker +Natanael Copa +Natasha Jarus +Nate Brennand +Nate Eagleson +Nate Jones +Nathan Carlson +Nathan Herald +Nathan Hsieh +Nathan Kleyn +Nathan LeClaire +Nathan McCauley +Nathan Williams +Naveed Jamil +Neal McBurnett +Neil Horman +Neil Peterson +Nelson Chen +Neyazul Haque +Nghia Tran +Niall O'Higgins +Nicholas E. Rabenau +Nick Adcock +Nick DeCoursin +Nick Irvine +Nick Neisen +Nick Parker +Nick Payne +Nick Russo +Nick Stenning +Nick Stinemates +Nick Wood +NickrenREN +Nicola Kabar +Nicolas Borboën +Nicolas De Loof +Nicolas Dudebout +Nicolas Goy +Nicolas Kaiser +Nicolas Sterchele +Nicolas V Castet +Nicolás Hock Isaza +Niel Drummond +Nigel Poulton +Nik Nyby +Nikhil Chawla +NikolaMandic +Nikolas Garofil +Nikolay Edigaryev +Nikolay Milovanov +Nirmal Mehta +Nishant Totla +NIWA Hideyuki +Noah Meyerhans +Noah Treuhaft +NobodyOnSE +noducks +Nolan Darilek +Noriki Nakamura +nponeccop +Nurahmadie +Nuutti Kotivuori +nzwsch +O.S. Tezer +objectified +Odin Ugedal +Oguz Bilgic +Oh Jinkyun +Ohad Schneider +ohmystack +Ole Reifschneider +Oliver Neal +Oliver Reason +Olivier Gambier +Olle Jonsson +Olli Janatuinen +Olly Pomeroy +Omri Shiv +Onur Filiz +Oriol Francès +Oscar Bonilla <6f6231@gmail.com> +Oskar Niburski +Otto Kekäläinen +Ouyang Liduo +Ovidio Mallo +Panagiotis Moustafellos +Paolo G. Giarrusso +Pascal +Pascal Bach +Pascal Borreli +Pascal Hartig +Patrick Böänziger +Patrick Devine +Patrick Haas +Patrick Hemmer +Patrick Stapleton +Patrik Cyvoct +pattichen +Paul "TBBle" Hampson +Paul +paul +Paul Annesley +Paul Bellamy +Paul Bowsher +Paul Furtado +Paul Hammond +Paul Jimenez +Paul Kehrer +Paul Lietar +Paul Liljenberg +Paul Morie +Paul Nasrat +Paul Weaver +Paulo Gomes +Paulo Ribeiro +Pavel Lobashov +Pavel Matěja +Pavel Pletenev +Pavel Pospisil +Pavel Sutyrin +Pavel Tikhomirov +Pavlos Ratis +Pavol Vargovcik +Pawel Konczalski +Paweł Gronowski +Peeyush Gupta +Peggy Li +Pei Su +Peng Tao +Penghan Wang +Per Weijnitz +perhapszzy@sina.com +Pete Woods +Peter Bourgon +Peter Braden +Peter Bücker +Peter Choi +Peter Dave Hello +Peter Edge +Peter Ericson +Peter Esbensen +Peter Jaffe +Peter Kang +Peter Malmgren +Peter Salvatore +Peter Volpe +Peter Waller +Petr Švihlík +Petros Angelatos +Phil +Phil Estes +Phil Sphicas +Phil Spitler +Philip Alexander Etling +Philip Monroe +Philipp Gillé +Philipp Wahala +Philipp Weissensteiner +Phillip Alexander +phineas +pidster +Piergiuliano Bossi +Pierre +Pierre Carrier +Pierre Dal-Pra +Pierre Wacrenier +Pierre-Alain RIVIERE +Piotr Bogdan +Piotr Karbowski +Porjo +Poul Kjeldager Sørensen +Pradeep Chhetri +Pradip Dhara +Pradipta Kr. Banerjee +Prasanna Gautam +Pratik Karki +Prayag Verma +Priya Wadhwa +Projjol Banerji +Przemek Hejman +Puneet Pruthi +Pure White +pysqz +Qiang Huang +Qin TianHuan +Qinglan Peng +Quan Tian +qudongfang +Quentin Brossard +Quentin Perez +Quentin Tayssier +r0n22 +Radostin Stoyanov +Rafal Jeczalik +Rafe Colton +Raghavendra K T +Raghuram Devarakonda +Raja Sami +Rajat Pandit +Rajdeep Dua +Ralf Sippl +Ralle +Ralph Bean +Ramkumar Ramachandra +Ramon Brooker +Ramon van Alteren +RaviTeja Pothana +Ray Tsang +ReadmeCritic +realityone +Recursive Madman +Reficul +Regan McCooey +Remi Rampin +Remy Suen +Renato Riccieri Santos Zannon +Renaud Gaubert +Rhys Hiltner +Ri Xu +Ricardo N Feliciano +Rich Horwood +Rich Moyse +Rich Seymour +Richard Burnison +Richard Harvey +Richard Mathie +Richard Metzler +Richard Scothern +Richo Healey +Rick Bradley +Rick van de Loo +Rick Wieman +Rik Nijessen +Riku Voipio +Riley Guerin +Ritesh H Shukla +Riyaz Faizullabhoy +Rob Cowsill <42620235+rcowsill@users.noreply.github.com> +Rob Gulewich +Rob Vesse +Robert Bachmann +Robert Bittle +Robert Obryk +Robert Schneider +Robert Shade +Robert Stern +Robert Terhaar +Robert Wallis +Robert Wang +Roberto G. Hashioka +Roberto Muñoz Fernández +Robin Naundorf +Robin Schneider +Robin Speekenbrink +Robin Thoni +robpc +Rodolfo Carvalho +Rodrigo Campos +Rodrigo Vaz +Roel Van Nyen +Roger Peppe +Rohit Jnagal +Rohit Kadam +Rohit Kapur +Rojin George +Roland Huß +Roland Kammerer +Roland Moriz +Roma Sokolov +Roman Dudin +Roman Mazur +Roman Strashkin +Roman Volosatovs +Roman Zabaluev +Ron Smits +Ron Williams +Rong Gao +Rong Zhang +Rongxiang Song +Rony Weng +root +root +root +root +Rory Hunter +Rory McCune +Ross Boucher +Rovanion Luckey +Royce Remer +Rozhnov Alexandr +Rudolph Gottesheim +Rui Cao +Rui Lopes +Ruilin Li +Runshen Zhu +Russ Magee +Ryan Abrams +Ryan Anderson +Ryan Aslett +Ryan Barry +Ryan Belgrave +Ryan Campbell +Ryan Detzel +Ryan Fowler +Ryan Liu +Ryan McLaughlin +Ryan O'Donnell +Ryan Seto +Ryan Shea +Ryan Simmen +Ryan Stelly +Ryan Thomas +Ryan Trauntvein +Ryan Wallner +Ryan Zhang +ryancooper7 +RyanDeng +Ryo Nakao +Ryoga Saito +Rémy Greinhofer +s. rannou +Sabin Basyal +Sachin Joshi +Sagar Hani +Sainath Grandhi +Sakeven Jiang +Salahuddin Khan +Sally O'Malley +Sam Abed +Sam Alba +Sam Bailey +Sam J Sharpe +Sam Neirinck +Sam Reis +Sam Rijs +Sam Whited +Sambuddha Basu +Sami Wagiaalla +Samuel Andaya +Samuel Dion-Girardeau +Samuel Karp +Samuel PHAN +sanchayanghosh +Sandeep Bansal +Sankar சங்கர் +Sanket Saurav +Santhosh Manohar +sapphiredev +Sargun Dhillon +Sascha Andres +Sascha Grunert +SataQiu +Satnam Singh +Satoshi Amemiya +Satoshi Tagomori +Scott Bessler +Scott Collier +Scott Johnston +Scott Percival +Scott Stamp +Scott Walls +sdreyesg +Sean Christopherson +Sean Cronin +Sean Lee +Sean McIntyre +Sean OMeara +Sean P. Kane +Sean Rodman +Sebastiaan van Steenis +Sebastiaan van Stijn +Sebastian Höffner +Sebastian Radloff +Sebastien Goasguen +Senthil Kumar Selvaraj +Senthil Kumaran +SeongJae Park +Seongyeol Lim +Serge Hallyn +Sergey Alekseev +Sergey Evstifeev +Sergii Kabashniuk +Sergio Lopez +Serhat Gülçiçek +SeungUkLee +Sevki Hasirci +Shane Canon +Shane da Silva +Shaun Kaasten +shaunol +Shawn Landden +Shawn Siefkas +shawnhe +Shayan Pooya +Shayne Wang +Shekhar Gulati +Sheng Yang +Shengbo Song +Shengjing Zhu +Shev Yan +Shih-Yuan Lee +Shihao Xia +Shijiang Wei +Shijun Qin +Shishir Mahajan +Shoubhik Bose +Shourya Sarcar +Shu-Wai Chow +shuai-z +Shukui Yang +Sian Lerk Lau +Siarhei Rasiukevich +Sidhartha Mani +sidharthamani +Silas Sewell +Silvan Jegen +Simão Reis +Simon Barendse +Simon Eskildsen +Simon Ferquel +Simon Leinen +Simon Menke +Simon Taranto +Simon Vikstrom +Sindhu S +Sjoerd Langkemper +skanehira +Smark Meng +Solganik Alexander +Solomon Hykes +Song Gao +Soshi Katsuta +Sotiris Salloumis +Soulou +Spencer Brown +Spencer Smith +Spike Curtis +Sridatta Thatipamala +Sridhar Ratnakumar +Srini Brahmaroutu +Srinivasan Srivatsan +Staf Wagemakers +Stanislav Bondarenko +Stanislav Levin +Steeve Morin +Stefan Berger +Stefan J. Wernli +Stefan Praszalowicz +Stefan S. +Stefan Scherer +Stefan Staudenmeyer +Stefan Weil +Steffen Butzer +Stephan Spindler +Stephen Benjamin +Stephen Crosby +Stephen Day +Stephen Drake +Stephen Rust +Steve Desmond +Steve Dougherty +Steve Durrheimer +Steve Francia +Steve Koch +Steven Burgess +Steven Erenst +Steven Hartland +Steven Iveson +Steven Merrill +Steven Richards +Steven Taylor +Stéphane Este-Gracias +Stig Larsson +Su Wang +Subhajit Ghosh +Sujith Haridasan +Sun Gengze <690388648@qq.com> +Sun Jianbo +Sune Keller +Sunny Gogoi +Suryakumar Sudar +Sven Dowideit +Swapnil Daingade +Sylvain Baubeau +Sylvain Bellemare +Sébastien +Sébastien HOUZÉ +Sébastien Luttringer +Sébastien Stormacq +Sören Tempel +Tabakhase +Tadej Janež +Takuto Sato +tang0th +Tangi Colin +Tatsuki Sugiura +Tatsushi Inagaki +Taylan Isikdemir +Taylor Jones +Ted M. Young +Tehmasp Chaudhri +Tejaswini Duggaraju +Tejesh Mehta +Terry Chu +terryding77 <550147740@qq.com> +Thatcher Peskens +theadactyl +Thell 'Bo' Fowler +Thermionix +Thiago Alves Silva +Thijs Terlouw +Thomas Bikeev +Thomas Frössman +Thomas Gazagnaire +Thomas Graf +Thomas Grainger +Thomas Hansen +Thomas Ledos +Thomas Leonard +Thomas Léveil +Thomas Orozco +Thomas Riccardi +Thomas Schroeter +Thomas Sjögren +Thomas Swift +Thomas Tanaka +Thomas Texier +Ti Zhou +Tiago Seabra +Tianon Gravi +Tianyi Wang +Tibor Vass +Tiffany Jernigan +Tiffany Low +Till Claassen +Till Wegmüller +Tim +Tim Bart +Tim Bosse +Tim Dettrick +Tim Düsterhus +Tim Hockin +Tim Potter +Tim Ruffles +Tim Smith +Tim Terhorst +Tim Wagner +Tim Wang +Tim Waugh +Tim Wraight +Tim Zju <21651152@zju.edu.cn> +timchenxiaoyu <837829664@qq.com> +timfeirg +Timo Rothenpieler +Timothy Hobbs +tjwebb123 +tobe +Tobias Bieniek +Tobias Bradtke +Tobias Gesellchen +Tobias Klauser +Tobias Munk +Tobias Pfandzelter +Tobias Schmidt +Tobias Schwab +Todd Crane +Todd Lunter +Todd Whiteman +Toli Kuznets +Tom Barlow +Tom Booth +Tom Denham +Tom Fotherby +Tom Howe +Tom Hulihan +Tom Maaswinkel +Tom Parker +Tom Sweeney +Tom Wilkie +Tom X. Tobin +Tom Zhao +Tomas Janousek +Tomas Kral +Tomas Tomecek +Tomasz Kopczynski +Tomasz Lipinski +Tomasz Nurkiewicz +Tomek Mańko +Tommaso Visconti +Tomoya Tabuchi +Tomáš Hrčka +tonic +Tonny Xu +Tony Abboud +Tony Daws +Tony Miller +toogley +Torstein Husebø +Toshiaki Makita +Tõnis Tiigi +Trace Andreason +tracylihui <793912329@qq.com> +Trapier Marshall +Travis Cline +Travis Thieman +Trent Ogren +Trevor +Trevor Pounds +Trevor Sullivan +Trishna Guha +Tristan Carel +Troy Denton +Tudor Brindus +Ty Alexander +Tycho Andersen +Tyler Brock +Tyler Brown +Tzu-Jung Lee +uhayate +Ulysse Carion +Umesh Yadav +Utz Bacher +vagrant +Vaidas Jablonskis +Valentin Kulesh +vanderliang +Velko Ivanov +Veres Lajos +Victor Algaze +Victor Coisne +Victor Costan +Victor I. Wood +Victor Lyuboslavsky +Victor Marmol +Victor Palma +Victor Vieux +Victoria Bialas +Vijaya Kumar K +Vikas Choudhary +Vikram bir Singh +Viktor Stanchev +Viktor Vojnovski +VinayRaghavanKS +Vincent Batts +Vincent Bernat +Vincent Boulineau +Vincent Demeester +Vincent Giersch +Vincent Mayers +Vincent Woo +Vinod Kulkarni +Vishal Doshi +Vishnu Kannan +Vitaly Ostrosablin +Vitor Monteiro +Vivek Agarwal +Vivek Dasgupta +Vivek Goyal +Vladimir Bulyga +Vladimir Kirillov +Vladimir Pouzanov +Vladimir Rutsky +Vladimir Varankin +VladimirAus +Vladislav Kolesnikov +Vlastimil Zeman +Vojtech Vitek (V-Teq) +Walter Leibbrandt +Walter Stanish +Wang Chao +Wang Guoliang +Wang Jie +Wang Long +Wang Ping +Wang Xing +Wang Yuexiao +Wang Yumu <37442693@qq.com> +wanghuaiqing +Ward Vandewege +WarheadsSE +Wassim Dhif +Wataru Ishida +Wayne Chang +Wayne Song +Weerasak Chongnguluam +Wei Fu +Wei Wu +Wei-Ting Kuo +weipeng +weiyan +Weiyang Zhu +Wen Cheng Ma +Wendel Fleming +Wenjun Tang +Wenkai Yin +wenlxie +Wenxuan Zhao +Wenyu You <21551128@zju.edu.cn> +Wenzhi Liang +Wes Morgan +Wewang Xiaorenfine +Wiktor Kwapisiewicz +Will Dietz +Will Rouesnel +Will Weaver +willhf +William Delanoue +William Henry +William Hubbs +William Martin +William Riancho +William Thurston +Wilson Júnior +Wing-Kam Wong +WiseTrem +Wolfgang Nagele +Wolfgang Powisch +Wonjun Kim +WuLonghui +xamyzhao +Xia Wu +Xian Chaobo +Xianglin Gao +Xianjie +Xianlu Bird +Xiao YongBiao +Xiao Zhang +XiaoBing Jiang +Xiaodong Liu +Xiaodong Zhang +Xiaohua Ding +Xiaoxi He +Xiaoxu Chen +Xiaoyu Zhang +xichengliudui <1693291525@qq.com> +xiekeyang +Ximo Guanter Gonzálbez +Xinbo Weng +Xinfeng Liu +Xinzi Zhou +Xiuming Chen +Xuecong Liao +xuzhaokui +Yadnyawalkya Tale +Yahya +yalpul +YAMADA Tsuyoshi +Yamasaki Masahide +Yan Feng +Yan Zhu +Yang Bai +Yang Li +Yang Pengfei +yangchenliang +Yann Autissier +Yanqiang Miao +Yao Zaiyong +Yash Murty +Yassine Tijani +Yasunori Mahata +Yazhong Liu +Yestin Sun +Yi EungJun +Yibai Zhang +Yihang Ho +Ying Li +Yohei Ueda +Yong Tang +Yongxin Li +Yongzhi Pan +Yosef Fertel +You-Sheng Yang (楊有勝) +youcai +Youcef YEKHLEF +Youfu Zhang +Yu Changchun +Yu Chengxia +Yu Peng +Yu-Ju Hong +Yuan Sun +Yuanhong Peng +Yue Zhang +Yufei Xiong +Yuhao Fang +Yuichiro Kaneko +YujiOshima +Yunxiang Huang +Yurii Rashkovskii +Yusuf Tarık Günaydın +Yves Blusseau <90z7oey02@sneakemail.com> +Yves Junqueira +Zac Dover +Zach Borboa +Zach Gershman +Zachary Jaffee +Zain Memon +Zaiste! +Zane DeGraffenried +Zefan Li +Zen Lin(Zhinan Lin) +Zhang Kun +Zhang Wei +Zhang Wentao +ZhangHang +zhangxianwei +Zhenan Ye <21551168@zju.edu.cn> +zhenghenghuo +Zhenhai Gao +Zhenkun Bi +ZhiPeng Lu +zhipengzuo +Zhou Hao +Zhoulin Xie +Zhu Guihua +Zhu Kunjia +Zhuoyun Wei +Ziheng Liu +Zilin Du +zimbatm +Ziming Dong +ZJUshuaizhou <21551191@zju.edu.cn> +zmarouf +Zoltan Tombol +Zou Yu +zqh +Zuhayr Elahi +Zunayed Ali +Álvaro Lázaro +Átila Camurça Alves +尹吉峰 +屈骏 +徐俊杰 +慕陶 +搏通 +黄艳红00139573 +정재영 diff --git a/vendor/github.com/docker/docker/LICENSE b/vendor/github.com/docker/docker/LICENSE new file mode 100644 index 0000000000..6d8d58fb67 --- /dev/null +++ b/vendor/github.com/docker/docker/LICENSE @@ -0,0 +1,191 @@ + + Apache License + Version 2.0, January 2004 + https://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + Copyright 2013-2018 Docker, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/docker/docker/NOTICE b/vendor/github.com/docker/docker/NOTICE new file mode 100644 index 0000000000..58b19b6d15 --- /dev/null +++ b/vendor/github.com/docker/docker/NOTICE @@ -0,0 +1,19 @@ +Docker +Copyright 2012-2017 Docker, Inc. + +This product includes software developed at Docker, Inc. (https://www.docker.com). + +This product contains software (https://github.com/creack/pty) developed +by Keith Rarick, licensed under the MIT License. + +The following is courtesy of our legal counsel: + + +Use and transfer of Docker may be subject to certain restrictions by the +United States and other governments. +It is your responsibility to ensure that your use and/or transfer does not +violate applicable laws. + +For more information, please see https://www.bis.doc.gov + +See also https://www.apache.org/dev/crypto.html and/or seek legal counsel. diff --git a/vendor/github.com/docker/docker/api/README.md b/vendor/github.com/docker/docker/api/README.md new file mode 100644 index 0000000000..f136c3433a --- /dev/null +++ b/vendor/github.com/docker/docker/api/README.md @@ -0,0 +1,42 @@ +# Working on the Engine API + +The Engine API is an HTTP API used by the command-line client to communicate with the daemon. It can also be used by third-party software to control the daemon. + +It consists of various components in this repository: + +- `api/swagger.yaml` A Swagger definition of the API. +- `api/types/` Types shared by both the client and server, representing various objects, options, responses, etc. Most are written manually, but some are automatically generated from the Swagger definition. See [#27919](https://github.com/docker/docker/issues/27919) for progress on this. +- `cli/` The command-line client. +- `client/` The Go client used by the command-line client. It can also be used by third-party Go programs. +- `daemon/` The daemon, which serves the API. + +## Swagger definition + +The API is defined by the [Swagger](http://swagger.io/specification/) definition in `api/swagger.yaml`. This definition can be used to: + +1. Automatically generate documentation. +2. Automatically generate the Go server and client. (A work-in-progress.) +3. Provide a machine readable version of the API for introspecting what it can do, automatically generating clients for other languages, etc. + +## Updating the API documentation + +The API documentation is generated entirely from `api/swagger.yaml`. If you make updates to the API, edit this file to represent the change in the documentation. + +The file is split into two main sections: + +- `definitions`, which defines re-usable objects used in requests and responses +- `paths`, which defines the API endpoints (and some inline objects which don't need to be reusable) + +To make an edit, first look for the endpoint you want to edit under `paths`, then make the required edits. Endpoints may reference reusable objects with `$ref`, which can be found in the `definitions` section. + +There is hopefully enough example material in the file for you to copy a similar pattern from elsewhere in the file (e.g. adding new fields or endpoints), but for the full reference, see the [Swagger specification](https://github.com/docker/docker/issues/27919). + +`swagger.yaml` is validated by `hack/validate/swagger` to ensure it is a valid Swagger definition. This is useful when making edits to ensure you are doing the right thing. + +## Viewing the API documentation + +When you make edits to `swagger.yaml`, you may want to check the generated API documentation to ensure it renders correctly. + +Run `make swagger-docs` and a preview will be running at `http://localhost`. Some of the styling may be incorrect, but you'll be able to ensure that it is generating the correct documentation. + +The production documentation is generated by vendoring `swagger.yaml` into [docker/docker.github.io](https://github.com/docker/docker.github.io). diff --git a/vendor/github.com/docker/docker/api/common.go b/vendor/github.com/docker/docker/api/common.go new file mode 100644 index 0000000000..bee9b875a8 --- /dev/null +++ b/vendor/github.com/docker/docker/api/common.go @@ -0,0 +1,11 @@ +package api // import "github.com/docker/docker/api" + +// Common constants for daemon and client. +const ( + // DefaultVersion of Current REST API + DefaultVersion = "1.42" + + // NoBaseImageSpecifier is the symbol used by the FROM + // command to specify that no base image is to be used. + NoBaseImageSpecifier = "scratch" +) diff --git a/vendor/github.com/docker/docker/api/common_unix.go b/vendor/github.com/docker/docker/api/common_unix.go new file mode 100644 index 0000000000..19fc63d658 --- /dev/null +++ b/vendor/github.com/docker/docker/api/common_unix.go @@ -0,0 +1,7 @@ +//go:build !windows +// +build !windows + +package api // import "github.com/docker/docker/api" + +// MinVersion represents Minimum REST API version supported +const MinVersion = "1.12" diff --git a/vendor/github.com/docker/docker/api/common_windows.go b/vendor/github.com/docker/docker/api/common_windows.go new file mode 100644 index 0000000000..590ba5479b --- /dev/null +++ b/vendor/github.com/docker/docker/api/common_windows.go @@ -0,0 +1,8 @@ +package api // import "github.com/docker/docker/api" + +// MinVersion represents Minimum REST API version supported +// Technically the first daemon API version released on Windows is v1.25 in +// engine version 1.13. However, some clients are explicitly using downlevel +// APIs (e.g. docker-compose v2.1 file format) and that is just too restrictive. +// Hence also allowing 1.24 on Windows. +const MinVersion string = "1.24" diff --git a/vendor/github.com/docker/docker/api/swagger-gen.yaml b/vendor/github.com/docker/docker/api/swagger-gen.yaml new file mode 100644 index 0000000000..f07a02737f --- /dev/null +++ b/vendor/github.com/docker/docker/api/swagger-gen.yaml @@ -0,0 +1,12 @@ + +layout: + models: + - name: definition + source: asset:model + target: "{{ joinFilePath .Target .ModelPackage }}" + file_name: "{{ (snakize (pascalize .Name)) }}.go" + operations: + - name: handler + source: asset:serverOperation + target: "{{ joinFilePath .Target .APIPackage .Package }}" + file_name: "{{ (snakize (pascalize .Name)) }}.go" diff --git a/vendor/github.com/docker/docker/api/swagger.yaml b/vendor/github.com/docker/docker/api/swagger.yaml new file mode 100644 index 0000000000..afe7a8c371 --- /dev/null +++ b/vendor/github.com/docker/docker/api/swagger.yaml @@ -0,0 +1,12152 @@ +# A Swagger 2.0 (a.k.a. OpenAPI) definition of the Engine API. +# +# This is used for generating API documentation and the types used by the +# client/server. See api/README.md for more information. +# +# Some style notes: +# - This file is used by ReDoc, which allows GitHub Flavored Markdown in +# descriptions. +# - There is no maximum line length, for ease of editing and pretty diffs. +# - operationIds are in the format "NounVerb", with a singular noun. + +swagger: "2.0" +schemes: + - "http" + - "https" +produces: + - "application/json" + - "text/plain" +consumes: + - "application/json" + - "text/plain" +basePath: "/v1.42" +info: + title: "Docker Engine API" + version: "1.42" + x-logo: + url: "https://docs.docker.com/assets/images/logo-docker-main.png" + description: | + The Engine API is an HTTP API served by Docker Engine. It is the API the + Docker client uses to communicate with the Engine, so everything the Docker + client can do can be done with the API. + + Most of the client's commands map directly to API endpoints (e.g. `docker ps` + is `GET /containers/json`). The notable exception is running containers, + which consists of several API calls. + + # Errors + + The API uses standard HTTP status codes to indicate the success or failure + of the API call. The body of the response will be JSON in the following + format: + + ``` + { + "message": "page not found" + } + ``` + + # Versioning + + The API is usually changed in each release, so API calls are versioned to + ensure that clients don't break. To lock to a specific version of the API, + you prefix the URL with its version, for example, call `/v1.30/info` to use + the v1.30 version of the `/info` endpoint. If the API version specified in + the URL is not supported by the daemon, a HTTP `400 Bad Request` error message + is returned. + + If you omit the version-prefix, the current version of the API (v1.42) is used. + For example, calling `/info` is the same as calling `/v1.42/info`. Using the + API without a version-prefix is deprecated and will be removed in a future release. + + Engine releases in the near future should support this version of the API, + so your client will continue to work even if it is talking to a newer Engine. + + The API uses an open schema model, which means server may add extra properties + to responses. Likewise, the server will ignore any extra query parameters and + request body properties. When you write clients, you need to ignore additional + properties in responses to ensure they do not break when talking to newer + daemons. + + + # Authentication + + Authentication for registries is handled client side. The client has to send + authentication details to various endpoints that need to communicate with + registries, such as `POST /images/(name)/push`. These are sent as + `X-Registry-Auth` header as a [base64url encoded](https://tools.ietf.org/html/rfc4648#section-5) + (JSON) string with the following structure: + + ``` + { + "username": "string", + "password": "string", + "email": "string", + "serveraddress": "string" + } + ``` + + The `serveraddress` is a domain/IP without a protocol. Throughout this + structure, double quotes are required. + + If you have already got an identity token from the [`/auth` endpoint](#operation/SystemAuth), + you can just pass this instead of credentials: + + ``` + { + "identitytoken": "9cbaf023786cd7..." + } + ``` + +# The tags on paths define the menu sections in the ReDoc documentation, so +# the usage of tags must make sense for that: +# - They should be singular, not plural. +# - There should not be too many tags, or the menu becomes unwieldy. For +# example, it is preferable to add a path to the "System" tag instead of +# creating a tag with a single path in it. +# - The order of tags in this list defines the order in the menu. +tags: + # Primary objects + - name: "Container" + x-displayName: "Containers" + description: | + Create and manage containers. + - name: "Image" + x-displayName: "Images" + - name: "Network" + x-displayName: "Networks" + description: | + Networks are user-defined networks that containers can be attached to. + See the [networking documentation](https://docs.docker.com/network/) + for more information. + - name: "Volume" + x-displayName: "Volumes" + description: | + Create and manage persistent storage that can be attached to containers. + - name: "Exec" + x-displayName: "Exec" + description: | + Run new commands inside running containers. Refer to the + [command-line reference](https://docs.docker.com/engine/reference/commandline/exec/) + for more information. + + To exec a command in a container, you first need to create an exec instance, + then start it. These two API endpoints are wrapped up in a single command-line + command, `docker exec`. + + # Swarm things + - name: "Swarm" + x-displayName: "Swarm" + description: | + Engines can be clustered together in a swarm. Refer to the + [swarm mode documentation](https://docs.docker.com/engine/swarm/) + for more information. + - name: "Node" + x-displayName: "Nodes" + description: | + Nodes are instances of the Engine participating in a swarm. Swarm mode + must be enabled for these endpoints to work. + - name: "Service" + x-displayName: "Services" + description: | + Services are the definitions of tasks to run on a swarm. Swarm mode must + be enabled for these endpoints to work. + - name: "Task" + x-displayName: "Tasks" + description: | + A task is a container running on a swarm. It is the atomic scheduling unit + of swarm. Swarm mode must be enabled for these endpoints to work. + - name: "Secret" + x-displayName: "Secrets" + description: | + Secrets are sensitive data that can be used by services. Swarm mode must + be enabled for these endpoints to work. + - name: "Config" + x-displayName: "Configs" + description: | + Configs are application configurations that can be used by services. Swarm + mode must be enabled for these endpoints to work. + # System things + - name: "Plugin" + x-displayName: "Plugins" + - name: "System" + x-displayName: "System" + +definitions: + Port: + type: "object" + description: "An open port on a container" + required: [PrivatePort, Type] + properties: + IP: + type: "string" + format: "ip-address" + description: "Host IP address that the container's port is mapped to" + PrivatePort: + type: "integer" + format: "uint16" + x-nullable: false + description: "Port on the container" + PublicPort: + type: "integer" + format: "uint16" + description: "Port exposed on the host" + Type: + type: "string" + x-nullable: false + enum: ["tcp", "udp", "sctp"] + example: + PrivatePort: 8080 + PublicPort: 80 + Type: "tcp" + + MountPoint: + type: "object" + description: | + MountPoint represents a mount point configuration inside the container. + This is used for reporting the mountpoints in use by a container. + properties: + Type: + description: | + The mount type: + + - `bind` a mount of a file or directory from the host into the container. + - `volume` a docker volume with the given `Name`. + - `tmpfs` a `tmpfs`. + - `npipe` a named pipe from the host into the container. + - `cluster` a Swarm cluster volume + type: "string" + enum: + - "bind" + - "volume" + - "tmpfs" + - "npipe" + - "cluster" + example: "volume" + Name: + description: | + Name is the name reference to the underlying data defined by `Source` + e.g., the volume name. + type: "string" + example: "myvolume" + Source: + description: | + Source location of the mount. + + For volumes, this contains the storage location of the volume (within + `/var/lib/docker/volumes/`). For bind-mounts, and `npipe`, this contains + the source (host) part of the bind-mount. For `tmpfs` mount points, this + field is empty. + type: "string" + example: "/var/lib/docker/volumes/myvolume/_data" + Destination: + description: | + Destination is the path relative to the container root (`/`) where + the `Source` is mounted inside the container. + type: "string" + example: "/usr/share/nginx/html/" + Driver: + description: | + Driver is the volume driver used to create the volume (if it is a volume). + type: "string" + example: "local" + Mode: + description: | + Mode is a comma separated list of options supplied by the user when + creating the bind/volume mount. + + The default is platform-specific (`"z"` on Linux, empty on Windows). + type: "string" + example: "z" + RW: + description: | + Whether the mount is mounted writable (read-write). + type: "boolean" + example: true + Propagation: + description: | + Propagation describes how mounts are propagated from the host into the + mount point, and vice-versa. Refer to the [Linux kernel documentation](https://www.kernel.org/doc/Documentation/filesystems/sharedsubtree.txt) + for details. This field is not used on Windows. + type: "string" + example: "" + + DeviceMapping: + type: "object" + description: "A device mapping between the host and container" + properties: + PathOnHost: + type: "string" + PathInContainer: + type: "string" + CgroupPermissions: + type: "string" + example: + PathOnHost: "/dev/deviceName" + PathInContainer: "/dev/deviceName" + CgroupPermissions: "mrw" + + DeviceRequest: + type: "object" + description: "A request for devices to be sent to device drivers" + properties: + Driver: + type: "string" + example: "nvidia" + Count: + type: "integer" + example: -1 + DeviceIDs: + type: "array" + items: + type: "string" + example: + - "0" + - "1" + - "GPU-fef8089b-4820-abfc-e83e-94318197576e" + Capabilities: + description: | + A list of capabilities; an OR list of AND lists of capabilities. + type: "array" + items: + type: "array" + items: + type: "string" + example: + # gpu AND nvidia AND compute + - ["gpu", "nvidia", "compute"] + Options: + description: | + Driver-specific options, specified as a key/value pairs. These options + are passed directly to the driver. + type: "object" + additionalProperties: + type: "string" + + ThrottleDevice: + type: "object" + properties: + Path: + description: "Device path" + type: "string" + Rate: + description: "Rate" + type: "integer" + format: "int64" + minimum: 0 + + Mount: + type: "object" + properties: + Target: + description: "Container path." + type: "string" + Source: + description: "Mount source (e.g. a volume name, a host path)." + type: "string" + Type: + description: | + The mount type. Available types: + + - `bind` Mounts a file or directory from the host into the container. Must exist prior to creating the container. + - `volume` Creates a volume with the given name and options (or uses a pre-existing volume with the same name and options). These are **not** removed when the container is removed. + - `tmpfs` Create a tmpfs with the given options. The mount source cannot be specified for tmpfs. + - `npipe` Mounts a named pipe from the host into the container. Must exist prior to creating the container. + - `cluster` a Swarm cluster volume + type: "string" + enum: + - "bind" + - "volume" + - "tmpfs" + - "npipe" + - "cluster" + ReadOnly: + description: "Whether the mount should be read-only." + type: "boolean" + Consistency: + description: "The consistency requirement for the mount: `default`, `consistent`, `cached`, or `delegated`." + type: "string" + BindOptions: + description: "Optional configuration for the `bind` type." + type: "object" + properties: + Propagation: + description: "A propagation mode with the value `[r]private`, `[r]shared`, or `[r]slave`." + type: "string" + enum: + - "private" + - "rprivate" + - "shared" + - "rshared" + - "slave" + - "rslave" + NonRecursive: + description: "Disable recursive bind mount." + type: "boolean" + default: false + CreateMountpoint: + description: "Create mount point on host if missing" + type: "boolean" + default: false + VolumeOptions: + description: "Optional configuration for the `volume` type." + type: "object" + properties: + NoCopy: + description: "Populate volume with data from the target." + type: "boolean" + default: false + Labels: + description: "User-defined key/value metadata." + type: "object" + additionalProperties: + type: "string" + DriverConfig: + description: "Map of driver specific options" + type: "object" + properties: + Name: + description: "Name of the driver to use to create the volume." + type: "string" + Options: + description: "key/value map of driver specific options." + type: "object" + additionalProperties: + type: "string" + TmpfsOptions: + description: "Optional configuration for the `tmpfs` type." + type: "object" + properties: + SizeBytes: + description: "The size for the tmpfs mount in bytes." + type: "integer" + format: "int64" + Mode: + description: "The permission mode for the tmpfs mount in an integer." + type: "integer" + + RestartPolicy: + description: | + The behavior to apply when the container exits. The default is not to + restart. + + An ever increasing delay (double the previous delay, starting at 100ms) is + added before each restart to prevent flooding the server. + type: "object" + properties: + Name: + type: "string" + description: | + - Empty string means not to restart + - `no` Do not automatically restart + - `always` Always restart + - `unless-stopped` Restart always except when the user has manually stopped the container + - `on-failure` Restart only when the container exit code is non-zero + enum: + - "" + - "no" + - "always" + - "unless-stopped" + - "on-failure" + MaximumRetryCount: + type: "integer" + description: | + If `on-failure` is used, the number of times to retry before giving up. + + Resources: + description: "A container's resources (cgroups config, ulimits, etc)" + type: "object" + properties: + # Applicable to all platforms + CpuShares: + description: | + An integer value representing this container's relative CPU weight + versus other containers. + type: "integer" + Memory: + description: "Memory limit in bytes." + type: "integer" + format: "int64" + default: 0 + # Applicable to UNIX platforms + CgroupParent: + description: | + Path to `cgroups` under which the container's `cgroup` is created. If + the path is not absolute, the path is considered to be relative to the + `cgroups` path of the init process. Cgroups are created if they do not + already exist. + type: "string" + BlkioWeight: + description: "Block IO weight (relative weight)." + type: "integer" + minimum: 0 + maximum: 1000 + BlkioWeightDevice: + description: | + Block IO weight (relative device weight) in the form: + + ``` + [{"Path": "device_path", "Weight": weight}] + ``` + type: "array" + items: + type: "object" + properties: + Path: + type: "string" + Weight: + type: "integer" + minimum: 0 + BlkioDeviceReadBps: + description: | + Limit read rate (bytes per second) from a device, in the form: + + ``` + [{"Path": "device_path", "Rate": rate}] + ``` + type: "array" + items: + $ref: "#/definitions/ThrottleDevice" + BlkioDeviceWriteBps: + description: | + Limit write rate (bytes per second) to a device, in the form: + + ``` + [{"Path": "device_path", "Rate": rate}] + ``` + type: "array" + items: + $ref: "#/definitions/ThrottleDevice" + BlkioDeviceReadIOps: + description: | + Limit read rate (IO per second) from a device, in the form: + + ``` + [{"Path": "device_path", "Rate": rate}] + ``` + type: "array" + items: + $ref: "#/definitions/ThrottleDevice" + BlkioDeviceWriteIOps: + description: | + Limit write rate (IO per second) to a device, in the form: + + ``` + [{"Path": "device_path", "Rate": rate}] + ``` + type: "array" + items: + $ref: "#/definitions/ThrottleDevice" + CpuPeriod: + description: "The length of a CPU period in microseconds." + type: "integer" + format: "int64" + CpuQuota: + description: | + Microseconds of CPU time that the container can get in a CPU period. + type: "integer" + format: "int64" + CpuRealtimePeriod: + description: | + The length of a CPU real-time period in microseconds. Set to 0 to + allocate no time allocated to real-time tasks. + type: "integer" + format: "int64" + CpuRealtimeRuntime: + description: | + The length of a CPU real-time runtime in microseconds. Set to 0 to + allocate no time allocated to real-time tasks. + type: "integer" + format: "int64" + CpusetCpus: + description: | + CPUs in which to allow execution (e.g., `0-3`, `0,1`). + type: "string" + example: "0-3" + CpusetMems: + description: | + Memory nodes (MEMs) in which to allow execution (0-3, 0,1). Only + effective on NUMA systems. + type: "string" + Devices: + description: "A list of devices to add to the container." + type: "array" + items: + $ref: "#/definitions/DeviceMapping" + DeviceCgroupRules: + description: "a list of cgroup rules to apply to the container" + type: "array" + items: + type: "string" + example: "c 13:* rwm" + DeviceRequests: + description: | + A list of requests for devices to be sent to device drivers. + type: "array" + items: + $ref: "#/definitions/DeviceRequest" + KernelMemoryTCP: + description: | + Hard limit for kernel TCP buffer memory (in bytes). Depending on the + OCI runtime in use, this option may be ignored. It is no longer supported + by the default (runc) runtime. + + This field is omitted when empty. + type: "integer" + format: "int64" + MemoryReservation: + description: "Memory soft limit in bytes." + type: "integer" + format: "int64" + MemorySwap: + description: | + Total memory limit (memory + swap). Set as `-1` to enable unlimited + swap. + type: "integer" + format: "int64" + MemorySwappiness: + description: | + Tune a container's memory swappiness behavior. Accepts an integer + between 0 and 100. + type: "integer" + format: "int64" + minimum: 0 + maximum: 100 + NanoCpus: + description: "CPU quota in units of 10-9 CPUs." + type: "integer" + format: "int64" + OomKillDisable: + description: "Disable OOM Killer for the container." + type: "boolean" + Init: + description: | + Run an init inside the container that forwards signals and reaps + processes. This field is omitted if empty, and the default (as + configured on the daemon) is used. + type: "boolean" + x-nullable: true + PidsLimit: + description: | + Tune a container's PIDs limit. Set `0` or `-1` for unlimited, or `null` + to not change. + type: "integer" + format: "int64" + x-nullable: true + Ulimits: + description: | + A list of resource limits to set in the container. For example: + + ``` + {"Name": "nofile", "Soft": 1024, "Hard": 2048} + ``` + type: "array" + items: + type: "object" + properties: + Name: + description: "Name of ulimit" + type: "string" + Soft: + description: "Soft limit" + type: "integer" + Hard: + description: "Hard limit" + type: "integer" + # Applicable to Windows + CpuCount: + description: | + The number of usable CPUs (Windows only). + + On Windows Server containers, the processor resource controls are + mutually exclusive. The order of precedence is `CPUCount` first, then + `CPUShares`, and `CPUPercent` last. + type: "integer" + format: "int64" + CpuPercent: + description: | + The usable percentage of the available CPUs (Windows only). + + On Windows Server containers, the processor resource controls are + mutually exclusive. The order of precedence is `CPUCount` first, then + `CPUShares`, and `CPUPercent` last. + type: "integer" + format: "int64" + IOMaximumIOps: + description: "Maximum IOps for the container system drive (Windows only)" + type: "integer" + format: "int64" + IOMaximumBandwidth: + description: | + Maximum IO in bytes per second for the container system drive + (Windows only). + type: "integer" + format: "int64" + + Limit: + description: | + An object describing a limit on resources which can be requested by a task. + type: "object" + properties: + NanoCPUs: + type: "integer" + format: "int64" + example: 4000000000 + MemoryBytes: + type: "integer" + format: "int64" + example: 8272408576 + Pids: + description: | + Limits the maximum number of PIDs in the container. Set `0` for unlimited. + type: "integer" + format: "int64" + default: 0 + example: 100 + + ResourceObject: + description: | + An object describing the resources which can be advertised by a node and + requested by a task. + type: "object" + properties: + NanoCPUs: + type: "integer" + format: "int64" + example: 4000000000 + MemoryBytes: + type: "integer" + format: "int64" + example: 8272408576 + GenericResources: + $ref: "#/definitions/GenericResources" + + GenericResources: + description: | + User-defined resources can be either Integer resources (e.g, `SSD=3`) or + String resources (e.g, `GPU=UUID1`). + type: "array" + items: + type: "object" + properties: + NamedResourceSpec: + type: "object" + properties: + Kind: + type: "string" + Value: + type: "string" + DiscreteResourceSpec: + type: "object" + properties: + Kind: + type: "string" + Value: + type: "integer" + format: "int64" + example: + - DiscreteResourceSpec: + Kind: "SSD" + Value: 3 + - NamedResourceSpec: + Kind: "GPU" + Value: "UUID1" + - NamedResourceSpec: + Kind: "GPU" + Value: "UUID2" + + HealthConfig: + description: "A test to perform to check that the container is healthy." + type: "object" + properties: + Test: + description: | + The test to perform. Possible values are: + + - `[]` inherit healthcheck from image or parent image + - `["NONE"]` disable healthcheck + - `["CMD", args...]` exec arguments directly + - `["CMD-SHELL", command]` run command with system's default shell + type: "array" + items: + type: "string" + Interval: + description: | + The time to wait between checks in nanoseconds. It should be 0 or at + least 1000000 (1 ms). 0 means inherit. + type: "integer" + format: "int64" + Timeout: + description: | + The time to wait before considering the check to have hung. It should + be 0 or at least 1000000 (1 ms). 0 means inherit. + type: "integer" + format: "int64" + Retries: + description: | + The number of consecutive failures needed to consider a container as + unhealthy. 0 means inherit. + type: "integer" + StartPeriod: + description: | + Start period for the container to initialize before starting + health-retries countdown in nanoseconds. It should be 0 or at least + 1000000 (1 ms). 0 means inherit. + type: "integer" + format: "int64" + + Health: + description: | + Health stores information about the container's healthcheck results. + type: "object" + x-nullable: true + properties: + Status: + description: | + Status is one of `none`, `starting`, `healthy` or `unhealthy` + + - "none" Indicates there is no healthcheck + - "starting" Starting indicates that the container is not yet ready + - "healthy" Healthy indicates that the container is running correctly + - "unhealthy" Unhealthy indicates that the container has a problem + type: "string" + enum: + - "none" + - "starting" + - "healthy" + - "unhealthy" + example: "healthy" + FailingStreak: + description: "FailingStreak is the number of consecutive failures" + type: "integer" + example: 0 + Log: + type: "array" + description: | + Log contains the last few results (oldest first) + items: + $ref: "#/definitions/HealthcheckResult" + + HealthcheckResult: + description: | + HealthcheckResult stores information about a single run of a healthcheck probe + type: "object" + x-nullable: true + properties: + Start: + description: | + Date and time at which this check started in + [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format with nano-seconds. + type: "string" + format: "date-time" + example: "2020-01-04T10:44:24.496525531Z" + End: + description: | + Date and time at which this check ended in + [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format with nano-seconds. + type: "string" + format: "dateTime" + example: "2020-01-04T10:45:21.364524523Z" + ExitCode: + description: | + ExitCode meanings: + + - `0` healthy + - `1` unhealthy + - `2` reserved (considered unhealthy) + - other values: error running probe + type: "integer" + example: 0 + Output: + description: "Output from last check" + type: "string" + + HostConfig: + description: "Container configuration that depends on the host we are running on" + allOf: + - $ref: "#/definitions/Resources" + - type: "object" + properties: + # Applicable to all platforms + Binds: + type: "array" + description: | + A list of volume bindings for this container. Each volume binding + is a string in one of these forms: + + - `host-src:container-dest[:options]` to bind-mount a host path + into the container. Both `host-src`, and `container-dest` must + be an _absolute_ path. + - `volume-name:container-dest[:options]` to bind-mount a volume + managed by a volume driver into the container. `container-dest` + must be an _absolute_ path. + + `options` is an optional, comma-delimited list of: + + - `nocopy` disables automatic copying of data from the container + path to the volume. The `nocopy` flag only applies to named volumes. + - `[ro|rw]` mounts a volume read-only or read-write, respectively. + If omitted or set to `rw`, volumes are mounted read-write. + - `[z|Z]` applies SELinux labels to allow or deny multiple containers + to read and write to the same volume. + - `z`: a _shared_ content label is applied to the content. This + label indicates that multiple containers can share the volume + content, for both reading and writing. + - `Z`: a _private unshared_ label is applied to the content. + This label indicates that only the current container can use + a private volume. Labeling systems such as SELinux require + proper labels to be placed on volume content that is mounted + into a container. Without a label, the security system can + prevent a container's processes from using the content. By + default, the labels set by the host operating system are not + modified. + - `[[r]shared|[r]slave|[r]private]` specifies mount + [propagation behavior](https://www.kernel.org/doc/Documentation/filesystems/sharedsubtree.txt). + This only applies to bind-mounted volumes, not internal volumes + or named volumes. Mount propagation requires the source mount + point (the location where the source directory is mounted in the + host operating system) to have the correct propagation properties. + For shared volumes, the source mount point must be set to `shared`. + For slave volumes, the mount must be set to either `shared` or + `slave`. + items: + type: "string" + ContainerIDFile: + type: "string" + description: "Path to a file where the container ID is written" + LogConfig: + type: "object" + description: "The logging configuration for this container" + properties: + Type: + type: "string" + enum: + - "json-file" + - "syslog" + - "journald" + - "gelf" + - "fluentd" + - "awslogs" + - "splunk" + - "etwlogs" + - "none" + Config: + type: "object" + additionalProperties: + type: "string" + NetworkMode: + type: "string" + description: | + Network mode to use for this container. Supported standard values + are: `bridge`, `host`, `none`, and `container:`. Any + other value is taken as a custom network's name to which this + container should connect to. + PortBindings: + $ref: "#/definitions/PortMap" + RestartPolicy: + $ref: "#/definitions/RestartPolicy" + AutoRemove: + type: "boolean" + description: | + Automatically remove the container when the container's process + exits. This has no effect if `RestartPolicy` is set. + VolumeDriver: + type: "string" + description: "Driver that this container uses to mount volumes." + VolumesFrom: + type: "array" + description: | + A list of volumes to inherit from another container, specified in + the form `[:]`. + items: + type: "string" + Mounts: + description: | + Specification for mounts to be added to the container. + type: "array" + items: + $ref: "#/definitions/Mount" + ConsoleSize: + type: "array" + description: | + Initial console size, as an `[height, width]` array. + x-nullable: true + minItems: 2 + maxItems: 2 + items: + type: "integer" + minimum: 0 + + # Applicable to UNIX platforms + CapAdd: + type: "array" + description: | + A list of kernel capabilities to add to the container. Conflicts + with option 'Capabilities'. + items: + type: "string" + CapDrop: + type: "array" + description: | + A list of kernel capabilities to drop from the container. Conflicts + with option 'Capabilities'. + items: + type: "string" + CgroupnsMode: + type: "string" + enum: + - "private" + - "host" + description: | + cgroup namespace mode for the container. Possible values are: + + - `"private"`: the container runs in its own private cgroup namespace + - `"host"`: use the host system's cgroup namespace + + If not specified, the daemon default is used, which can either be `"private"` + or `"host"`, depending on daemon version, kernel support and configuration. + Dns: + type: "array" + description: "A list of DNS servers for the container to use." + items: + type: "string" + DnsOptions: + type: "array" + description: "A list of DNS options." + items: + type: "string" + DnsSearch: + type: "array" + description: "A list of DNS search domains." + items: + type: "string" + ExtraHosts: + type: "array" + description: | + A list of hostnames/IP mappings to add to the container's `/etc/hosts` + file. Specified in the form `["hostname:IP"]`. + items: + type: "string" + GroupAdd: + type: "array" + description: | + A list of additional groups that the container process will run as. + items: + type: "string" + IpcMode: + type: "string" + description: | + IPC sharing mode for the container. Possible values are: + + - `"none"`: own private IPC namespace, with /dev/shm not mounted + - `"private"`: own private IPC namespace + - `"shareable"`: own private IPC namespace, with a possibility to share it with other containers + - `"container:"`: join another (shareable) container's IPC namespace + - `"host"`: use the host system's IPC namespace + + If not specified, daemon default is used, which can either be `"private"` + or `"shareable"`, depending on daemon version and configuration. + Cgroup: + type: "string" + description: "Cgroup to use for the container." + Links: + type: "array" + description: | + A list of links for the container in the form `container_name:alias`. + items: + type: "string" + OomScoreAdj: + type: "integer" + description: | + An integer value containing the score given to the container in + order to tune OOM killer preferences. + example: 500 + PidMode: + type: "string" + description: | + Set the PID (Process) Namespace mode for the container. It can be + either: + + - `"container:"`: joins another container's PID namespace + - `"host"`: use the host's PID namespace inside the container + Privileged: + type: "boolean" + description: "Gives the container full access to the host." + PublishAllPorts: + type: "boolean" + description: | + Allocates an ephemeral host port for all of a container's + exposed ports. + + Ports are de-allocated when the container stops and allocated when + the container starts. The allocated port might be changed when + restarting the container. + + The port is selected from the ephemeral port range that depends on + the kernel. For example, on Linux the range is defined by + `/proc/sys/net/ipv4/ip_local_port_range`. + ReadonlyRootfs: + type: "boolean" + description: "Mount the container's root filesystem as read only." + SecurityOpt: + type: "array" + description: | + A list of string values to customize labels for MLS systems, such + as SELinux. + items: + type: "string" + StorageOpt: + type: "object" + description: | + Storage driver options for this container, in the form `{"size": "120G"}`. + additionalProperties: + type: "string" + Tmpfs: + type: "object" + description: | + A map of container directories which should be replaced by tmpfs + mounts, and their corresponding mount options. For example: + + ``` + { "/run": "rw,noexec,nosuid,size=65536k" } + ``` + additionalProperties: + type: "string" + UTSMode: + type: "string" + description: "UTS namespace to use for the container." + UsernsMode: + type: "string" + description: | + Sets the usernamespace mode for the container when usernamespace + remapping option is enabled. + ShmSize: + type: "integer" + description: | + Size of `/dev/shm` in bytes. If omitted, the system uses 64MB. + minimum: 0 + Sysctls: + type: "object" + description: | + A list of kernel parameters (sysctls) to set in the container. + For example: + + ``` + {"net.ipv4.ip_forward": "1"} + ``` + additionalProperties: + type: "string" + Runtime: + type: "string" + description: "Runtime to use with this container." + # Applicable to Windows + Isolation: + type: "string" + description: | + Isolation technology of the container. (Windows only) + enum: + - "default" + - "process" + - "hyperv" + MaskedPaths: + type: "array" + description: | + The list of paths to be masked inside the container (this overrides + the default set of paths). + items: + type: "string" + ReadonlyPaths: + type: "array" + description: | + The list of paths to be set as read-only inside the container + (this overrides the default set of paths). + items: + type: "string" + + ContainerConfig: + description: | + Configuration for a container that is portable between hosts. + + When used as `ContainerConfig` field in an image, `ContainerConfig` is an + optional field containing the configuration of the container that was last + committed when creating the image. + + Previous versions of Docker builder used this field to store build cache, + and it is not in active use anymore. + type: "object" + properties: + Hostname: + description: | + The hostname to use for the container, as a valid RFC 1123 hostname. + type: "string" + example: "439f4e91bd1d" + Domainname: + description: | + The domain name to use for the container. + type: "string" + User: + description: "The user that commands are run as inside the container." + type: "string" + AttachStdin: + description: "Whether to attach to `stdin`." + type: "boolean" + default: false + AttachStdout: + description: "Whether to attach to `stdout`." + type: "boolean" + default: true + AttachStderr: + description: "Whether to attach to `stderr`." + type: "boolean" + default: true + ExposedPorts: + description: | + An object mapping ports to an empty object in the form: + + `{"/": {}}` + type: "object" + x-nullable: true + additionalProperties: + type: "object" + enum: + - {} + default: {} + example: { + "80/tcp": {}, + "443/tcp": {} + } + Tty: + description: | + Attach standard streams to a TTY, including `stdin` if it is not closed. + type: "boolean" + default: false + OpenStdin: + description: "Open `stdin`" + type: "boolean" + default: false + StdinOnce: + description: "Close `stdin` after one attached client disconnects" + type: "boolean" + default: false + Env: + description: | + A list of environment variables to set inside the container in the + form `["VAR=value", ...]`. A variable without `=` is removed from the + environment, rather than to have an empty value. + type: "array" + items: + type: "string" + example: + - "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" + Cmd: + description: | + Command to run specified as a string or an array of strings. + type: "array" + items: + type: "string" + example: ["/bin/sh"] + Healthcheck: + $ref: "#/definitions/HealthConfig" + ArgsEscaped: + description: "Command is already escaped (Windows only)" + type: "boolean" + default: false + example: false + x-nullable: true + Image: + description: | + The name (or reference) of the image to use when creating the container, + or which was used when the container was created. + type: "string" + example: "example-image:1.0" + Volumes: + description: | + An object mapping mount point paths inside the container to empty + objects. + type: "object" + additionalProperties: + type: "object" + enum: + - {} + default: {} + WorkingDir: + description: "The working directory for commands to run in." + type: "string" + example: "/public/" + Entrypoint: + description: | + The entry point for the container as a string or an array of strings. + + If the array consists of exactly one empty string (`[""]`) then the + entry point is reset to system default (i.e., the entry point used by + docker when there is no `ENTRYPOINT` instruction in the `Dockerfile`). + type: "array" + items: + type: "string" + example: [] + NetworkDisabled: + description: "Disable networking for the container." + type: "boolean" + x-nullable: true + MacAddress: + description: "MAC address of the container." + type: "string" + x-nullable: true + OnBuild: + description: | + `ONBUILD` metadata that were defined in the image's `Dockerfile`. + type: "array" + x-nullable: true + items: + type: "string" + example: [] + Labels: + description: "User-defined key/value metadata." + type: "object" + additionalProperties: + type: "string" + example: + com.example.some-label: "some-value" + com.example.some-other-label: "some-other-value" + StopSignal: + description: | + Signal to stop a container as a string or unsigned integer. + type: "string" + example: "SIGTERM" + x-nullable: true + StopTimeout: + description: "Timeout to stop a container in seconds." + type: "integer" + default: 10 + x-nullable: true + Shell: + description: | + Shell for when `RUN`, `CMD`, and `ENTRYPOINT` uses a shell. + type: "array" + x-nullable: true + items: + type: "string" + example: ["/bin/sh", "-c"] + + NetworkingConfig: + description: | + NetworkingConfig represents the container's networking configuration for + each of its interfaces. + It is used for the networking configs specified in the `docker create` + and `docker network connect` commands. + type: "object" + properties: + EndpointsConfig: + description: | + A mapping of network name to endpoint configuration for that network. + type: "object" + additionalProperties: + $ref: "#/definitions/EndpointSettings" + example: + # putting an example here, instead of using the example values from + # /definitions/EndpointSettings, because containers/create currently + # does not support attaching to multiple networks, so the example request + # would be confusing if it showed that multiple networks can be contained + # in the EndpointsConfig. + # TODO remove once we support multiple networks on container create (see https://github.com/moby/moby/blob/07e6b843594e061f82baa5fa23c2ff7d536c2a05/daemon/create.go#L323) + EndpointsConfig: + isolated_nw: + IPAMConfig: + IPv4Address: "172.20.30.33" + IPv6Address: "2001:db8:abcd::3033" + LinkLocalIPs: + - "169.254.34.68" + - "fe80::3468" + Links: + - "container_1" + - "container_2" + Aliases: + - "server_x" + - "server_y" + + NetworkSettings: + description: "NetworkSettings exposes the network settings in the API" + type: "object" + properties: + Bridge: + description: Name of the network's bridge (for example, `docker0`). + type: "string" + example: "docker0" + SandboxID: + description: SandboxID uniquely represents a container's network stack. + type: "string" + example: "9d12daf2c33f5959c8bf90aa513e4f65b561738661003029ec84830cd503a0c3" + HairpinMode: + description: | + Indicates if hairpin NAT should be enabled on the virtual interface. + type: "boolean" + example: false + LinkLocalIPv6Address: + description: IPv6 unicast address using the link-local prefix. + type: "string" + example: "fe80::42:acff:fe11:1" + LinkLocalIPv6PrefixLen: + description: Prefix length of the IPv6 unicast address. + type: "integer" + example: "64" + Ports: + $ref: "#/definitions/PortMap" + SandboxKey: + description: SandboxKey identifies the sandbox + type: "string" + example: "/var/run/docker/netns/8ab54b426c38" + + # TODO is SecondaryIPAddresses actually used? + SecondaryIPAddresses: + description: "" + type: "array" + items: + $ref: "#/definitions/Address" + x-nullable: true + + # TODO is SecondaryIPv6Addresses actually used? + SecondaryIPv6Addresses: + description: "" + type: "array" + items: + $ref: "#/definitions/Address" + x-nullable: true + + # TODO properties below are part of DefaultNetworkSettings, which is + # marked as deprecated since Docker 1.9 and to be removed in Docker v17.12 + EndpointID: + description: | + EndpointID uniquely represents a service endpoint in a Sandbox. + +


+ + > **Deprecated**: This field is only propagated when attached to the + > default "bridge" network. Use the information from the "bridge" + > network inside the `Networks` map instead, which contains the same + > information. This field was deprecated in Docker 1.9 and is scheduled + > to be removed in Docker 17.12.0 + type: "string" + example: "b88f5b905aabf2893f3cbc4ee42d1ea7980bbc0a92e2c8922b1e1795298afb0b" + Gateway: + description: | + Gateway address for the default "bridge" network. + +


+ + > **Deprecated**: This field is only propagated when attached to the + > default "bridge" network. Use the information from the "bridge" + > network inside the `Networks` map instead, which contains the same + > information. This field was deprecated in Docker 1.9 and is scheduled + > to be removed in Docker 17.12.0 + type: "string" + example: "172.17.0.1" + GlobalIPv6Address: + description: | + Global IPv6 address for the default "bridge" network. + +


+ + > **Deprecated**: This field is only propagated when attached to the + > default "bridge" network. Use the information from the "bridge" + > network inside the `Networks` map instead, which contains the same + > information. This field was deprecated in Docker 1.9 and is scheduled + > to be removed in Docker 17.12.0 + type: "string" + example: "2001:db8::5689" + GlobalIPv6PrefixLen: + description: | + Mask length of the global IPv6 address. + +


+ + > **Deprecated**: This field is only propagated when attached to the + > default "bridge" network. Use the information from the "bridge" + > network inside the `Networks` map instead, which contains the same + > information. This field was deprecated in Docker 1.9 and is scheduled + > to be removed in Docker 17.12.0 + type: "integer" + example: 64 + IPAddress: + description: | + IPv4 address for the default "bridge" network. + +


+ + > **Deprecated**: This field is only propagated when attached to the + > default "bridge" network. Use the information from the "bridge" + > network inside the `Networks` map instead, which contains the same + > information. This field was deprecated in Docker 1.9 and is scheduled + > to be removed in Docker 17.12.0 + type: "string" + example: "172.17.0.4" + IPPrefixLen: + description: | + Mask length of the IPv4 address. + +


+ + > **Deprecated**: This field is only propagated when attached to the + > default "bridge" network. Use the information from the "bridge" + > network inside the `Networks` map instead, which contains the same + > information. This field was deprecated in Docker 1.9 and is scheduled + > to be removed in Docker 17.12.0 + type: "integer" + example: 16 + IPv6Gateway: + description: | + IPv6 gateway address for this network. + +


+ + > **Deprecated**: This field is only propagated when attached to the + > default "bridge" network. Use the information from the "bridge" + > network inside the `Networks` map instead, which contains the same + > information. This field was deprecated in Docker 1.9 and is scheduled + > to be removed in Docker 17.12.0 + type: "string" + example: "2001:db8:2::100" + MacAddress: + description: | + MAC address for the container on the default "bridge" network. + +


+ + > **Deprecated**: This field is only propagated when attached to the + > default "bridge" network. Use the information from the "bridge" + > network inside the `Networks` map instead, which contains the same + > information. This field was deprecated in Docker 1.9 and is scheduled + > to be removed in Docker 17.12.0 + type: "string" + example: "02:42:ac:11:00:04" + Networks: + description: | + Information about all networks that the container is connected to. + type: "object" + additionalProperties: + $ref: "#/definitions/EndpointSettings" + + Address: + description: Address represents an IPv4 or IPv6 IP address. + type: "object" + properties: + Addr: + description: IP address. + type: "string" + PrefixLen: + description: Mask length of the IP address. + type: "integer" + + PortMap: + description: | + PortMap describes the mapping of container ports to host ports, using the + container's port-number and protocol as key in the format `/`, + for example, `80/udp`. + + If a container's port is mapped for multiple protocols, separate entries + are added to the mapping table. + type: "object" + additionalProperties: + type: "array" + x-nullable: true + items: + $ref: "#/definitions/PortBinding" + example: + "443/tcp": + - HostIp: "127.0.0.1" + HostPort: "4443" + "80/tcp": + - HostIp: "0.0.0.0" + HostPort: "80" + - HostIp: "0.0.0.0" + HostPort: "8080" + "80/udp": + - HostIp: "0.0.0.0" + HostPort: "80" + "53/udp": + - HostIp: "0.0.0.0" + HostPort: "53" + "2377/tcp": null + + PortBinding: + description: | + PortBinding represents a binding between a host IP address and a host + port. + type: "object" + properties: + HostIp: + description: "Host IP address that the container's port is mapped to." + type: "string" + example: "127.0.0.1" + HostPort: + description: "Host port number that the container's port is mapped to." + type: "string" + example: "4443" + + GraphDriverData: + description: | + Information about the storage driver used to store the container's and + image's filesystem. + type: "object" + required: [Name, Data] + properties: + Name: + description: "Name of the storage driver." + type: "string" + x-nullable: false + example: "overlay2" + Data: + description: | + Low-level storage metadata, provided as key/value pairs. + + This information is driver-specific, and depends on the storage-driver + in use, and should be used for informational purposes only. + type: "object" + x-nullable: false + additionalProperties: + type: "string" + example: { + "MergedDir": "/var/lib/docker/overlay2/ef749362d13333e65fc95c572eb525abbe0052e16e086cb64bc3b98ae9aa6d74/merged", + "UpperDir": "/var/lib/docker/overlay2/ef749362d13333e65fc95c572eb525abbe0052e16e086cb64bc3b98ae9aa6d74/diff", + "WorkDir": "/var/lib/docker/overlay2/ef749362d13333e65fc95c572eb525abbe0052e16e086cb64bc3b98ae9aa6d74/work" + } + + ImageInspect: + description: | + Information about an image in the local image cache. + type: "object" + properties: + Id: + description: | + ID is the content-addressable ID of an image. + + This identifier is a content-addressable digest calculated from the + image's configuration (which includes the digests of layers used by + the image). + + Note that this digest differs from the `RepoDigests` below, which + holds digests of image manifests that reference the image. + type: "string" + x-nullable: false + example: "sha256:ec3f0931a6e6b6855d76b2d7b0be30e81860baccd891b2e243280bf1cd8ad710" + RepoTags: + description: | + List of image names/tags in the local image cache that reference this + image. + + Multiple image tags can refer to the same image, and this list may be + empty if no tags reference the image, in which case the image is + "untagged", in which case it can still be referenced by its ID. + type: "array" + items: + type: "string" + example: + - "example:1.0" + - "example:latest" + - "example:stable" + - "internal.registry.example.com:5000/example:1.0" + RepoDigests: + description: | + List of content-addressable digests of locally available image manifests + that the image is referenced from. Multiple manifests can refer to the + same image. + + These digests are usually only available if the image was either pulled + from a registry, or if the image was pushed to a registry, which is when + the manifest is generated and its digest calculated. + type: "array" + items: + type: "string" + example: + - "example@sha256:afcc7f1ac1b49db317a7196c902e61c6c3c4607d63599ee1a82d702d249a0ccb" + - "internal.registry.example.com:5000/example@sha256:b69959407d21e8a062e0416bf13405bb2b71ed7a84dde4158ebafacfa06f5578" + Parent: + description: | + ID of the parent image. + + Depending on how the image was created, this field may be empty and + is only set for images that were built/created locally. This field + is empty if the image was pulled from an image registry. + type: "string" + x-nullable: false + example: "" + Comment: + description: | + Optional message that was set when committing or importing the image. + type: "string" + x-nullable: false + example: "" + Created: + description: | + Date and time at which the image was created, formatted in + [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format with nano-seconds. + type: "string" + x-nullable: false + example: "2022-02-04T21:20:12.497794809Z" + Container: + description: | + The ID of the container that was used to create the image. + + Depending on how the image was created, this field may be empty. + type: "string" + x-nullable: false + example: "65974bc86f1770ae4bff79f651ebdbce166ae9aada632ee3fa9af3a264911735" + ContainerConfig: + $ref: "#/definitions/ContainerConfig" + DockerVersion: + description: | + The version of Docker that was used to build the image. + + Depending on how the image was created, this field may be empty. + type: "string" + x-nullable: false + example: "20.10.7" + Author: + description: | + Name of the author that was specified when committing the image, or as + specified through MAINTAINER (deprecated) in the Dockerfile. + type: "string" + x-nullable: false + example: "" + Config: + $ref: "#/definitions/ContainerConfig" + Architecture: + description: | + Hardware CPU architecture that the image runs on. + type: "string" + x-nullable: false + example: "arm" + Variant: + description: | + CPU architecture variant (presently ARM-only). + type: "string" + x-nullable: true + example: "v7" + Os: + description: | + Operating System the image is built to run on. + type: "string" + x-nullable: false + example: "linux" + OsVersion: + description: | + Operating System version the image is built to run on (especially + for Windows). + type: "string" + example: "" + x-nullable: true + Size: + description: | + Total size of the image including all layers it is composed of. + type: "integer" + format: "int64" + x-nullable: false + example: 1239828 + VirtualSize: + description: | + Total size of the image including all layers it is composed of. + + In versions of Docker before v1.10, this field was calculated from + the image itself and all of its parent images. Docker v1.10 and up + store images self-contained, and no longer use a parent-chain, making + this field an equivalent of the Size field. + + This field is kept for backward compatibility, but may be removed in + a future version of the API. + type: "integer" + format: "int64" + x-nullable: false + example: 1239828 + GraphDriver: + $ref: "#/definitions/GraphDriverData" + RootFS: + description: | + Information about the image's RootFS, including the layer IDs. + type: "object" + required: [Type] + properties: + Type: + type: "string" + x-nullable: false + example: "layers" + Layers: + type: "array" + items: + type: "string" + example: + - "sha256:1834950e52ce4d5a88a1bbd131c537f4d0e56d10ff0dd69e66be3b7dfa9df7e6" + - "sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef" + Metadata: + description: | + Additional metadata of the image in the local cache. This information + is local to the daemon, and not part of the image itself. + type: "object" + properties: + LastTagTime: + description: | + Date and time at which the image was last tagged in + [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format with nano-seconds. + + This information is only available if the image was tagged locally, + and omitted otherwise. + type: "string" + format: "dateTime" + example: "2022-02-28T14:40:02.623929178Z" + x-nullable: true + ImageSummary: + type: "object" + required: + - Id + - ParentId + - RepoTags + - RepoDigests + - Created + - Size + - SharedSize + - VirtualSize + - Labels + - Containers + properties: + Id: + description: | + ID is the content-addressable ID of an image. + + This identifier is a content-addressable digest calculated from the + image's configuration (which includes the digests of layers used by + the image). + + Note that this digest differs from the `RepoDigests` below, which + holds digests of image manifests that reference the image. + type: "string" + x-nullable: false + example: "sha256:ec3f0931a6e6b6855d76b2d7b0be30e81860baccd891b2e243280bf1cd8ad710" + ParentId: + description: | + ID of the parent image. + + Depending on how the image was created, this field may be empty and + is only set for images that were built/created locally. This field + is empty if the image was pulled from an image registry. + type: "string" + x-nullable: false + example: "" + RepoTags: + description: | + List of image names/tags in the local image cache that reference this + image. + + Multiple image tags can refer to the same image, and this list may be + empty if no tags reference the image, in which case the image is + "untagged", in which case it can still be referenced by its ID. + type: "array" + x-nullable: false + items: + type: "string" + example: + - "example:1.0" + - "example:latest" + - "example:stable" + - "internal.registry.example.com:5000/example:1.0" + RepoDigests: + description: | + List of content-addressable digests of locally available image manifests + that the image is referenced from. Multiple manifests can refer to the + same image. + + These digests are usually only available if the image was either pulled + from a registry, or if the image was pushed to a registry, which is when + the manifest is generated and its digest calculated. + type: "array" + x-nullable: false + items: + type: "string" + example: + - "example@sha256:afcc7f1ac1b49db317a7196c902e61c6c3c4607d63599ee1a82d702d249a0ccb" + - "internal.registry.example.com:5000/example@sha256:b69959407d21e8a062e0416bf13405bb2b71ed7a84dde4158ebafacfa06f5578" + Created: + description: | + Date and time at which the image was created as a Unix timestamp + (number of seconds sinds EPOCH). + type: "integer" + x-nullable: false + example: "1644009612" + Size: + description: | + Total size of the image including all layers it is composed of. + type: "integer" + format: "int64" + x-nullable: false + example: 172064416 + SharedSize: + description: | + Total size of image layers that are shared between this image and other + images. + + This size is not calculated by default. `-1` indicates that the value + has not been set / calculated. + type: "integer" + format: "int64" + x-nullable: false + example: 1239828 + VirtualSize: + description: | + Total size of the image including all layers it is composed of. + + In versions of Docker before v1.10, this field was calculated from + the image itself and all of its parent images. Docker v1.10 and up + store images self-contained, and no longer use a parent-chain, making + this field an equivalent of the Size field. + + This field is kept for backward compatibility, but may be removed in + a future version of the API. + type: "integer" + format: "int64" + x-nullable: false + example: 172064416 + Labels: + description: "User-defined key/value metadata." + type: "object" + x-nullable: false + additionalProperties: + type: "string" + example: + com.example.some-label: "some-value" + com.example.some-other-label: "some-other-value" + Containers: + description: | + Number of containers using this image. Includes both stopped and running + containers. + + This size is not calculated by default, and depends on which API endpoint + is used. `-1` indicates that the value has not been set / calculated. + x-nullable: false + type: "integer" + example: 2 + + AuthConfig: + type: "object" + properties: + username: + type: "string" + password: + type: "string" + email: + type: "string" + serveraddress: + type: "string" + example: + username: "hannibal" + password: "xxxx" + serveraddress: "https://index.docker.io/v1/" + + ProcessConfig: + type: "object" + properties: + privileged: + type: "boolean" + user: + type: "string" + tty: + type: "boolean" + entrypoint: + type: "string" + arguments: + type: "array" + items: + type: "string" + + Volume: + type: "object" + required: [Name, Driver, Mountpoint, Labels, Scope, Options] + properties: + Name: + type: "string" + description: "Name of the volume." + x-nullable: false + example: "tardis" + Driver: + type: "string" + description: "Name of the volume driver used by the volume." + x-nullable: false + example: "custom" + Mountpoint: + type: "string" + description: "Mount path of the volume on the host." + x-nullable: false + example: "/var/lib/docker/volumes/tardis" + CreatedAt: + type: "string" + format: "dateTime" + description: "Date/Time the volume was created." + example: "2016-06-07T20:31:11.853781916Z" + Status: + type: "object" + description: | + Low-level details about the volume, provided by the volume driver. + Details are returned as a map with key/value pairs: + `{"key":"value","key2":"value2"}`. + + The `Status` field is optional, and is omitted if the volume driver + does not support this feature. + additionalProperties: + type: "object" + example: + hello: "world" + Labels: + type: "object" + description: "User-defined key/value metadata." + x-nullable: false + additionalProperties: + type: "string" + example: + com.example.some-label: "some-value" + com.example.some-other-label: "some-other-value" + Scope: + type: "string" + description: | + The level at which the volume exists. Either `global` for cluster-wide, + or `local` for machine level. + default: "local" + x-nullable: false + enum: ["local", "global"] + example: "local" + ClusterVolume: + $ref: "#/definitions/ClusterVolume" + Options: + type: "object" + description: | + The driver specific options used when creating the volume. + additionalProperties: + type: "string" + example: + device: "tmpfs" + o: "size=100m,uid=1000" + type: "tmpfs" + UsageData: + type: "object" + x-nullable: true + x-go-name: "UsageData" + required: [Size, RefCount] + description: | + Usage details about the volume. This information is used by the + `GET /system/df` endpoint, and omitted in other endpoints. + properties: + Size: + type: "integer" + format: "int64" + default: -1 + description: | + Amount of disk space used by the volume (in bytes). This information + is only available for volumes created with the `"local"` volume + driver. For volumes created with other volume drivers, this field + is set to `-1` ("not available") + x-nullable: false + RefCount: + type: "integer" + format: "int64" + default: -1 + description: | + The number of containers referencing this volume. This field + is set to `-1` if the reference-count is not available. + x-nullable: false + + VolumeCreateOptions: + description: "Volume configuration" + type: "object" + title: "VolumeConfig" + x-go-name: "CreateOptions" + properties: + Name: + description: | + The new volume's name. If not specified, Docker generates a name. + type: "string" + x-nullable: false + example: "tardis" + Driver: + description: "Name of the volume driver to use." + type: "string" + default: "local" + x-nullable: false + example: "custom" + DriverOpts: + description: | + A mapping of driver options and values. These options are + passed directly to the driver and are driver specific. + type: "object" + additionalProperties: + type: "string" + example: + device: "tmpfs" + o: "size=100m,uid=1000" + type: "tmpfs" + Labels: + description: "User-defined key/value metadata." + type: "object" + additionalProperties: + type: "string" + example: + com.example.some-label: "some-value" + com.example.some-other-label: "some-other-value" + ClusterVolumeSpec: + $ref: "#/definitions/ClusterVolumeSpec" + + VolumeListResponse: + type: "object" + title: "VolumeListResponse" + x-go-name: "ListResponse" + description: "Volume list response" + properties: + Volumes: + type: "array" + description: "List of volumes" + items: + $ref: "#/definitions/Volume" + Warnings: + type: "array" + description: | + Warnings that occurred when fetching the list of volumes. + items: + type: "string" + example: [] + + Network: + type: "object" + properties: + Name: + type: "string" + Id: + type: "string" + Created: + type: "string" + format: "dateTime" + Scope: + type: "string" + Driver: + type: "string" + EnableIPv6: + type: "boolean" + IPAM: + $ref: "#/definitions/IPAM" + Internal: + type: "boolean" + Attachable: + type: "boolean" + Ingress: + type: "boolean" + Containers: + type: "object" + additionalProperties: + $ref: "#/definitions/NetworkContainer" + Options: + type: "object" + additionalProperties: + type: "string" + Labels: + type: "object" + additionalProperties: + type: "string" + example: + Name: "net01" + Id: "7d86d31b1478e7cca9ebed7e73aa0fdeec46c5ca29497431d3007d2d9e15ed99" + Created: "2016-10-19T04:33:30.360899459Z" + Scope: "local" + Driver: "bridge" + EnableIPv6: false + IPAM: + Driver: "default" + Config: + - Subnet: "172.19.0.0/16" + Gateway: "172.19.0.1" + Options: + foo: "bar" + Internal: false + Attachable: false + Ingress: false + Containers: + 19a4d5d687db25203351ed79d478946f861258f018fe384f229f2efa4b23513c: + Name: "test" + EndpointID: "628cadb8bcb92de107b2a1e516cbffe463e321f548feb37697cce00ad694f21a" + MacAddress: "02:42:ac:13:00:02" + IPv4Address: "172.19.0.2/16" + IPv6Address: "" + Options: + com.docker.network.bridge.default_bridge: "true" + com.docker.network.bridge.enable_icc: "true" + com.docker.network.bridge.enable_ip_masquerade: "true" + com.docker.network.bridge.host_binding_ipv4: "0.0.0.0" + com.docker.network.bridge.name: "docker0" + com.docker.network.driver.mtu: "1500" + Labels: + com.example.some-label: "some-value" + com.example.some-other-label: "some-other-value" + IPAM: + type: "object" + properties: + Driver: + description: "Name of the IPAM driver to use." + type: "string" + default: "default" + Config: + description: | + List of IPAM configuration options, specified as a map: + + ``` + {"Subnet": , "IPRange": , "Gateway": , "AuxAddress": } + ``` + type: "array" + items: + $ref: "#/definitions/IPAMConfig" + Options: + description: "Driver-specific options, specified as a map." + type: "object" + additionalProperties: + type: "string" + + IPAMConfig: + type: "object" + properties: + Subnet: + type: "string" + IPRange: + type: "string" + Gateway: + type: "string" + AuxiliaryAddresses: + type: "object" + additionalProperties: + type: "string" + + NetworkContainer: + type: "object" + properties: + Name: + type: "string" + EndpointID: + type: "string" + MacAddress: + type: "string" + IPv4Address: + type: "string" + IPv6Address: + type: "string" + + BuildInfo: + type: "object" + properties: + id: + type: "string" + stream: + type: "string" + error: + type: "string" + errorDetail: + $ref: "#/definitions/ErrorDetail" + status: + type: "string" + progress: + type: "string" + progressDetail: + $ref: "#/definitions/ProgressDetail" + aux: + $ref: "#/definitions/ImageID" + + BuildCache: + type: "object" + description: | + BuildCache contains information about a build cache record. + properties: + ID: + type: "string" + description: | + Unique ID of the build cache record. + example: "ndlpt0hhvkqcdfkputsk4cq9c" + Parent: + description: | + ID of the parent build cache record. + + > **Deprecated**: This field is deprecated, and omitted if empty. + type: "string" + x-nullable: true + example: "" + Parents: + description: | + List of parent build cache record IDs. + type: "array" + items: + type: "string" + x-nullable: true + example: ["hw53o5aio51xtltp5xjp8v7fx"] + Type: + type: "string" + description: | + Cache record type. + example: "regular" + # see https://github.com/moby/buildkit/blob/fce4a32258dc9d9664f71a4831d5de10f0670677/client/diskusage.go#L75-L84 + enum: + - "internal" + - "frontend" + - "source.local" + - "source.git.checkout" + - "exec.cachemount" + - "regular" + Description: + type: "string" + description: | + Description of the build-step that produced the build cache. + example: "mount / from exec /bin/sh -c echo 'Binary::apt::APT::Keep-Downloaded-Packages \"true\";' > /etc/apt/apt.conf.d/keep-cache" + InUse: + type: "boolean" + description: | + Indicates if the build cache is in use. + example: false + Shared: + type: "boolean" + description: | + Indicates if the build cache is shared. + example: true + Size: + description: | + Amount of disk space used by the build cache (in bytes). + type: "integer" + example: 51 + CreatedAt: + description: | + Date and time at which the build cache was created in + [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format with nano-seconds. + type: "string" + format: "dateTime" + example: "2016-08-18T10:44:24.496525531Z" + LastUsedAt: + description: | + Date and time at which the build cache was last used in + [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format with nano-seconds. + type: "string" + format: "dateTime" + x-nullable: true + example: "2017-08-09T07:09:37.632105588Z" + UsageCount: + type: "integer" + example: 26 + + ImageID: + type: "object" + description: "Image ID or Digest" + properties: + ID: + type: "string" + example: + ID: "sha256:85f05633ddc1c50679be2b16a0479ab6f7637f8884e0cfe0f4d20e1ebb3d6e7c" + + CreateImageInfo: + type: "object" + properties: + id: + type: "string" + error: + type: "string" + errorDetail: + $ref: "#/definitions/ErrorDetail" + status: + type: "string" + progress: + type: "string" + progressDetail: + $ref: "#/definitions/ProgressDetail" + + PushImageInfo: + type: "object" + properties: + error: + type: "string" + status: + type: "string" + progress: + type: "string" + progressDetail: + $ref: "#/definitions/ProgressDetail" + + ErrorDetail: + type: "object" + properties: + code: + type: "integer" + message: + type: "string" + + ProgressDetail: + type: "object" + properties: + current: + type: "integer" + total: + type: "integer" + + ErrorResponse: + description: "Represents an error." + type: "object" + required: ["message"] + properties: + message: + description: "The error message." + type: "string" + x-nullable: false + example: + message: "Something went wrong." + + IdResponse: + description: "Response to an API call that returns just an Id" + type: "object" + required: ["Id"] + properties: + Id: + description: "The id of the newly created object." + type: "string" + x-nullable: false + + EndpointSettings: + description: "Configuration for a network endpoint." + type: "object" + properties: + # Configurations + IPAMConfig: + $ref: "#/definitions/EndpointIPAMConfig" + Links: + type: "array" + items: + type: "string" + example: + - "container_1" + - "container_2" + Aliases: + type: "array" + items: + type: "string" + example: + - "server_x" + - "server_y" + + # Operational data + NetworkID: + description: | + Unique ID of the network. + type: "string" + example: "08754567f1f40222263eab4102e1c733ae697e8e354aa9cd6e18d7402835292a" + EndpointID: + description: | + Unique ID for the service endpoint in a Sandbox. + type: "string" + example: "b88f5b905aabf2893f3cbc4ee42d1ea7980bbc0a92e2c8922b1e1795298afb0b" + Gateway: + description: | + Gateway address for this network. + type: "string" + example: "172.17.0.1" + IPAddress: + description: | + IPv4 address. + type: "string" + example: "172.17.0.4" + IPPrefixLen: + description: | + Mask length of the IPv4 address. + type: "integer" + example: 16 + IPv6Gateway: + description: | + IPv6 gateway address. + type: "string" + example: "2001:db8:2::100" + GlobalIPv6Address: + description: | + Global IPv6 address. + type: "string" + example: "2001:db8::5689" + GlobalIPv6PrefixLen: + description: | + Mask length of the global IPv6 address. + type: "integer" + format: "int64" + example: 64 + MacAddress: + description: | + MAC address for the endpoint on this network. + type: "string" + example: "02:42:ac:11:00:04" + DriverOpts: + description: | + DriverOpts is a mapping of driver options and values. These options + are passed directly to the driver and are driver specific. + type: "object" + x-nullable: true + additionalProperties: + type: "string" + example: + com.example.some-label: "some-value" + com.example.some-other-label: "some-other-value" + + EndpointIPAMConfig: + description: | + EndpointIPAMConfig represents an endpoint's IPAM configuration. + type: "object" + x-nullable: true + properties: + IPv4Address: + type: "string" + example: "172.20.30.33" + IPv6Address: + type: "string" + example: "2001:db8:abcd::3033" + LinkLocalIPs: + type: "array" + items: + type: "string" + example: + - "169.254.34.68" + - "fe80::3468" + + PluginMount: + type: "object" + x-nullable: false + required: [Name, Description, Settable, Source, Destination, Type, Options] + properties: + Name: + type: "string" + x-nullable: false + example: "some-mount" + Description: + type: "string" + x-nullable: false + example: "This is a mount that's used by the plugin." + Settable: + type: "array" + items: + type: "string" + Source: + type: "string" + example: "/var/lib/docker/plugins/" + Destination: + type: "string" + x-nullable: false + example: "/mnt/state" + Type: + type: "string" + x-nullable: false + example: "bind" + Options: + type: "array" + items: + type: "string" + example: + - "rbind" + - "rw" + + PluginDevice: + type: "object" + required: [Name, Description, Settable, Path] + x-nullable: false + properties: + Name: + type: "string" + x-nullable: false + Description: + type: "string" + x-nullable: false + Settable: + type: "array" + items: + type: "string" + Path: + type: "string" + example: "/dev/fuse" + + PluginEnv: + type: "object" + x-nullable: false + required: [Name, Description, Settable, Value] + properties: + Name: + x-nullable: false + type: "string" + Description: + x-nullable: false + type: "string" + Settable: + type: "array" + items: + type: "string" + Value: + type: "string" + + PluginInterfaceType: + type: "object" + x-nullable: false + required: [Prefix, Capability, Version] + properties: + Prefix: + type: "string" + x-nullable: false + Capability: + type: "string" + x-nullable: false + Version: + type: "string" + x-nullable: false + + PluginPrivilege: + description: | + Describes a permission the user has to accept upon installing + the plugin. + type: "object" + x-go-name: "PluginPrivilege" + properties: + Name: + type: "string" + example: "network" + Description: + type: "string" + Value: + type: "array" + items: + type: "string" + example: + - "host" + + Plugin: + description: "A plugin for the Engine API" + type: "object" + required: [Settings, Enabled, Config, Name] + properties: + Id: + type: "string" + example: "5724e2c8652da337ab2eedd19fc6fc0ec908e4bd907c7421bf6a8dfc70c4c078" + Name: + type: "string" + x-nullable: false + example: "tiborvass/sample-volume-plugin" + Enabled: + description: + True if the plugin is running. False if the plugin is not running, + only installed. + type: "boolean" + x-nullable: false + example: true + Settings: + description: "Settings that can be modified by users." + type: "object" + x-nullable: false + required: [Args, Devices, Env, Mounts] + properties: + Mounts: + type: "array" + items: + $ref: "#/definitions/PluginMount" + Env: + type: "array" + items: + type: "string" + example: + - "DEBUG=0" + Args: + type: "array" + items: + type: "string" + Devices: + type: "array" + items: + $ref: "#/definitions/PluginDevice" + PluginReference: + description: "plugin remote reference used to push/pull the plugin" + type: "string" + x-nullable: false + example: "localhost:5000/tiborvass/sample-volume-plugin:latest" + Config: + description: "The config of a plugin." + type: "object" + x-nullable: false + required: + - Description + - Documentation + - Interface + - Entrypoint + - WorkDir + - Network + - Linux + - PidHost + - PropagatedMount + - IpcHost + - Mounts + - Env + - Args + properties: + DockerVersion: + description: "Docker Version used to create the plugin" + type: "string" + x-nullable: false + example: "17.06.0-ce" + Description: + type: "string" + x-nullable: false + example: "A sample volume plugin for Docker" + Documentation: + type: "string" + x-nullable: false + example: "https://docs.docker.com/engine/extend/plugins/" + Interface: + description: "The interface between Docker and the plugin" + x-nullable: false + type: "object" + required: [Types, Socket] + properties: + Types: + type: "array" + items: + $ref: "#/definitions/PluginInterfaceType" + example: + - "docker.volumedriver/1.0" + Socket: + type: "string" + x-nullable: false + example: "plugins.sock" + ProtocolScheme: + type: "string" + example: "some.protocol/v1.0" + description: "Protocol to use for clients connecting to the plugin." + enum: + - "" + - "moby.plugins.http/v1" + Entrypoint: + type: "array" + items: + type: "string" + example: + - "/usr/bin/sample-volume-plugin" + - "/data" + WorkDir: + type: "string" + x-nullable: false + example: "/bin/" + User: + type: "object" + x-nullable: false + properties: + UID: + type: "integer" + format: "uint32" + example: 1000 + GID: + type: "integer" + format: "uint32" + example: 1000 + Network: + type: "object" + x-nullable: false + required: [Type] + properties: + Type: + x-nullable: false + type: "string" + example: "host" + Linux: + type: "object" + x-nullable: false + required: [Capabilities, AllowAllDevices, Devices] + properties: + Capabilities: + type: "array" + items: + type: "string" + example: + - "CAP_SYS_ADMIN" + - "CAP_SYSLOG" + AllowAllDevices: + type: "boolean" + x-nullable: false + example: false + Devices: + type: "array" + items: + $ref: "#/definitions/PluginDevice" + PropagatedMount: + type: "string" + x-nullable: false + example: "/mnt/volumes" + IpcHost: + type: "boolean" + x-nullable: false + example: false + PidHost: + type: "boolean" + x-nullable: false + example: false + Mounts: + type: "array" + items: + $ref: "#/definitions/PluginMount" + Env: + type: "array" + items: + $ref: "#/definitions/PluginEnv" + example: + - Name: "DEBUG" + Description: "If set, prints debug messages" + Settable: null + Value: "0" + Args: + type: "object" + x-nullable: false + required: [Name, Description, Settable, Value] + properties: + Name: + x-nullable: false + type: "string" + example: "args" + Description: + x-nullable: false + type: "string" + example: "command line arguments" + Settable: + type: "array" + items: + type: "string" + Value: + type: "array" + items: + type: "string" + rootfs: + type: "object" + properties: + type: + type: "string" + example: "layers" + diff_ids: + type: "array" + items: + type: "string" + example: + - "sha256:675532206fbf3030b8458f88d6e26d4eb1577688a25efec97154c94e8b6b4887" + - "sha256:e216a057b1cb1efc11f8a268f37ef62083e70b1b38323ba252e25ac88904a7e8" + + ObjectVersion: + description: | + The version number of the object such as node, service, etc. This is needed + to avoid conflicting writes. The client must send the version number along + with the modified specification when updating these objects. + + This approach ensures safe concurrency and determinism in that the change + on the object may not be applied if the version number has changed from the + last read. In other words, if two update requests specify the same base + version, only one of the requests can succeed. As a result, two separate + update requests that happen at the same time will not unintentionally + overwrite each other. + type: "object" + properties: + Index: + type: "integer" + format: "uint64" + example: 373531 + + NodeSpec: + type: "object" + properties: + Name: + description: "Name for the node." + type: "string" + example: "my-node" + Labels: + description: "User-defined key/value metadata." + type: "object" + additionalProperties: + type: "string" + Role: + description: "Role of the node." + type: "string" + enum: + - "worker" + - "manager" + example: "manager" + Availability: + description: "Availability of the node." + type: "string" + enum: + - "active" + - "pause" + - "drain" + example: "active" + example: + Availability: "active" + Name: "node-name" + Role: "manager" + Labels: + foo: "bar" + + Node: + type: "object" + properties: + ID: + type: "string" + example: "24ifsmvkjbyhk" + Version: + $ref: "#/definitions/ObjectVersion" + CreatedAt: + description: | + Date and time at which the node was added to the swarm in + [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format with nano-seconds. + type: "string" + format: "dateTime" + example: "2016-08-18T10:44:24.496525531Z" + UpdatedAt: + description: | + Date and time at which the node was last updated in + [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format with nano-seconds. + type: "string" + format: "dateTime" + example: "2017-08-09T07:09:37.632105588Z" + Spec: + $ref: "#/definitions/NodeSpec" + Description: + $ref: "#/definitions/NodeDescription" + Status: + $ref: "#/definitions/NodeStatus" + ManagerStatus: + $ref: "#/definitions/ManagerStatus" + + NodeDescription: + description: | + NodeDescription encapsulates the properties of the Node as reported by the + agent. + type: "object" + properties: + Hostname: + type: "string" + example: "bf3067039e47" + Platform: + $ref: "#/definitions/Platform" + Resources: + $ref: "#/definitions/ResourceObject" + Engine: + $ref: "#/definitions/EngineDescription" + TLSInfo: + $ref: "#/definitions/TLSInfo" + + Platform: + description: | + Platform represents the platform (Arch/OS). + type: "object" + properties: + Architecture: + description: | + Architecture represents the hardware architecture (for example, + `x86_64`). + type: "string" + example: "x86_64" + OS: + description: | + OS represents the Operating System (for example, `linux` or `windows`). + type: "string" + example: "linux" + + EngineDescription: + description: "EngineDescription provides information about an engine." + type: "object" + properties: + EngineVersion: + type: "string" + example: "17.06.0" + Labels: + type: "object" + additionalProperties: + type: "string" + example: + foo: "bar" + Plugins: + type: "array" + items: + type: "object" + properties: + Type: + type: "string" + Name: + type: "string" + example: + - Type: "Log" + Name: "awslogs" + - Type: "Log" + Name: "fluentd" + - Type: "Log" + Name: "gcplogs" + - Type: "Log" + Name: "gelf" + - Type: "Log" + Name: "journald" + - Type: "Log" + Name: "json-file" + - Type: "Log" + Name: "logentries" + - Type: "Log" + Name: "splunk" + - Type: "Log" + Name: "syslog" + - Type: "Network" + Name: "bridge" + - Type: "Network" + Name: "host" + - Type: "Network" + Name: "ipvlan" + - Type: "Network" + Name: "macvlan" + - Type: "Network" + Name: "null" + - Type: "Network" + Name: "overlay" + - Type: "Volume" + Name: "local" + - Type: "Volume" + Name: "localhost:5000/vieux/sshfs:latest" + - Type: "Volume" + Name: "vieux/sshfs:latest" + + TLSInfo: + description: | + Information about the issuer of leaf TLS certificates and the trusted root + CA certificate. + type: "object" + properties: + TrustRoot: + description: | + The root CA certificate(s) that are used to validate leaf TLS + certificates. + type: "string" + CertIssuerSubject: + description: + The base64-url-safe-encoded raw subject bytes of the issuer. + type: "string" + CertIssuerPublicKey: + description: | + The base64-url-safe-encoded raw public key bytes of the issuer. + type: "string" + example: + TrustRoot: | + -----BEGIN CERTIFICATE----- + MIIBajCCARCgAwIBAgIUbYqrLSOSQHoxD8CwG6Bi2PJi9c8wCgYIKoZIzj0EAwIw + EzERMA8GA1UEAxMIc3dhcm0tY2EwHhcNMTcwNDI0MjE0MzAwWhcNMzcwNDE5MjE0 + MzAwWjATMREwDwYDVQQDEwhzd2FybS1jYTBZMBMGByqGSM49AgEGCCqGSM49AwEH + A0IABJk/VyMPYdaqDXJb/VXh5n/1Yuv7iNrxV3Qb3l06XD46seovcDWs3IZNV1lf + 3Skyr0ofcchipoiHkXBODojJydSjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMB + Af8EBTADAQH/MB0GA1UdDgQWBBRUXxuRcnFjDfR/RIAUQab8ZV/n4jAKBggqhkjO + PQQDAgNIADBFAiAy+JTe6Uc3KyLCMiqGl2GyWGQqQDEcO3/YG36x7om65AIhAJvz + pxv6zFeVEkAEEkqIYi0omA9+CjanB/6Bz4n1uw8H + -----END CERTIFICATE----- + CertIssuerSubject: "MBMxETAPBgNVBAMTCHN3YXJtLWNh" + CertIssuerPublicKey: "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEmT9XIw9h1qoNclv9VeHmf/Vi6/uI2vFXdBveXTpcPjqx6i9wNazchk1XWV/dKTKvSh9xyGKmiIeRcE4OiMnJ1A==" + + NodeStatus: + description: | + NodeStatus represents the status of a node. + + It provides the current status of the node, as seen by the manager. + type: "object" + properties: + State: + $ref: "#/definitions/NodeState" + Message: + type: "string" + example: "" + Addr: + description: "IP address of the node." + type: "string" + example: "172.17.0.2" + + NodeState: + description: "NodeState represents the state of a node." + type: "string" + enum: + - "unknown" + - "down" + - "ready" + - "disconnected" + example: "ready" + + ManagerStatus: + description: | + ManagerStatus represents the status of a manager. + + It provides the current status of a node's manager component, if the node + is a manager. + x-nullable: true + type: "object" + properties: + Leader: + type: "boolean" + default: false + example: true + Reachability: + $ref: "#/definitions/Reachability" + Addr: + description: | + The IP address and port at which the manager is reachable. + type: "string" + example: "10.0.0.46:2377" + + Reachability: + description: "Reachability represents the reachability of a node." + type: "string" + enum: + - "unknown" + - "unreachable" + - "reachable" + example: "reachable" + + SwarmSpec: + description: "User modifiable swarm configuration." + type: "object" + properties: + Name: + description: "Name of the swarm." + type: "string" + example: "default" + Labels: + description: "User-defined key/value metadata." + type: "object" + additionalProperties: + type: "string" + example: + com.example.corp.type: "production" + com.example.corp.department: "engineering" + Orchestration: + description: "Orchestration configuration." + type: "object" + x-nullable: true + properties: + TaskHistoryRetentionLimit: + description: | + The number of historic tasks to keep per instance or node. If + negative, never remove completed or failed tasks. + type: "integer" + format: "int64" + example: 10 + Raft: + description: "Raft configuration." + type: "object" + properties: + SnapshotInterval: + description: "The number of log entries between snapshots." + type: "integer" + format: "uint64" + example: 10000 + KeepOldSnapshots: + description: | + The number of snapshots to keep beyond the current snapshot. + type: "integer" + format: "uint64" + LogEntriesForSlowFollowers: + description: | + The number of log entries to keep around to sync up slow followers + after a snapshot is created. + type: "integer" + format: "uint64" + example: 500 + ElectionTick: + description: | + The number of ticks that a follower will wait for a message from + the leader before becoming a candidate and starting an election. + `ElectionTick` must be greater than `HeartbeatTick`. + + A tick currently defaults to one second, so these translate + directly to seconds currently, but this is NOT guaranteed. + type: "integer" + example: 3 + HeartbeatTick: + description: | + The number of ticks between heartbeats. Every HeartbeatTick ticks, + the leader will send a heartbeat to the followers. + + A tick currently defaults to one second, so these translate + directly to seconds currently, but this is NOT guaranteed. + type: "integer" + example: 1 + Dispatcher: + description: "Dispatcher configuration." + type: "object" + x-nullable: true + properties: + HeartbeatPeriod: + description: | + The delay for an agent to send a heartbeat to the dispatcher. + type: "integer" + format: "int64" + example: 5000000000 + CAConfig: + description: "CA configuration." + type: "object" + x-nullable: true + properties: + NodeCertExpiry: + description: "The duration node certificates are issued for." + type: "integer" + format: "int64" + example: 7776000000000000 + ExternalCAs: + description: | + Configuration for forwarding signing requests to an external + certificate authority. + type: "array" + items: + type: "object" + properties: + Protocol: + description: | + Protocol for communication with the external CA (currently + only `cfssl` is supported). + type: "string" + enum: + - "cfssl" + default: "cfssl" + URL: + description: | + URL where certificate signing requests should be sent. + type: "string" + Options: + description: | + An object with key/value pairs that are interpreted as + protocol-specific options for the external CA driver. + type: "object" + additionalProperties: + type: "string" + CACert: + description: | + The root CA certificate (in PEM format) this external CA uses + to issue TLS certificates (assumed to be to the current swarm + root CA certificate if not provided). + type: "string" + SigningCACert: + description: | + The desired signing CA certificate for all swarm node TLS leaf + certificates, in PEM format. + type: "string" + SigningCAKey: + description: | + The desired signing CA key for all swarm node TLS leaf certificates, + in PEM format. + type: "string" + ForceRotate: + description: | + An integer whose purpose is to force swarm to generate a new + signing CA certificate and key, if none have been specified in + `SigningCACert` and `SigningCAKey` + format: "uint64" + type: "integer" + EncryptionConfig: + description: "Parameters related to encryption-at-rest." + type: "object" + properties: + AutoLockManagers: + description: | + If set, generate a key and use it to lock data stored on the + managers. + type: "boolean" + example: false + TaskDefaults: + description: "Defaults for creating tasks in this cluster." + type: "object" + properties: + LogDriver: + description: | + The log driver to use for tasks created in the orchestrator if + unspecified by a service. + + Updating this value only affects new tasks. Existing tasks continue + to use their previously configured log driver until recreated. + type: "object" + properties: + Name: + description: | + The log driver to use as a default for new tasks. + type: "string" + example: "json-file" + Options: + description: | + Driver-specific options for the selectd log driver, specified + as key/value pairs. + type: "object" + additionalProperties: + type: "string" + example: + "max-file": "10" + "max-size": "100m" + + # The Swarm information for `GET /info`. It is the same as `GET /swarm`, but + # without `JoinTokens`. + ClusterInfo: + description: | + ClusterInfo represents information about the swarm as is returned by the + "/info" endpoint. Join-tokens are not included. + x-nullable: true + type: "object" + properties: + ID: + description: "The ID of the swarm." + type: "string" + example: "abajmipo7b4xz5ip2nrla6b11" + Version: + $ref: "#/definitions/ObjectVersion" + CreatedAt: + description: | + Date and time at which the swarm was initialised in + [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format with nano-seconds. + type: "string" + format: "dateTime" + example: "2016-08-18T10:44:24.496525531Z" + UpdatedAt: + description: | + Date and time at which the swarm was last updated in + [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format with nano-seconds. + type: "string" + format: "dateTime" + example: "2017-08-09T07:09:37.632105588Z" + Spec: + $ref: "#/definitions/SwarmSpec" + TLSInfo: + $ref: "#/definitions/TLSInfo" + RootRotationInProgress: + description: | + Whether there is currently a root CA rotation in progress for the swarm + type: "boolean" + example: false + DataPathPort: + description: | + DataPathPort specifies the data path port number for data traffic. + Acceptable port range is 1024 to 49151. + If no port is set or is set to 0, the default port (4789) is used. + type: "integer" + format: "uint32" + default: 4789 + example: 4789 + DefaultAddrPool: + description: | + Default Address Pool specifies default subnet pools for global scope + networks. + type: "array" + items: + type: "string" + format: "CIDR" + example: ["10.10.0.0/16", "20.20.0.0/16"] + SubnetSize: + description: | + SubnetSize specifies the subnet size of the networks created from the + default subnet pool. + type: "integer" + format: "uint32" + maximum: 29 + default: 24 + example: 24 + + JoinTokens: + description: | + JoinTokens contains the tokens workers and managers need to join the swarm. + type: "object" + properties: + Worker: + description: | + The token workers can use to join the swarm. + type: "string" + example: "SWMTKN-1-3pu6hszjas19xyp7ghgosyx9k8atbfcr8p2is99znpy26u2lkl-1awxwuwd3z9j1z3puu7rcgdbx" + Manager: + description: | + The token managers can use to join the swarm. + type: "string" + example: "SWMTKN-1-3pu6hszjas19xyp7ghgosyx9k8atbfcr8p2is99znpy26u2lkl-7p73s1dx5in4tatdymyhg9hu2" + + Swarm: + type: "object" + allOf: + - $ref: "#/definitions/ClusterInfo" + - type: "object" + properties: + JoinTokens: + $ref: "#/definitions/JoinTokens" + + TaskSpec: + description: "User modifiable task configuration." + type: "object" + properties: + PluginSpec: + type: "object" + description: | + Plugin spec for the service. *(Experimental release only.)* + +


+ + > **Note**: ContainerSpec, NetworkAttachmentSpec, and PluginSpec are + > mutually exclusive. PluginSpec is only used when the Runtime field + > is set to `plugin`. NetworkAttachmentSpec is used when the Runtime + > field is set to `attachment`. + properties: + Name: + description: "The name or 'alias' to use for the plugin." + type: "string" + Remote: + description: "The plugin image reference to use." + type: "string" + Disabled: + description: "Disable the plugin once scheduled." + type: "boolean" + PluginPrivilege: + type: "array" + items: + $ref: "#/definitions/PluginPrivilege" + ContainerSpec: + type: "object" + description: | + Container spec for the service. + +


+ + > **Note**: ContainerSpec, NetworkAttachmentSpec, and PluginSpec are + > mutually exclusive. PluginSpec is only used when the Runtime field + > is set to `plugin`. NetworkAttachmentSpec is used when the Runtime + > field is set to `attachment`. + properties: + Image: + description: "The image name to use for the container" + type: "string" + Labels: + description: "User-defined key/value data." + type: "object" + additionalProperties: + type: "string" + Command: + description: "The command to be run in the image." + type: "array" + items: + type: "string" + Args: + description: "Arguments to the command." + type: "array" + items: + type: "string" + Hostname: + description: | + The hostname to use for the container, as a valid + [RFC 1123](https://tools.ietf.org/html/rfc1123) hostname. + type: "string" + Env: + description: | + A list of environment variables in the form `VAR=value`. + type: "array" + items: + type: "string" + Dir: + description: "The working directory for commands to run in." + type: "string" + User: + description: "The user inside the container." + type: "string" + Groups: + type: "array" + description: | + A list of additional groups that the container process will run as. + items: + type: "string" + Privileges: + type: "object" + description: "Security options for the container" + properties: + CredentialSpec: + type: "object" + description: "CredentialSpec for managed service account (Windows only)" + properties: + Config: + type: "string" + example: "0bt9dmxjvjiqermk6xrop3ekq" + description: | + Load credential spec from a Swarm Config with the given ID. + The specified config must also be present in the Configs + field with the Runtime property set. + +


+ + + > **Note**: `CredentialSpec.File`, `CredentialSpec.Registry`, + > and `CredentialSpec.Config` are mutually exclusive. + File: + type: "string" + example: "spec.json" + description: | + Load credential spec from this file. The file is read by + the daemon, and must be present in the `CredentialSpecs` + subdirectory in the docker data directory, which defaults + to `C:\ProgramData\Docker\` on Windows. + + For example, specifying `spec.json` loads + `C:\ProgramData\Docker\CredentialSpecs\spec.json`. + +


+ + > **Note**: `CredentialSpec.File`, `CredentialSpec.Registry`, + > and `CredentialSpec.Config` are mutually exclusive. + Registry: + type: "string" + description: | + Load credential spec from this value in the Windows + registry. The specified registry value must be located in: + + `HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Virtualization\Containers\CredentialSpecs` + +


+ + + > **Note**: `CredentialSpec.File`, `CredentialSpec.Registry`, + > and `CredentialSpec.Config` are mutually exclusive. + SELinuxContext: + type: "object" + description: "SELinux labels of the container" + properties: + Disable: + type: "boolean" + description: "Disable SELinux" + User: + type: "string" + description: "SELinux user label" + Role: + type: "string" + description: "SELinux role label" + Type: + type: "string" + description: "SELinux type label" + Level: + type: "string" + description: "SELinux level label" + TTY: + description: "Whether a pseudo-TTY should be allocated." + type: "boolean" + OpenStdin: + description: "Open `stdin`" + type: "boolean" + ReadOnly: + description: "Mount the container's root filesystem as read only." + type: "boolean" + Mounts: + description: | + Specification for mounts to be added to containers created as part + of the service. + type: "array" + items: + $ref: "#/definitions/Mount" + StopSignal: + description: "Signal to stop the container." + type: "string" + StopGracePeriod: + description: | + Amount of time to wait for the container to terminate before + forcefully killing it. + type: "integer" + format: "int64" + HealthCheck: + $ref: "#/definitions/HealthConfig" + Hosts: + type: "array" + description: | + A list of hostname/IP mappings to add to the container's `hosts` + file. The format of extra hosts is specified in the + [hosts(5)](http://man7.org/linux/man-pages/man5/hosts.5.html) + man page: + + IP_address canonical_hostname [aliases...] + items: + type: "string" + DNSConfig: + description: | + Specification for DNS related configurations in resolver configuration + file (`resolv.conf`). + type: "object" + properties: + Nameservers: + description: "The IP addresses of the name servers." + type: "array" + items: + type: "string" + Search: + description: "A search list for host-name lookup." + type: "array" + items: + type: "string" + Options: + description: | + A list of internal resolver variables to be modified (e.g., + `debug`, `ndots:3`, etc.). + type: "array" + items: + type: "string" + Secrets: + description: | + Secrets contains references to zero or more secrets that will be + exposed to the service. + type: "array" + items: + type: "object" + properties: + File: + description: | + File represents a specific target that is backed by a file. + type: "object" + properties: + Name: + description: | + Name represents the final filename in the filesystem. + type: "string" + UID: + description: "UID represents the file UID." + type: "string" + GID: + description: "GID represents the file GID." + type: "string" + Mode: + description: "Mode represents the FileMode of the file." + type: "integer" + format: "uint32" + SecretID: + description: | + SecretID represents the ID of the specific secret that we're + referencing. + type: "string" + SecretName: + description: | + SecretName is the name of the secret that this references, + but this is just provided for lookup/display purposes. The + secret in the reference will be identified by its ID. + type: "string" + Configs: + description: | + Configs contains references to zero or more configs that will be + exposed to the service. + type: "array" + items: + type: "object" + properties: + File: + description: | + File represents a specific target that is backed by a file. + +


+ + > **Note**: `Configs.File` and `Configs.Runtime` are mutually exclusive + type: "object" + properties: + Name: + description: | + Name represents the final filename in the filesystem. + type: "string" + UID: + description: "UID represents the file UID." + type: "string" + GID: + description: "GID represents the file GID." + type: "string" + Mode: + description: "Mode represents the FileMode of the file." + type: "integer" + format: "uint32" + Runtime: + description: | + Runtime represents a target that is not mounted into the + container but is used by the task + +


+ + > **Note**: `Configs.File` and `Configs.Runtime` are mutually + > exclusive + type: "object" + ConfigID: + description: | + ConfigID represents the ID of the specific config that we're + referencing. + type: "string" + ConfigName: + description: | + ConfigName is the name of the config that this references, + but this is just provided for lookup/display purposes. The + config in the reference will be identified by its ID. + type: "string" + Isolation: + type: "string" + description: | + Isolation technology of the containers running the service. + (Windows only) + enum: + - "default" + - "process" + - "hyperv" + Init: + description: | + Run an init inside the container that forwards signals and reaps + processes. This field is omitted if empty, and the default (as + configured on the daemon) is used. + type: "boolean" + x-nullable: true + Sysctls: + description: | + Set kernel namedspaced parameters (sysctls) in the container. + The Sysctls option on services accepts the same sysctls as the + are supported on containers. Note that while the same sysctls are + supported, no guarantees or checks are made about their + suitability for a clustered environment, and it's up to the user + to determine whether a given sysctl will work properly in a + Service. + type: "object" + additionalProperties: + type: "string" + # This option is not used by Windows containers + CapabilityAdd: + type: "array" + description: | + A list of kernel capabilities to add to the default set + for the container. + items: + type: "string" + example: + - "CAP_NET_RAW" + - "CAP_SYS_ADMIN" + - "CAP_SYS_CHROOT" + - "CAP_SYSLOG" + CapabilityDrop: + type: "array" + description: | + A list of kernel capabilities to drop from the default set + for the container. + items: + type: "string" + example: + - "CAP_NET_RAW" + Ulimits: + description: | + A list of resource limits to set in the container. For example: `{"Name": "nofile", "Soft": 1024, "Hard": 2048}`" + type: "array" + items: + type: "object" + properties: + Name: + description: "Name of ulimit" + type: "string" + Soft: + description: "Soft limit" + type: "integer" + Hard: + description: "Hard limit" + type: "integer" + NetworkAttachmentSpec: + description: | + Read-only spec type for non-swarm containers attached to swarm overlay + networks. + +


+ + > **Note**: ContainerSpec, NetworkAttachmentSpec, and PluginSpec are + > mutually exclusive. PluginSpec is only used when the Runtime field + > is set to `plugin`. NetworkAttachmentSpec is used when the Runtime + > field is set to `attachment`. + type: "object" + properties: + ContainerID: + description: "ID of the container represented by this task" + type: "string" + Resources: + description: | + Resource requirements which apply to each individual container created + as part of the service. + type: "object" + properties: + Limits: + description: "Define resources limits." + $ref: "#/definitions/Limit" + Reservations: + description: "Define resources reservation." + $ref: "#/definitions/ResourceObject" + RestartPolicy: + description: | + Specification for the restart policy which applies to containers + created as part of this service. + type: "object" + properties: + Condition: + description: "Condition for restart." + type: "string" + enum: + - "none" + - "on-failure" + - "any" + Delay: + description: "Delay between restart attempts." + type: "integer" + format: "int64" + MaxAttempts: + description: | + Maximum attempts to restart a given container before giving up + (default value is 0, which is ignored). + type: "integer" + format: "int64" + default: 0 + Window: + description: | + Windows is the time window used to evaluate the restart policy + (default value is 0, which is unbounded). + type: "integer" + format: "int64" + default: 0 + Placement: + type: "object" + properties: + Constraints: + description: | + An array of constraint expressions to limit the set of nodes where + a task can be scheduled. Constraint expressions can either use a + _match_ (`==`) or _exclude_ (`!=`) rule. Multiple constraints find + nodes that satisfy every expression (AND match). Constraints can + match node or Docker Engine labels as follows: + + node attribute | matches | example + ---------------------|--------------------------------|----------------------------------------------- + `node.id` | Node ID | `node.id==2ivku8v2gvtg4` + `node.hostname` | Node hostname | `node.hostname!=node-2` + `node.role` | Node role (`manager`/`worker`) | `node.role==manager` + `node.platform.os` | Node operating system | `node.platform.os==windows` + `node.platform.arch` | Node architecture | `node.platform.arch==x86_64` + `node.labels` | User-defined node labels | `node.labels.security==high` + `engine.labels` | Docker Engine's labels | `engine.labels.operatingsystem==ubuntu-14.04` + + `engine.labels` apply to Docker Engine labels like operating system, + drivers, etc. Swarm administrators add `node.labels` for operational + purposes by using the [`node update endpoint`](#operation/NodeUpdate). + + type: "array" + items: + type: "string" + example: + - "node.hostname!=node3.corp.example.com" + - "node.role!=manager" + - "node.labels.type==production" + - "node.platform.os==linux" + - "node.platform.arch==x86_64" + Preferences: + description: | + Preferences provide a way to make the scheduler aware of factors + such as topology. They are provided in order from highest to + lowest precedence. + type: "array" + items: + type: "object" + properties: + Spread: + type: "object" + properties: + SpreadDescriptor: + description: | + label descriptor, such as `engine.labels.az`. + type: "string" + example: + - Spread: + SpreadDescriptor: "node.labels.datacenter" + - Spread: + SpreadDescriptor: "node.labels.rack" + MaxReplicas: + description: | + Maximum number of replicas for per node (default value is 0, which + is unlimited) + type: "integer" + format: "int64" + default: 0 + Platforms: + description: | + Platforms stores all the platforms that the service's image can + run on. This field is used in the platform filter for scheduling. + If empty, then the platform filter is off, meaning there are no + scheduling restrictions. + type: "array" + items: + $ref: "#/definitions/Platform" + ForceUpdate: + description: | + A counter that triggers an update even if no relevant parameters have + been changed. + type: "integer" + Runtime: + description: | + Runtime is the type of runtime specified for the task executor. + type: "string" + Networks: + description: "Specifies which networks the service should attach to." + type: "array" + items: + $ref: "#/definitions/NetworkAttachmentConfig" + LogDriver: + description: | + Specifies the log driver to use for tasks created from this spec. If + not present, the default one for the swarm will be used, finally + falling back to the engine default if not specified. + type: "object" + properties: + Name: + type: "string" + Options: + type: "object" + additionalProperties: + type: "string" + + TaskState: + type: "string" + enum: + - "new" + - "allocated" + - "pending" + - "assigned" + - "accepted" + - "preparing" + - "ready" + - "starting" + - "running" + - "complete" + - "shutdown" + - "failed" + - "rejected" + - "remove" + - "orphaned" + + Task: + type: "object" + properties: + ID: + description: "The ID of the task." + type: "string" + Version: + $ref: "#/definitions/ObjectVersion" + CreatedAt: + type: "string" + format: "dateTime" + UpdatedAt: + type: "string" + format: "dateTime" + Name: + description: "Name of the task." + type: "string" + Labels: + description: "User-defined key/value metadata." + type: "object" + additionalProperties: + type: "string" + Spec: + $ref: "#/definitions/TaskSpec" + ServiceID: + description: "The ID of the service this task is part of." + type: "string" + Slot: + type: "integer" + NodeID: + description: "The ID of the node that this task is on." + type: "string" + AssignedGenericResources: + $ref: "#/definitions/GenericResources" + Status: + type: "object" + properties: + Timestamp: + type: "string" + format: "dateTime" + State: + $ref: "#/definitions/TaskState" + Message: + type: "string" + Err: + type: "string" + ContainerStatus: + type: "object" + properties: + ContainerID: + type: "string" + PID: + type: "integer" + ExitCode: + type: "integer" + DesiredState: + $ref: "#/definitions/TaskState" + JobIteration: + description: | + If the Service this Task belongs to is a job-mode service, contains + the JobIteration of the Service this Task was created for. Absent if + the Task was created for a Replicated or Global Service. + $ref: "#/definitions/ObjectVersion" + example: + ID: "0kzzo1i0y4jz6027t0k7aezc7" + Version: + Index: 71 + CreatedAt: "2016-06-07T21:07:31.171892745Z" + UpdatedAt: "2016-06-07T21:07:31.376370513Z" + Spec: + ContainerSpec: + Image: "redis" + Resources: + Limits: {} + Reservations: {} + RestartPolicy: + Condition: "any" + MaxAttempts: 0 + Placement: {} + ServiceID: "9mnpnzenvg8p8tdbtq4wvbkcz" + Slot: 1 + NodeID: "60gvrl6tm78dmak4yl7srz94v" + Status: + Timestamp: "2016-06-07T21:07:31.290032978Z" + State: "running" + Message: "started" + ContainerStatus: + ContainerID: "e5d62702a1b48d01c3e02ca1e0212a250801fa8d67caca0b6f35919ebc12f035" + PID: 677 + DesiredState: "running" + NetworksAttachments: + - Network: + ID: "4qvuz4ko70xaltuqbt8956gd1" + Version: + Index: 18 + CreatedAt: "2016-06-07T20:31:11.912919752Z" + UpdatedAt: "2016-06-07T21:07:29.955277358Z" + Spec: + Name: "ingress" + Labels: + com.docker.swarm.internal: "true" + DriverConfiguration: {} + IPAMOptions: + Driver: {} + Configs: + - Subnet: "10.255.0.0/16" + Gateway: "10.255.0.1" + DriverState: + Name: "overlay" + Options: + com.docker.network.driver.overlay.vxlanid_list: "256" + IPAMOptions: + Driver: + Name: "default" + Configs: + - Subnet: "10.255.0.0/16" + Gateway: "10.255.0.1" + Addresses: + - "10.255.0.10/16" + AssignedGenericResources: + - DiscreteResourceSpec: + Kind: "SSD" + Value: 3 + - NamedResourceSpec: + Kind: "GPU" + Value: "UUID1" + - NamedResourceSpec: + Kind: "GPU" + Value: "UUID2" + + ServiceSpec: + description: "User modifiable configuration for a service." + type: object + properties: + Name: + description: "Name of the service." + type: "string" + Labels: + description: "User-defined key/value metadata." + type: "object" + additionalProperties: + type: "string" + TaskTemplate: + $ref: "#/definitions/TaskSpec" + Mode: + description: "Scheduling mode for the service." + type: "object" + properties: + Replicated: + type: "object" + properties: + Replicas: + type: "integer" + format: "int64" + Global: + type: "object" + ReplicatedJob: + description: | + The mode used for services with a finite number of tasks that run + to a completed state. + type: "object" + properties: + MaxConcurrent: + description: | + The maximum number of replicas to run simultaneously. + type: "integer" + format: "int64" + default: 1 + TotalCompletions: + description: | + The total number of replicas desired to reach the Completed + state. If unset, will default to the value of `MaxConcurrent` + type: "integer" + format: "int64" + GlobalJob: + description: | + The mode used for services which run a task to the completed state + on each valid node. + type: "object" + UpdateConfig: + description: "Specification for the update strategy of the service." + type: "object" + properties: + Parallelism: + description: | + Maximum number of tasks to be updated in one iteration (0 means + unlimited parallelism). + type: "integer" + format: "int64" + Delay: + description: "Amount of time between updates, in nanoseconds." + type: "integer" + format: "int64" + FailureAction: + description: | + Action to take if an updated task fails to run, or stops running + during the update. + type: "string" + enum: + - "continue" + - "pause" + - "rollback" + Monitor: + description: | + Amount of time to monitor each updated task for failures, in + nanoseconds. + type: "integer" + format: "int64" + MaxFailureRatio: + description: | + The fraction of tasks that may fail during an update before the + failure action is invoked, specified as a floating point number + between 0 and 1. + type: "number" + default: 0 + Order: + description: | + The order of operations when rolling out an updated task. Either + the old task is shut down before the new task is started, or the + new task is started before the old task is shut down. + type: "string" + enum: + - "stop-first" + - "start-first" + RollbackConfig: + description: "Specification for the rollback strategy of the service." + type: "object" + properties: + Parallelism: + description: | + Maximum number of tasks to be rolled back in one iteration (0 means + unlimited parallelism). + type: "integer" + format: "int64" + Delay: + description: | + Amount of time between rollback iterations, in nanoseconds. + type: "integer" + format: "int64" + FailureAction: + description: | + Action to take if an rolled back task fails to run, or stops + running during the rollback. + type: "string" + enum: + - "continue" + - "pause" + Monitor: + description: | + Amount of time to monitor each rolled back task for failures, in + nanoseconds. + type: "integer" + format: "int64" + MaxFailureRatio: + description: | + The fraction of tasks that may fail during a rollback before the + failure action is invoked, specified as a floating point number + between 0 and 1. + type: "number" + default: 0 + Order: + description: | + The order of operations when rolling back a task. Either the old + task is shut down before the new task is started, or the new task + is started before the old task is shut down. + type: "string" + enum: + - "stop-first" + - "start-first" + Networks: + description: "Specifies which networks the service should attach to." + type: "array" + items: + $ref: "#/definitions/NetworkAttachmentConfig" + + EndpointSpec: + $ref: "#/definitions/EndpointSpec" + + EndpointPortConfig: + type: "object" + properties: + Name: + type: "string" + Protocol: + type: "string" + enum: + - "tcp" + - "udp" + - "sctp" + TargetPort: + description: "The port inside the container." + type: "integer" + PublishedPort: + description: "The port on the swarm hosts." + type: "integer" + PublishMode: + description: | + The mode in which port is published. + +


+ + - "ingress" makes the target port accessible on every node, + regardless of whether there is a task for the service running on + that node or not. + - "host" bypasses the routing mesh and publish the port directly on + the swarm node where that service is running. + + type: "string" + enum: + - "ingress" + - "host" + default: "ingress" + example: "ingress" + + EndpointSpec: + description: "Properties that can be configured to access and load balance a service." + type: "object" + properties: + Mode: + description: | + The mode of resolution to use for internal load balancing between tasks. + type: "string" + enum: + - "vip" + - "dnsrr" + default: "vip" + Ports: + description: | + List of exposed ports that this service is accessible on from the + outside. Ports can only be provided if `vip` resolution mode is used. + type: "array" + items: + $ref: "#/definitions/EndpointPortConfig" + + Service: + type: "object" + properties: + ID: + type: "string" + Version: + $ref: "#/definitions/ObjectVersion" + CreatedAt: + type: "string" + format: "dateTime" + UpdatedAt: + type: "string" + format: "dateTime" + Spec: + $ref: "#/definitions/ServiceSpec" + Endpoint: + type: "object" + properties: + Spec: + $ref: "#/definitions/EndpointSpec" + Ports: + type: "array" + items: + $ref: "#/definitions/EndpointPortConfig" + VirtualIPs: + type: "array" + items: + type: "object" + properties: + NetworkID: + type: "string" + Addr: + type: "string" + UpdateStatus: + description: "The status of a service update." + type: "object" + properties: + State: + type: "string" + enum: + - "updating" + - "paused" + - "completed" + StartedAt: + type: "string" + format: "dateTime" + CompletedAt: + type: "string" + format: "dateTime" + Message: + type: "string" + ServiceStatus: + description: | + The status of the service's tasks. Provided only when requested as + part of a ServiceList operation. + type: "object" + properties: + RunningTasks: + description: | + The number of tasks for the service currently in the Running state. + type: "integer" + format: "uint64" + example: 7 + DesiredTasks: + description: | + The number of tasks for the service desired to be running. + For replicated services, this is the replica count from the + service spec. For global services, this is computed by taking + count of all tasks for the service with a Desired State other + than Shutdown. + type: "integer" + format: "uint64" + example: 10 + CompletedTasks: + description: | + The number of tasks for a job that are in the Completed state. + This field must be cross-referenced with the service type, as the + value of 0 may mean the service is not in a job mode, or it may + mean the job-mode service has no tasks yet Completed. + type: "integer" + format: "uint64" + JobStatus: + description: | + The status of the service when it is in one of ReplicatedJob or + GlobalJob modes. Absent on Replicated and Global mode services. The + JobIteration is an ObjectVersion, but unlike the Service's version, + does not need to be sent with an update request. + type: "object" + properties: + JobIteration: + description: | + JobIteration is a value increased each time a Job is executed, + successfully or otherwise. "Executed", in this case, means the + job as a whole has been started, not that an individual Task has + been launched. A job is "Executed" when its ServiceSpec is + updated. JobIteration can be used to disambiguate Tasks belonging + to different executions of a job. Though JobIteration will + increase with each subsequent execution, it may not necessarily + increase by 1, and so JobIteration should not be used to + $ref: "#/definitions/ObjectVersion" + LastExecution: + description: | + The last time, as observed by the server, that this job was + started. + type: "string" + format: "dateTime" + example: + ID: "9mnpnzenvg8p8tdbtq4wvbkcz" + Version: + Index: 19 + CreatedAt: "2016-06-07T21:05:51.880065305Z" + UpdatedAt: "2016-06-07T21:07:29.962229872Z" + Spec: + Name: "hopeful_cori" + TaskTemplate: + ContainerSpec: + Image: "redis" + Resources: + Limits: {} + Reservations: {} + RestartPolicy: + Condition: "any" + MaxAttempts: 0 + Placement: {} + ForceUpdate: 0 + Mode: + Replicated: + Replicas: 1 + UpdateConfig: + Parallelism: 1 + Delay: 1000000000 + FailureAction: "pause" + Monitor: 15000000000 + MaxFailureRatio: 0.15 + RollbackConfig: + Parallelism: 1 + Delay: 1000000000 + FailureAction: "pause" + Monitor: 15000000000 + MaxFailureRatio: 0.15 + EndpointSpec: + Mode: "vip" + Ports: + - + Protocol: "tcp" + TargetPort: 6379 + PublishedPort: 30001 + Endpoint: + Spec: + Mode: "vip" + Ports: + - + Protocol: "tcp" + TargetPort: 6379 + PublishedPort: 30001 + Ports: + - + Protocol: "tcp" + TargetPort: 6379 + PublishedPort: 30001 + VirtualIPs: + - + NetworkID: "4qvuz4ko70xaltuqbt8956gd1" + Addr: "10.255.0.2/16" + - + NetworkID: "4qvuz4ko70xaltuqbt8956gd1" + Addr: "10.255.0.3/16" + + ImageDeleteResponseItem: + type: "object" + properties: + Untagged: + description: "The image ID of an image that was untagged" + type: "string" + Deleted: + description: "The image ID of an image that was deleted" + type: "string" + + ServiceUpdateResponse: + type: "object" + properties: + Warnings: + description: "Optional warning messages" + type: "array" + items: + type: "string" + example: + Warning: "unable to pin image doesnotexist:latest to digest: image library/doesnotexist:latest not found" + + ContainerSummary: + type: "object" + properties: + Id: + description: "The ID of this container" + type: "string" + x-go-name: "ID" + Names: + description: "The names that this container has been given" + type: "array" + items: + type: "string" + Image: + description: "The name of the image used when creating this container" + type: "string" + ImageID: + description: "The ID of the image that this container was created from" + type: "string" + Command: + description: "Command to run when starting the container" + type: "string" + Created: + description: "When the container was created" + type: "integer" + format: "int64" + Ports: + description: "The ports exposed by this container" + type: "array" + items: + $ref: "#/definitions/Port" + SizeRw: + description: "The size of files that have been created or changed by this container" + type: "integer" + format: "int64" + SizeRootFs: + description: "The total size of all the files in this container" + type: "integer" + format: "int64" + Labels: + description: "User-defined key/value metadata." + type: "object" + additionalProperties: + type: "string" + State: + description: "The state of this container (e.g. `Exited`)" + type: "string" + Status: + description: "Additional human-readable status of this container (e.g. `Exit 0`)" + type: "string" + HostConfig: + type: "object" + properties: + NetworkMode: + type: "string" + NetworkSettings: + description: "A summary of the container's network settings" + type: "object" + properties: + Networks: + type: "object" + additionalProperties: + $ref: "#/definitions/EndpointSettings" + Mounts: + type: "array" + items: + $ref: "#/definitions/MountPoint" + + Driver: + description: "Driver represents a driver (network, logging, secrets)." + type: "object" + required: [Name] + properties: + Name: + description: "Name of the driver." + type: "string" + x-nullable: false + example: "some-driver" + Options: + description: "Key/value map of driver-specific options." + type: "object" + x-nullable: false + additionalProperties: + type: "string" + example: + OptionA: "value for driver-specific option A" + OptionB: "value for driver-specific option B" + + SecretSpec: + type: "object" + properties: + Name: + description: "User-defined name of the secret." + type: "string" + Labels: + description: "User-defined key/value metadata." + type: "object" + additionalProperties: + type: "string" + example: + com.example.some-label: "some-value" + com.example.some-other-label: "some-other-value" + Data: + description: | + Base64-url-safe-encoded ([RFC 4648](https://tools.ietf.org/html/rfc4648#section-5)) + data to store as secret. + + This field is only used to _create_ a secret, and is not returned by + other endpoints. + type: "string" + example: "" + Driver: + description: | + Name of the secrets driver used to fetch the secret's value from an + external secret store. + $ref: "#/definitions/Driver" + Templating: + description: | + Templating driver, if applicable + + Templating controls whether and how to evaluate the config payload as + a template. If no driver is set, no templating is used. + $ref: "#/definitions/Driver" + + Secret: + type: "object" + properties: + ID: + type: "string" + example: "blt1owaxmitz71s9v5zh81zun" + Version: + $ref: "#/definitions/ObjectVersion" + CreatedAt: + type: "string" + format: "dateTime" + example: "2017-07-20T13:55:28.678958722Z" + UpdatedAt: + type: "string" + format: "dateTime" + example: "2017-07-20T13:55:28.678958722Z" + Spec: + $ref: "#/definitions/SecretSpec" + + ConfigSpec: + type: "object" + properties: + Name: + description: "User-defined name of the config." + type: "string" + Labels: + description: "User-defined key/value metadata." + type: "object" + additionalProperties: + type: "string" + Data: + description: | + Base64-url-safe-encoded ([RFC 4648](https://tools.ietf.org/html/rfc4648#section-5)) + config data. + type: "string" + Templating: + description: | + Templating driver, if applicable + + Templating controls whether and how to evaluate the config payload as + a template. If no driver is set, no templating is used. + $ref: "#/definitions/Driver" + + Config: + type: "object" + properties: + ID: + type: "string" + Version: + $ref: "#/definitions/ObjectVersion" + CreatedAt: + type: "string" + format: "dateTime" + UpdatedAt: + type: "string" + format: "dateTime" + Spec: + $ref: "#/definitions/ConfigSpec" + + ContainerState: + description: | + ContainerState stores container's running state. It's part of ContainerJSONBase + and will be returned by the "inspect" command. + type: "object" + x-nullable: true + properties: + Status: + description: | + String representation of the container state. Can be one of "created", + "running", "paused", "restarting", "removing", "exited", or "dead". + type: "string" + enum: ["created", "running", "paused", "restarting", "removing", "exited", "dead"] + example: "running" + Running: + description: | + Whether this container is running. + + Note that a running container can be _paused_. The `Running` and `Paused` + booleans are not mutually exclusive: + + When pausing a container (on Linux), the freezer cgroup is used to suspend + all processes in the container. Freezing the process requires the process to + be running. As a result, paused containers are both `Running` _and_ `Paused`. + + Use the `Status` field instead to determine if a container's state is "running". + type: "boolean" + example: true + Paused: + description: "Whether this container is paused." + type: "boolean" + example: false + Restarting: + description: "Whether this container is restarting." + type: "boolean" + example: false + OOMKilled: + description: | + Whether this container has been killed because it ran out of memory. + type: "boolean" + example: false + Dead: + type: "boolean" + example: false + Pid: + description: "The process ID of this container" + type: "integer" + example: 1234 + ExitCode: + description: "The last exit code of this container" + type: "integer" + example: 0 + Error: + type: "string" + StartedAt: + description: "The time when this container was last started." + type: "string" + example: "2020-01-06T09:06:59.461876391Z" + FinishedAt: + description: "The time when this container last exited." + type: "string" + example: "2020-01-06T09:07:59.461876391Z" + Health: + $ref: "#/definitions/Health" + + ContainerCreateResponse: + description: "OK response to ContainerCreate operation" + type: "object" + title: "ContainerCreateResponse" + x-go-name: "CreateResponse" + required: [Id, Warnings] + properties: + Id: + description: "The ID of the created container" + type: "string" + x-nullable: false + example: "ede54ee1afda366ab42f824e8a5ffd195155d853ceaec74a927f249ea270c743" + Warnings: + description: "Warnings encountered when creating the container" + type: "array" + x-nullable: false + items: + type: "string" + example: [] + + ContainerWaitResponse: + description: "OK response to ContainerWait operation" + type: "object" + x-go-name: "WaitResponse" + title: "ContainerWaitResponse" + required: [StatusCode] + properties: + StatusCode: + description: "Exit code of the container" + type: "integer" + format: "int64" + x-nullable: false + Error: + $ref: "#/definitions/ContainerWaitExitError" + + ContainerWaitExitError: + description: "container waiting error, if any" + type: "object" + x-go-name: "WaitExitError" + properties: + Message: + description: "Details of an error" + type: "string" + + SystemVersion: + type: "object" + description: | + Response of Engine API: GET "/version" + properties: + Platform: + type: "object" + required: [Name] + properties: + Name: + type: "string" + Components: + type: "array" + description: | + Information about system components + items: + type: "object" + x-go-name: ComponentVersion + required: [Name, Version] + properties: + Name: + description: | + Name of the component + type: "string" + example: "Engine" + Version: + description: | + Version of the component + type: "string" + x-nullable: false + example: "19.03.12" + Details: + description: | + Key/value pairs of strings with additional information about the + component. These values are intended for informational purposes + only, and their content is not defined, and not part of the API + specification. + + These messages can be printed by the client as information to the user. + type: "object" + x-nullable: true + Version: + description: "The version of the daemon" + type: "string" + example: "19.03.12" + ApiVersion: + description: | + The default (and highest) API version that is supported by the daemon + type: "string" + example: "1.40" + MinAPIVersion: + description: | + The minimum API version that is supported by the daemon + type: "string" + example: "1.12" + GitCommit: + description: | + The Git commit of the source code that was used to build the daemon + type: "string" + example: "48a66213fe" + GoVersion: + description: | + The version Go used to compile the daemon, and the version of the Go + runtime in use. + type: "string" + example: "go1.13.14" + Os: + description: | + The operating system that the daemon is running on ("linux" or "windows") + type: "string" + example: "linux" + Arch: + description: | + The architecture that the daemon is running on + type: "string" + example: "amd64" + KernelVersion: + description: | + The kernel version (`uname -r`) that the daemon is running on. + + This field is omitted when empty. + type: "string" + example: "4.19.76-linuxkit" + Experimental: + description: | + Indicates if the daemon is started with experimental features enabled. + + This field is omitted when empty / false. + type: "boolean" + example: true + BuildTime: + description: | + The date and time that the daemon was compiled. + type: "string" + example: "2020-06-22T15:49:27.000000000+00:00" + + SystemInfo: + type: "object" + properties: + ID: + description: | + Unique identifier of the daemon. + +


+ + > **Note**: The format of the ID itself is not part of the API, and + > should not be considered stable. + type: "string" + example: "7TRN:IPZB:QYBB:VPBQ:UMPP:KARE:6ZNR:XE6T:7EWV:PKF4:ZOJD:TPYS" + Containers: + description: "Total number of containers on the host." + type: "integer" + example: 14 + ContainersRunning: + description: | + Number of containers with status `"running"`. + type: "integer" + example: 3 + ContainersPaused: + description: | + Number of containers with status `"paused"`. + type: "integer" + example: 1 + ContainersStopped: + description: | + Number of containers with status `"stopped"`. + type: "integer" + example: 10 + Images: + description: | + Total number of images on the host. + + Both _tagged_ and _untagged_ (dangling) images are counted. + type: "integer" + example: 508 + Driver: + description: "Name of the storage driver in use." + type: "string" + example: "overlay2" + DriverStatus: + description: | + Information specific to the storage driver, provided as + "label" / "value" pairs. + + This information is provided by the storage driver, and formatted + in a way consistent with the output of `docker info` on the command + line. + +


+ + > **Note**: The information returned in this field, including the + > formatting of values and labels, should not be considered stable, + > and may change without notice. + type: "array" + items: + type: "array" + items: + type: "string" + example: + - ["Backing Filesystem", "extfs"] + - ["Supports d_type", "true"] + - ["Native Overlay Diff", "true"] + DockerRootDir: + description: | + Root directory of persistent Docker state. + + Defaults to `/var/lib/docker` on Linux, and `C:\ProgramData\docker` + on Windows. + type: "string" + example: "/var/lib/docker" + Plugins: + $ref: "#/definitions/PluginsInfo" + MemoryLimit: + description: "Indicates if the host has memory limit support enabled." + type: "boolean" + example: true + SwapLimit: + description: "Indicates if the host has memory swap limit support enabled." + type: "boolean" + example: true + KernelMemoryTCP: + description: | + Indicates if the host has kernel memory TCP limit support enabled. This + field is omitted if not supported. + + Kernel memory TCP limits are not supported when using cgroups v2, which + does not support the corresponding `memory.kmem.tcp.limit_in_bytes` cgroup. + type: "boolean" + example: true + CpuCfsPeriod: + description: | + Indicates if CPU CFS(Completely Fair Scheduler) period is supported by + the host. + type: "boolean" + example: true + CpuCfsQuota: + description: | + Indicates if CPU CFS(Completely Fair Scheduler) quota is supported by + the host. + type: "boolean" + example: true + CPUShares: + description: | + Indicates if CPU Shares limiting is supported by the host. + type: "boolean" + example: true + CPUSet: + description: | + Indicates if CPUsets (cpuset.cpus, cpuset.mems) are supported by the host. + + See [cpuset(7)](https://www.kernel.org/doc/Documentation/cgroup-v1/cpusets.txt) + type: "boolean" + example: true + PidsLimit: + description: "Indicates if the host kernel has PID limit support enabled." + type: "boolean" + example: true + OomKillDisable: + description: "Indicates if OOM killer disable is supported on the host." + type: "boolean" + IPv4Forwarding: + description: "Indicates IPv4 forwarding is enabled." + type: "boolean" + example: true + BridgeNfIptables: + description: "Indicates if `bridge-nf-call-iptables` is available on the host." + type: "boolean" + example: true + BridgeNfIp6tables: + description: "Indicates if `bridge-nf-call-ip6tables` is available on the host." + type: "boolean" + example: true + Debug: + description: | + Indicates if the daemon is running in debug-mode / with debug-level + logging enabled. + type: "boolean" + example: true + NFd: + description: | + The total number of file Descriptors in use by the daemon process. + + This information is only returned if debug-mode is enabled. + type: "integer" + example: 64 + NGoroutines: + description: | + The number of goroutines that currently exist. + + This information is only returned if debug-mode is enabled. + type: "integer" + example: 174 + SystemTime: + description: | + Current system-time in [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) + format with nano-seconds. + type: "string" + example: "2017-08-08T20:28:29.06202363Z" + LoggingDriver: + description: | + The logging driver to use as a default for new containers. + type: "string" + CgroupDriver: + description: | + The driver to use for managing cgroups. + type: "string" + enum: ["cgroupfs", "systemd", "none"] + default: "cgroupfs" + example: "cgroupfs" + CgroupVersion: + description: | + The version of the cgroup. + type: "string" + enum: ["1", "2"] + default: "1" + example: "1" + NEventsListener: + description: "Number of event listeners subscribed." + type: "integer" + example: 30 + KernelVersion: + description: | + Kernel version of the host. + + On Linux, this information obtained from `uname`. On Windows this + information is queried from the HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ + registry value, for example _"10.0 14393 (14393.1198.amd64fre.rs1_release_sec.170427-1353)"_. + type: "string" + example: "4.9.38-moby" + OperatingSystem: + description: | + Name of the host's operating system, for example: "Ubuntu 16.04.2 LTS" + or "Windows Server 2016 Datacenter" + type: "string" + example: "Alpine Linux v3.5" + OSVersion: + description: | + Version of the host's operating system + +


+ + > **Note**: The information returned in this field, including its + > very existence, and the formatting of values, should not be considered + > stable, and may change without notice. + type: "string" + example: "16.04" + OSType: + description: | + Generic type of the operating system of the host, as returned by the + Go runtime (`GOOS`). + + Currently returned values are "linux" and "windows". A full list of + possible values can be found in the [Go documentation](https://golang.org/doc/install/source#environment). + type: "string" + example: "linux" + Architecture: + description: | + Hardware architecture of the host, as returned by the Go runtime + (`GOARCH`). + + A full list of possible values can be found in the [Go documentation](https://golang.org/doc/install/source#environment). + type: "string" + example: "x86_64" + NCPU: + description: | + The number of logical CPUs usable by the daemon. + + The number of available CPUs is checked by querying the operating + system when the daemon starts. Changes to operating system CPU + allocation after the daemon is started are not reflected. + type: "integer" + example: 4 + MemTotal: + description: | + Total amount of physical memory available on the host, in bytes. + type: "integer" + format: "int64" + example: 2095882240 + + IndexServerAddress: + description: | + Address / URL of the index server that is used for image search, + and as a default for user authentication for Docker Hub and Docker Cloud. + default: "https://index.docker.io/v1/" + type: "string" + example: "https://index.docker.io/v1/" + RegistryConfig: + $ref: "#/definitions/RegistryServiceConfig" + GenericResources: + $ref: "#/definitions/GenericResources" + HttpProxy: + description: | + HTTP-proxy configured for the daemon. This value is obtained from the + [`HTTP_PROXY`](https://www.gnu.org/software/wget/manual/html_node/Proxies.html) environment variable. + Credentials ([user info component](https://tools.ietf.org/html/rfc3986#section-3.2.1)) in the proxy URL + are masked in the API response. + + Containers do not automatically inherit this configuration. + type: "string" + example: "http://xxxxx:xxxxx@proxy.corp.example.com:8080" + HttpsProxy: + description: | + HTTPS-proxy configured for the daemon. This value is obtained from the + [`HTTPS_PROXY`](https://www.gnu.org/software/wget/manual/html_node/Proxies.html) environment variable. + Credentials ([user info component](https://tools.ietf.org/html/rfc3986#section-3.2.1)) in the proxy URL + are masked in the API response. + + Containers do not automatically inherit this configuration. + type: "string" + example: "https://xxxxx:xxxxx@proxy.corp.example.com:4443" + NoProxy: + description: | + Comma-separated list of domain extensions for which no proxy should be + used. This value is obtained from the [`NO_PROXY`](https://www.gnu.org/software/wget/manual/html_node/Proxies.html) + environment variable. + + Containers do not automatically inherit this configuration. + type: "string" + example: "*.local, 169.254/16" + Name: + description: "Hostname of the host." + type: "string" + example: "node5.corp.example.com" + Labels: + description: | + User-defined labels (key/value metadata) as set on the daemon. + +


+ + > **Note**: When part of a Swarm, nodes can both have _daemon_ labels, + > set through the daemon configuration, and _node_ labels, set from a + > manager node in the Swarm. Node labels are not included in this + > field. Node labels can be retrieved using the `/nodes/(id)` endpoint + > on a manager node in the Swarm. + type: "array" + items: + type: "string" + example: ["storage=ssd", "production"] + ExperimentalBuild: + description: | + Indicates if experimental features are enabled on the daemon. + type: "boolean" + example: true + ServerVersion: + description: | + Version string of the daemon. + + > **Note**: the [standalone Swarm API](https://docs.docker.com/swarm/swarm-api/) + > returns the Swarm version instead of the daemon version, for example + > `swarm/1.2.8`. + type: "string" + example: "17.06.0-ce" + ClusterStore: + description: | + URL of the distributed storage backend. + + + The storage backend is used for multihost networking (to store + network and endpoint information) and by the node discovery mechanism. + +


+ + > **Deprecated**: This field is only propagated when using standalone Swarm + > mode, and overlay networking using an external k/v store. Overlay + > networks with Swarm mode enabled use the built-in raft store, and + > this field will be empty. + type: "string" + example: "consul://consul.corp.example.com:8600/some/path" + ClusterAdvertise: + description: | + The network endpoint that the Engine advertises for the purpose of + node discovery. ClusterAdvertise is a `host:port` combination on which + the daemon is reachable by other hosts. + +


+ + > **Deprecated**: This field is only propagated when using standalone Swarm + > mode, and overlay networking using an external k/v store. Overlay + > networks with Swarm mode enabled use the built-in raft store, and + > this field will be empty. + type: "string" + example: "node5.corp.example.com:8000" + Runtimes: + description: | + List of [OCI compliant](https://github.com/opencontainers/runtime-spec) + runtimes configured on the daemon. Keys hold the "name" used to + reference the runtime. + + The Docker daemon relies on an OCI compliant runtime (invoked via the + `containerd` daemon) as its interface to the Linux kernel namespaces, + cgroups, and SELinux. + + The default runtime is `runc`, and automatically configured. Additional + runtimes can be configured by the user and will be listed here. + type: "object" + additionalProperties: + $ref: "#/definitions/Runtime" + default: + runc: + path: "runc" + example: + runc: + path: "runc" + runc-master: + path: "/go/bin/runc" + custom: + path: "/usr/local/bin/my-oci-runtime" + runtimeArgs: ["--debug", "--systemd-cgroup=false"] + DefaultRuntime: + description: | + Name of the default OCI runtime that is used when starting containers. + + The default can be overridden per-container at create time. + type: "string" + default: "runc" + example: "runc" + Swarm: + $ref: "#/definitions/SwarmInfo" + LiveRestoreEnabled: + description: | + Indicates if live restore is enabled. + + If enabled, containers are kept running when the daemon is shutdown + or upon daemon start if running containers are detected. + type: "boolean" + default: false + example: false + Isolation: + description: | + Represents the isolation technology to use as a default for containers. + The supported values are platform-specific. + + If no isolation value is specified on daemon start, on Windows client, + the default is `hyperv`, and on Windows server, the default is `process`. + + This option is currently not used on other platforms. + default: "default" + type: "string" + enum: + - "default" + - "hyperv" + - "process" + InitBinary: + description: | + Name and, optional, path of the `docker-init` binary. + + If the path is omitted, the daemon searches the host's `$PATH` for the + binary and uses the first result. + type: "string" + example: "docker-init" + ContainerdCommit: + $ref: "#/definitions/Commit" + RuncCommit: + $ref: "#/definitions/Commit" + InitCommit: + $ref: "#/definitions/Commit" + SecurityOptions: + description: | + List of security features that are enabled on the daemon, such as + apparmor, seccomp, SELinux, user-namespaces (userns), and rootless. + + Additional configuration options for each security feature may + be present, and are included as a comma-separated list of key/value + pairs. + type: "array" + items: + type: "string" + example: + - "name=apparmor" + - "name=seccomp,profile=default" + - "name=selinux" + - "name=userns" + - "name=rootless" + ProductLicense: + description: | + Reports a summary of the product license on the daemon. + + If a commercial license has been applied to the daemon, information + such as number of nodes, and expiration are included. + type: "string" + example: "Community Engine" + DefaultAddressPools: + description: | + List of custom default address pools for local networks, which can be + specified in the daemon.json file or dockerd option. + + Example: a Base "10.10.0.0/16" with Size 24 will define the set of 256 + 10.10.[0-255].0/24 address pools. + type: "array" + items: + type: "object" + properties: + Base: + description: "The network address in CIDR format" + type: "string" + example: "10.10.0.0/16" + Size: + description: "The network pool size" + type: "integer" + example: "24" + Warnings: + description: | + List of warnings / informational messages about missing features, or + issues related to the daemon configuration. + + These messages can be printed by the client as information to the user. + type: "array" + items: + type: "string" + example: + - "WARNING: No memory limit support" + - "WARNING: bridge-nf-call-iptables is disabled" + - "WARNING: bridge-nf-call-ip6tables is disabled" + + + # PluginsInfo is a temp struct holding Plugins name + # registered with docker daemon. It is used by Info struct + PluginsInfo: + description: | + Available plugins per type. + +


+ + > **Note**: Only unmanaged (V1) plugins are included in this list. + > V1 plugins are "lazily" loaded, and are not returned in this list + > if there is no resource using the plugin. + type: "object" + properties: + Volume: + description: "Names of available volume-drivers, and network-driver plugins." + type: "array" + items: + type: "string" + example: ["local"] + Network: + description: "Names of available network-drivers, and network-driver plugins." + type: "array" + items: + type: "string" + example: ["bridge", "host", "ipvlan", "macvlan", "null", "overlay"] + Authorization: + description: "Names of available authorization plugins." + type: "array" + items: + type: "string" + example: ["img-authz-plugin", "hbm"] + Log: + description: "Names of available logging-drivers, and logging-driver plugins." + type: "array" + items: + type: "string" + example: ["awslogs", "fluentd", "gcplogs", "gelf", "journald", "json-file", "logentries", "splunk", "syslog"] + + + RegistryServiceConfig: + description: | + RegistryServiceConfig stores daemon registry services configuration. + type: "object" + x-nullable: true + properties: + AllowNondistributableArtifactsCIDRs: + description: | + List of IP ranges to which nondistributable artifacts can be pushed, + using the CIDR syntax [RFC 4632](https://tools.ietf.org/html/4632). + + Some images (for example, Windows base images) contain artifacts + whose distribution is restricted by license. When these images are + pushed to a registry, restricted artifacts are not included. + + This configuration override this behavior, and enables the daemon to + push nondistributable artifacts to all registries whose resolved IP + address is within the subnet described by the CIDR syntax. + + This option is useful when pushing images containing + nondistributable artifacts to a registry on an air-gapped network so + hosts on that network can pull the images without connecting to + another server. + + > **Warning**: Nondistributable artifacts typically have restrictions + > on how and where they can be distributed and shared. Only use this + > feature to push artifacts to private registries and ensure that you + > are in compliance with any terms that cover redistributing + > nondistributable artifacts. + + type: "array" + items: + type: "string" + example: ["::1/128", "127.0.0.0/8"] + AllowNondistributableArtifactsHostnames: + description: | + List of registry hostnames to which nondistributable artifacts can be + pushed, using the format `[:]` or `[:]`. + + Some images (for example, Windows base images) contain artifacts + whose distribution is restricted by license. When these images are + pushed to a registry, restricted artifacts are not included. + + This configuration override this behavior for the specified + registries. + + This option is useful when pushing images containing + nondistributable artifacts to a registry on an air-gapped network so + hosts on that network can pull the images without connecting to + another server. + + > **Warning**: Nondistributable artifacts typically have restrictions + > on how and where they can be distributed and shared. Only use this + > feature to push artifacts to private registries and ensure that you + > are in compliance with any terms that cover redistributing + > nondistributable artifacts. + type: "array" + items: + type: "string" + example: ["registry.internal.corp.example.com:3000", "[2001:db8:a0b:12f0::1]:443"] + InsecureRegistryCIDRs: + description: | + List of IP ranges of insecure registries, using the CIDR syntax + ([RFC 4632](https://tools.ietf.org/html/4632)). Insecure registries + accept un-encrypted (HTTP) and/or untrusted (HTTPS with certificates + from unknown CAs) communication. + + By default, local registries (`127.0.0.0/8`) are configured as + insecure. All other registries are secure. Communicating with an + insecure registry is not possible if the daemon assumes that registry + is secure. + + This configuration override this behavior, insecure communication with + registries whose resolved IP address is within the subnet described by + the CIDR syntax. + + Registries can also be marked insecure by hostname. Those registries + are listed under `IndexConfigs` and have their `Secure` field set to + `false`. + + > **Warning**: Using this option can be useful when running a local + > registry, but introduces security vulnerabilities. This option + > should therefore ONLY be used for testing purposes. For increased + > security, users should add their CA to their system's list of trusted + > CAs instead of enabling this option. + type: "array" + items: + type: "string" + example: ["::1/128", "127.0.0.0/8"] + IndexConfigs: + type: "object" + additionalProperties: + $ref: "#/definitions/IndexInfo" + example: + "127.0.0.1:5000": + "Name": "127.0.0.1:5000" + "Mirrors": [] + "Secure": false + "Official": false + "[2001:db8:a0b:12f0::1]:80": + "Name": "[2001:db8:a0b:12f0::1]:80" + "Mirrors": [] + "Secure": false + "Official": false + "docker.io": + Name: "docker.io" + Mirrors: ["https://hub-mirror.corp.example.com:5000/"] + Secure: true + Official: true + "registry.internal.corp.example.com:3000": + Name: "registry.internal.corp.example.com:3000" + Mirrors: [] + Secure: false + Official: false + Mirrors: + description: | + List of registry URLs that act as a mirror for the official + (`docker.io`) registry. + + type: "array" + items: + type: "string" + example: + - "https://hub-mirror.corp.example.com:5000/" + - "https://[2001:db8:a0b:12f0::1]/" + + IndexInfo: + description: + IndexInfo contains information about a registry. + type: "object" + x-nullable: true + properties: + Name: + description: | + Name of the registry, such as "docker.io". + type: "string" + example: "docker.io" + Mirrors: + description: | + List of mirrors, expressed as URIs. + type: "array" + items: + type: "string" + example: + - "https://hub-mirror.corp.example.com:5000/" + - "https://registry-2.docker.io/" + - "https://registry-3.docker.io/" + Secure: + description: | + Indicates if the registry is part of the list of insecure + registries. + + If `false`, the registry is insecure. Insecure registries accept + un-encrypted (HTTP) and/or untrusted (HTTPS with certificates from + unknown CAs) communication. + + > **Warning**: Insecure registries can be useful when running a local + > registry. However, because its use creates security vulnerabilities + > it should ONLY be enabled for testing purposes. For increased + > security, users should add their CA to their system's list of + > trusted CAs instead of enabling this option. + type: "boolean" + example: true + Official: + description: | + Indicates whether this is an official registry (i.e., Docker Hub / docker.io) + type: "boolean" + example: true + + Runtime: + description: | + Runtime describes an [OCI compliant](https://github.com/opencontainers/runtime-spec) + runtime. + + The runtime is invoked by the daemon via the `containerd` daemon. OCI + runtimes act as an interface to the Linux kernel namespaces, cgroups, + and SELinux. + type: "object" + properties: + path: + description: | + Name and, optional, path, of the OCI executable binary. + + If the path is omitted, the daemon searches the host's `$PATH` for the + binary and uses the first result. + type: "string" + example: "/usr/local/bin/my-oci-runtime" + runtimeArgs: + description: | + List of command-line arguments to pass to the runtime when invoked. + type: "array" + x-nullable: true + items: + type: "string" + example: ["--debug", "--systemd-cgroup=false"] + + Commit: + description: | + Commit holds the Git-commit (SHA1) that a binary was built from, as + reported in the version-string of external tools, such as `containerd`, + or `runC`. + type: "object" + properties: + ID: + description: "Actual commit ID of external tool." + type: "string" + example: "cfb82a876ecc11b5ca0977d1733adbe58599088a" + Expected: + description: | + Commit ID of external tool expected by dockerd as set at build time. + type: "string" + example: "2d41c047c83e09a6d61d464906feb2a2f3c52aa4" + + SwarmInfo: + description: | + Represents generic information about swarm. + type: "object" + properties: + NodeID: + description: "Unique identifier of for this node in the swarm." + type: "string" + default: "" + example: "k67qz4598weg5unwwffg6z1m1" + NodeAddr: + description: | + IP address at which this node can be reached by other nodes in the + swarm. + type: "string" + default: "" + example: "10.0.0.46" + LocalNodeState: + $ref: "#/definitions/LocalNodeState" + ControlAvailable: + type: "boolean" + default: false + example: true + Error: + type: "string" + default: "" + RemoteManagers: + description: | + List of ID's and addresses of other managers in the swarm. + type: "array" + default: null + x-nullable: true + items: + $ref: "#/definitions/PeerNode" + example: + - NodeID: "71izy0goik036k48jg985xnds" + Addr: "10.0.0.158:2377" + - NodeID: "79y6h1o4gv8n120drcprv5nmc" + Addr: "10.0.0.159:2377" + - NodeID: "k67qz4598weg5unwwffg6z1m1" + Addr: "10.0.0.46:2377" + Nodes: + description: "Total number of nodes in the swarm." + type: "integer" + x-nullable: true + example: 4 + Managers: + description: "Total number of managers in the swarm." + type: "integer" + x-nullable: true + example: 3 + Cluster: + $ref: "#/definitions/ClusterInfo" + + LocalNodeState: + description: "Current local status of this node." + type: "string" + default: "" + enum: + - "" + - "inactive" + - "pending" + - "active" + - "error" + - "locked" + example: "active" + + PeerNode: + description: "Represents a peer-node in the swarm" + type: "object" + properties: + NodeID: + description: "Unique identifier of for this node in the swarm." + type: "string" + Addr: + description: | + IP address and ports at which this node can be reached. + type: "string" + + NetworkAttachmentConfig: + description: | + Specifies how a service should be attached to a particular network. + type: "object" + properties: + Target: + description: | + The target network for attachment. Must be a network name or ID. + type: "string" + Aliases: + description: | + Discoverable alternate names for the service on this network. + type: "array" + items: + type: "string" + DriverOpts: + description: | + Driver attachment options for the network target. + type: "object" + additionalProperties: + type: "string" + + EventActor: + description: | + Actor describes something that generates events, like a container, network, + or a volume. + type: "object" + properties: + ID: + description: "The ID of the object emitting the event" + type: "string" + example: "ede54ee1afda366ab42f824e8a5ffd195155d853ceaec74a927f249ea270c743" + Attributes: + description: | + Various key/value attributes of the object, depending on its type. + type: "object" + additionalProperties: + type: "string" + example: + com.example.some-label: "some-label-value" + image: "alpine:latest" + name: "my-container" + + EventMessage: + description: | + EventMessage represents the information an event contains. + type: "object" + title: "SystemEventsResponse" + properties: + Type: + description: "The type of object emitting the event" + type: "string" + enum: ["builder", "config", "container", "daemon", "image", "network", "node", "plugin", "secret", "service", "volume"] + example: "container" + Action: + description: "The type of event" + type: "string" + example: "create" + Actor: + $ref: "#/definitions/EventActor" + scope: + description: | + Scope of the event. Engine events are `local` scope. Cluster (Swarm) + events are `swarm` scope. + type: "string" + enum: ["local", "swarm"] + time: + description: "Timestamp of event" + type: "integer" + format: "int64" + example: 1629574695 + timeNano: + description: "Timestamp of event, with nanosecond accuracy" + type: "integer" + format: "int64" + example: 1629574695515050031 + + OCIDescriptor: + type: "object" + x-go-name: Descriptor + description: | + A descriptor struct containing digest, media type, and size, as defined in + the [OCI Content Descriptors Specification](https://github.com/opencontainers/image-spec/blob/v1.0.1/descriptor.md). + properties: + mediaType: + description: | + The media type of the object this schema refers to. + type: "string" + example: "application/vnd.docker.distribution.manifest.v2+json" + digest: + description: | + The digest of the targeted content. + type: "string" + example: "sha256:c0537ff6a5218ef531ece93d4984efc99bbf3f7497c0a7726c88e2bb7584dc96" + size: + description: | + The size in bytes of the blob. + type: "integer" + format: "int64" + example: 3987495 + # TODO Not yet including these fields for now, as they are nil / omitted in our response. + # urls: + # description: | + # List of URLs from which this object MAY be downloaded. + # type: "array" + # items: + # type: "string" + # format: "uri" + # annotations: + # description: | + # Arbitrary metadata relating to the targeted content. + # type: "object" + # additionalProperties: + # type: "string" + # platform: + # $ref: "#/definitions/OCIPlatform" + + OCIPlatform: + type: "object" + x-go-name: Platform + description: | + Describes the platform which the image in the manifest runs on, as defined + in the [OCI Image Index Specification](https://github.com/opencontainers/image-spec/blob/v1.0.1/image-index.md). + properties: + architecture: + description: | + The CPU architecture, for example `amd64` or `ppc64`. + type: "string" + example: "arm" + os: + description: | + The operating system, for example `linux` or `windows`. + type: "string" + example: "windows" + os.version: + description: | + Optional field specifying the operating system version, for example on + Windows `10.0.19041.1165`. + type: "string" + example: "10.0.19041.1165" + os.features: + description: | + Optional field specifying an array of strings, each listing a required + OS feature (for example on Windows `win32k`). + type: "array" + items: + type: "string" + example: + - "win32k" + variant: + description: | + Optional field specifying a variant of the CPU, for example `v7` to + specify ARMv7 when architecture is `arm`. + type: "string" + example: "v7" + + DistributionInspect: + type: "object" + x-go-name: DistributionInspect + title: "DistributionInspectResponse" + required: [Descriptor, Platforms] + description: | + Describes the result obtained from contacting the registry to retrieve + image metadata. + properties: + Descriptor: + $ref: "#/definitions/OCIDescriptor" + Platforms: + type: "array" + description: | + An array containing all platforms supported by the image. + items: + $ref: "#/definitions/OCIPlatform" + + ClusterVolume: + type: "object" + description: | + Options and information specific to, and only present on, Swarm CSI + cluster volumes. + properties: + ID: + type: "string" + description: | + The Swarm ID of this volume. Because cluster volumes are Swarm + objects, they have an ID, unlike non-cluster volumes. This ID can + be used to refer to the Volume instead of the name. + Version: + $ref: "#/definitions/ObjectVersion" + CreatedAt: + type: "string" + format: "dateTime" + UpdatedAt: + type: "string" + format: "dateTime" + Spec: + $ref: "#/definitions/ClusterVolumeSpec" + Info: + type: "object" + description: | + Information about the global status of the volume. + properties: + CapacityBytes: + type: "integer" + format: "int64" + description: | + The capacity of the volume in bytes. A value of 0 indicates that + the capacity is unknown. + VolumeContext: + type: "object" + description: | + A map of strings to strings returned from the storage plugin when + the volume is created. + additionalProperties: + type: "string" + VolumeID: + type: "string" + description: | + The ID of the volume as returned by the CSI storage plugin. This + is distinct from the volume's ID as provided by Docker. This ID + is never used by the user when communicating with Docker to refer + to this volume. If the ID is blank, then the Volume has not been + successfully created in the plugin yet. + AccessibleTopology: + type: "array" + description: | + The topology this volume is actually accessible from. + items: + $ref: "#/definitions/Topology" + PublishStatus: + type: "array" + description: | + The status of the volume as it pertains to its publishing and use on + specific nodes + items: + type: "object" + properties: + NodeID: + type: "string" + description: | + The ID of the Swarm node the volume is published on. + State: + type: "string" + description: | + The published state of the volume. + * `pending-publish` The volume should be published to this node, but the call to the controller plugin to do so has not yet been successfully completed. + * `published` The volume is published successfully to the node. + * `pending-node-unpublish` The volume should be unpublished from the node, and the manager is awaiting confirmation from the worker that it has done so. + * `pending-controller-unpublish` The volume is successfully unpublished from the node, but has not yet been successfully unpublished on the controller. + enum: + - "pending-publish" + - "published" + - "pending-node-unpublish" + - "pending-controller-unpublish" + PublishContext: + type: "object" + description: | + A map of strings to strings returned by the CSI controller + plugin when a volume is published. + additionalProperties: + type: "string" + + ClusterVolumeSpec: + type: "object" + description: | + Cluster-specific options used to create the volume. + properties: + Group: + type: "string" + description: | + Group defines the volume group of this volume. Volumes belonging to + the same group can be referred to by group name when creating + Services. Referring to a volume by group instructs Swarm to treat + volumes in that group interchangeably for the purpose of scheduling. + Volumes with an empty string for a group technically all belong to + the same, emptystring group. + AccessMode: + type: "object" + description: | + Defines how the volume is used by tasks. + properties: + Scope: + type: "string" + description: | + The set of nodes this volume can be used on at one time. + - `single` The volume may only be scheduled to one node at a time. + - `multi` the volume may be scheduled to any supported number of nodes at a time. + default: "single" + enum: ["single", "multi"] + x-nullable: false + Sharing: + type: "string" + description: | + The number and way that different tasks can use this volume + at one time. + - `none` The volume may only be used by one task at a time. + - `readonly` The volume may be used by any number of tasks, but they all must mount the volume as readonly + - `onewriter` The volume may be used by any number of tasks, but only one may mount it as read/write. + - `all` The volume may have any number of readers and writers. + default: "none" + enum: ["none", "readonly", "onewriter", "all"] + x-nullable: false + MountVolume: + type: "object" + description: | + Options for using this volume as a Mount-type volume. + + Either MountVolume or BlockVolume, but not both, must be + present. + properties: + FsType: + type: "string" + description: | + Specifies the filesystem type for the mount volume. + Optional. + MountFlags: + type: "array" + description: | + Flags to pass when mounting the volume. Optional. + items: + type: "string" + BlockVolume: + type: "object" + description: | + Options for using this volume as a Block-type volume. + Intentionally empty. + Secrets: + type: "array" + description: | + Swarm Secrets that are passed to the CSI storage plugin when + operating on this volume. + items: + type: "object" + description: | + One cluster volume secret entry. Defines a key-value pair that + is passed to the plugin. + properties: + Key: + type: "string" + description: | + Key is the name of the key of the key-value pair passed to + the plugin. + Secret: + type: "string" + description: | + Secret is the swarm Secret object from which to read data. + This can be a Secret name or ID. The Secret data is + retrieved by swarm and used as the value of the key-value + pair passed to the plugin. + AccessibilityRequirements: + type: "object" + description: | + Requirements for the accessible topology of the volume. These + fields are optional. For an in-depth description of what these + fields mean, see the CSI specification. + properties: + Requisite: + type: "array" + description: | + A list of required topologies, at least one of which the + volume must be accessible from. + items: + $ref: "#/definitions/Topology" + Preferred: + type: "array" + description: | + A list of topologies that the volume should attempt to be + provisioned in. + items: + $ref: "#/definitions/Topology" + CapacityRange: + type: "object" + description: | + The desired capacity that the volume should be created with. If + empty, the plugin will decide the capacity. + properties: + RequiredBytes: + type: "integer" + format: "int64" + description: | + The volume must be at least this big. The value of 0 + indicates an unspecified minimum + LimitBytes: + type: "integer" + format: "int64" + description: | + The volume must not be bigger than this. The value of 0 + indicates an unspecified maximum. + Availability: + type: "string" + description: | + The availability of the volume for use in tasks. + - `active` The volume is fully available for scheduling on the cluster + - `pause` No new workloads should use the volume, but existing workloads are not stopped. + - `drain` All workloads using this volume should be stopped and rescheduled, and no new ones should be started. + default: "active" + x-nullable: false + enum: + - "active" + - "pause" + - "drain" + + Topology: + description: | + A map of topological domains to topological segments. For in depth + details, see documentation for the Topology object in the CSI + specification. + type: "object" + additionalProperties: + type: "string" + +paths: + /containers/json: + get: + summary: "List containers" + description: | + Returns a list of containers. For details on the format, see the + [inspect endpoint](#operation/ContainerInspect). + + Note that it uses a different, smaller representation of a container + than inspecting a single container. For example, the list of linked + containers is not propagated . + operationId: "ContainerList" + produces: + - "application/json" + parameters: + - name: "all" + in: "query" + description: | + Return all containers. By default, only running containers are shown. + type: "boolean" + default: false + - name: "limit" + in: "query" + description: | + Return this number of most recently created containers, including + non-running ones. + type: "integer" + - name: "size" + in: "query" + description: | + Return the size of container as fields `SizeRw` and `SizeRootFs`. + type: "boolean" + default: false + - name: "filters" + in: "query" + description: | + Filters to process on the container list, encoded as JSON (a + `map[string][]string`). For example, `{"status": ["paused"]}` will + only return paused containers. + + Available filters: + + - `ancestor`=(`[:]`, ``, or ``) + - `before`=(`` or ``) + - `expose`=(`[/]`|`/[]`) + - `exited=` containers with exit code of `` + - `health`=(`starting`|`healthy`|`unhealthy`|`none`) + - `id=` a container's ID + - `isolation=`(`default`|`process`|`hyperv`) (Windows daemon only) + - `is-task=`(`true`|`false`) + - `label=key` or `label="key=value"` of a container label + - `name=` a container's name + - `network`=(`` or ``) + - `publish`=(`[/]`|`/[]`) + - `since`=(`` or ``) + - `status=`(`created`|`restarting`|`running`|`removing`|`paused`|`exited`|`dead`) + - `volume`=(`` or ``) + type: "string" + responses: + 200: + description: "no error" + schema: + type: "array" + items: + $ref: "#/definitions/ContainerSummary" + examples: + application/json: + - Id: "8dfafdbc3a40" + Names: + - "/boring_feynman" + Image: "ubuntu:latest" + ImageID: "d74508fb6632491cea586a1fd7d748dfc5274cd6fdfedee309ecdcbc2bf5cb82" + Command: "echo 1" + Created: 1367854155 + State: "Exited" + Status: "Exit 0" + Ports: + - PrivatePort: 2222 + PublicPort: 3333 + Type: "tcp" + Labels: + com.example.vendor: "Acme" + com.example.license: "GPL" + com.example.version: "1.0" + SizeRw: 12288 + SizeRootFs: 0 + HostConfig: + NetworkMode: "default" + NetworkSettings: + Networks: + bridge: + NetworkID: "7ea29fc1412292a2d7bba362f9253545fecdfa8ce9a6e37dd10ba8bee7129812" + EndpointID: "2cdc4edb1ded3631c81f57966563e5c8525b81121bb3706a9a9a3ae102711f3f" + Gateway: "172.17.0.1" + IPAddress: "172.17.0.2" + IPPrefixLen: 16 + IPv6Gateway: "" + GlobalIPv6Address: "" + GlobalIPv6PrefixLen: 0 + MacAddress: "02:42:ac:11:00:02" + Mounts: + - Name: "fac362...80535" + Source: "/data" + Destination: "/data" + Driver: "local" + Mode: "ro,Z" + RW: false + Propagation: "" + - Id: "9cd87474be90" + Names: + - "/coolName" + Image: "ubuntu:latest" + ImageID: "d74508fb6632491cea586a1fd7d748dfc5274cd6fdfedee309ecdcbc2bf5cb82" + Command: "echo 222222" + Created: 1367854155 + State: "Exited" + Status: "Exit 0" + Ports: [] + Labels: {} + SizeRw: 12288 + SizeRootFs: 0 + HostConfig: + NetworkMode: "default" + NetworkSettings: + Networks: + bridge: + NetworkID: "7ea29fc1412292a2d7bba362f9253545fecdfa8ce9a6e37dd10ba8bee7129812" + EndpointID: "88eaed7b37b38c2a3f0c4bc796494fdf51b270c2d22656412a2ca5d559a64d7a" + Gateway: "172.17.0.1" + IPAddress: "172.17.0.8" + IPPrefixLen: 16 + IPv6Gateway: "" + GlobalIPv6Address: "" + GlobalIPv6PrefixLen: 0 + MacAddress: "02:42:ac:11:00:08" + Mounts: [] + - Id: "3176a2479c92" + Names: + - "/sleepy_dog" + Image: "ubuntu:latest" + ImageID: "d74508fb6632491cea586a1fd7d748dfc5274cd6fdfedee309ecdcbc2bf5cb82" + Command: "echo 3333333333333333" + Created: 1367854154 + State: "Exited" + Status: "Exit 0" + Ports: [] + Labels: {} + SizeRw: 12288 + SizeRootFs: 0 + HostConfig: + NetworkMode: "default" + NetworkSettings: + Networks: + bridge: + NetworkID: "7ea29fc1412292a2d7bba362f9253545fecdfa8ce9a6e37dd10ba8bee7129812" + EndpointID: "8b27c041c30326d59cd6e6f510d4f8d1d570a228466f956edf7815508f78e30d" + Gateway: "172.17.0.1" + IPAddress: "172.17.0.6" + IPPrefixLen: 16 + IPv6Gateway: "" + GlobalIPv6Address: "" + GlobalIPv6PrefixLen: 0 + MacAddress: "02:42:ac:11:00:06" + Mounts: [] + - Id: "4cb07b47f9fb" + Names: + - "/running_cat" + Image: "ubuntu:latest" + ImageID: "d74508fb6632491cea586a1fd7d748dfc5274cd6fdfedee309ecdcbc2bf5cb82" + Command: "echo 444444444444444444444444444444444" + Created: 1367854152 + State: "Exited" + Status: "Exit 0" + Ports: [] + Labels: {} + SizeRw: 12288 + SizeRootFs: 0 + HostConfig: + NetworkMode: "default" + NetworkSettings: + Networks: + bridge: + NetworkID: "7ea29fc1412292a2d7bba362f9253545fecdfa8ce9a6e37dd10ba8bee7129812" + EndpointID: "d91c7b2f0644403d7ef3095985ea0e2370325cd2332ff3a3225c4247328e66e9" + Gateway: "172.17.0.1" + IPAddress: "172.17.0.5" + IPPrefixLen: 16 + IPv6Gateway: "" + GlobalIPv6Address: "" + GlobalIPv6PrefixLen: 0 + MacAddress: "02:42:ac:11:00:05" + Mounts: [] + 400: + description: "bad parameter" + schema: + $ref: "#/definitions/ErrorResponse" + 500: + description: "server error" + schema: + $ref: "#/definitions/ErrorResponse" + tags: ["Container"] + /containers/create: + post: + summary: "Create a container" + operationId: "ContainerCreate" + consumes: + - "application/json" + - "application/octet-stream" + produces: + - "application/json" + parameters: + - name: "name" + in: "query" + description: | + Assign the specified name to the container. Must match + `/?[a-zA-Z0-9][a-zA-Z0-9_.-]+`. + type: "string" + pattern: "^/?[a-zA-Z0-9][a-zA-Z0-9_.-]+$" + - name: "platform" + in: "query" + description: | + Platform in the format `os[/arch[/variant]]` used for image lookup. + + When specified, the daemon checks if the requested image is present + in the local image cache with the given OS and Architecture, and + otherwise returns a `404` status. + + If the option is not set, the host's native OS and Architecture are + used to look up the image in the image cache. However, if no platform + is passed and the given image does exist in the local image cache, + but its OS or architecture does not match, the container is created + with the available image, and a warning is added to the `Warnings` + field in the response, for example; + + WARNING: The requested image's platform (linux/arm64/v8) does not + match the detected host platform (linux/amd64) and no + specific platform was requested + + type: "string" + default: "" + - name: "body" + in: "body" + description: "Container to create" + schema: + allOf: + - $ref: "#/definitions/ContainerConfig" + - type: "object" + properties: + HostConfig: + $ref: "#/definitions/HostConfig" + NetworkingConfig: + $ref: "#/definitions/NetworkingConfig" + example: + Hostname: "" + Domainname: "" + User: "" + AttachStdin: false + AttachStdout: true + AttachStderr: true + Tty: false + OpenStdin: false + StdinOnce: false + Env: + - "FOO=bar" + - "BAZ=quux" + Cmd: + - "date" + Entrypoint: "" + Image: "ubuntu" + Labels: + com.example.vendor: "Acme" + com.example.license: "GPL" + com.example.version: "1.0" + Volumes: + /volumes/data: {} + WorkingDir: "" + NetworkDisabled: false + MacAddress: "12:34:56:78:9a:bc" + ExposedPorts: + 22/tcp: {} + StopSignal: "SIGTERM" + StopTimeout: 10 + HostConfig: + Binds: + - "/tmp:/tmp" + Links: + - "redis3:redis" + Memory: 0 + MemorySwap: 0 + MemoryReservation: 0 + NanoCpus: 500000 + CpuPercent: 80 + CpuShares: 512 + CpuPeriod: 100000 + CpuRealtimePeriod: 1000000 + CpuRealtimeRuntime: 10000 + CpuQuota: 50000 + CpusetCpus: "0,1" + CpusetMems: "0,1" + MaximumIOps: 0 + MaximumIOBps: 0 + BlkioWeight: 300 + BlkioWeightDevice: + - {} + BlkioDeviceReadBps: + - {} + BlkioDeviceReadIOps: + - {} + BlkioDeviceWriteBps: + - {} + BlkioDeviceWriteIOps: + - {} + DeviceRequests: + - Driver: "nvidia" + Count: -1 + DeviceIDs": ["0", "1", "GPU-fef8089b-4820-abfc-e83e-94318197576e"] + Capabilities: [["gpu", "nvidia", "compute"]] + Options: + property1: "string" + property2: "string" + MemorySwappiness: 60 + OomKillDisable: false + OomScoreAdj: 500 + PidMode: "" + PidsLimit: 0 + PortBindings: + 22/tcp: + - HostPort: "11022" + PublishAllPorts: false + Privileged: false + ReadonlyRootfs: false + Dns: + - "8.8.8.8" + DnsOptions: + - "" + DnsSearch: + - "" + VolumesFrom: + - "parent" + - "other:ro" + CapAdd: + - "NET_ADMIN" + CapDrop: + - "MKNOD" + GroupAdd: + - "newgroup" + RestartPolicy: + Name: "" + MaximumRetryCount: 0 + AutoRemove: true + NetworkMode: "bridge" + Devices: [] + Ulimits: + - {} + LogConfig: + Type: "json-file" + Config: {} + SecurityOpt: [] + StorageOpt: {} + CgroupParent: "" + VolumeDriver: "" + ShmSize: 67108864 + NetworkingConfig: + EndpointsConfig: + isolated_nw: + IPAMConfig: + IPv4Address: "172.20.30.33" + IPv6Address: "2001:db8:abcd::3033" + LinkLocalIPs: + - "169.254.34.68" + - "fe80::3468" + Links: + - "container_1" + - "container_2" + Aliases: + - "server_x" + - "server_y" + + required: true + responses: + 201: + description: "Container created successfully" + schema: + $ref: "#/definitions/ContainerCreateResponse" + 400: + description: "bad parameter" + schema: + $ref: "#/definitions/ErrorResponse" + 404: + description: "no such image" + schema: + $ref: "#/definitions/ErrorResponse" + examples: + application/json: + message: "No such image: c2ada9df5af8" + 409: + description: "conflict" + schema: + $ref: "#/definitions/ErrorResponse" + 500: + description: "server error" + schema: + $ref: "#/definitions/ErrorResponse" + tags: ["Container"] + /containers/{id}/json: + get: + summary: "Inspect a container" + description: "Return low-level information about a container." + operationId: "ContainerInspect" + produces: + - "application/json" + responses: + 200: + description: "no error" + schema: + type: "object" + title: "ContainerInspectResponse" + properties: + Id: + description: "The ID of the container" + type: "string" + Created: + description: "The time the container was created" + type: "string" + Path: + description: "The path to the command being run" + type: "string" + Args: + description: "The arguments to the command being run" + type: "array" + items: + type: "string" + State: + $ref: "#/definitions/ContainerState" + Image: + description: "The container's image ID" + type: "string" + ResolvConfPath: + type: "string" + HostnamePath: + type: "string" + HostsPath: + type: "string" + LogPath: + type: "string" + Name: + type: "string" + RestartCount: + type: "integer" + Driver: + type: "string" + Platform: + type: "string" + MountLabel: + type: "string" + ProcessLabel: + type: "string" + AppArmorProfile: + type: "string" + ExecIDs: + description: "IDs of exec instances that are running in the container." + type: "array" + items: + type: "string" + x-nullable: true + HostConfig: + $ref: "#/definitions/HostConfig" + GraphDriver: + $ref: "#/definitions/GraphDriverData" + SizeRw: + description: | + The size of files that have been created or changed by this + container. + type: "integer" + format: "int64" + SizeRootFs: + description: "The total size of all the files in this container." + type: "integer" + format: "int64" + Mounts: + type: "array" + items: + $ref: "#/definitions/MountPoint" + Config: + $ref: "#/definitions/ContainerConfig" + NetworkSettings: + $ref: "#/definitions/NetworkSettings" + examples: + application/json: + AppArmorProfile: "" + Args: + - "-c" + - "exit 9" + Config: + AttachStderr: true + AttachStdin: false + AttachStdout: true + Cmd: + - "/bin/sh" + - "-c" + - "exit 9" + Domainname: "" + Env: + - "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" + Healthcheck: + Test: ["CMD-SHELL", "exit 0"] + Hostname: "ba033ac44011" + Image: "ubuntu" + Labels: + com.example.vendor: "Acme" + com.example.license: "GPL" + com.example.version: "1.0" + MacAddress: "" + NetworkDisabled: false + OpenStdin: false + StdinOnce: false + Tty: false + User: "" + Volumes: + /volumes/data: {} + WorkingDir: "" + StopSignal: "SIGTERM" + StopTimeout: 10 + Created: "2015-01-06T15:47:31.485331387Z" + Driver: "devicemapper" + ExecIDs: + - "b35395de42bc8abd327f9dd65d913b9ba28c74d2f0734eeeae84fa1c616a0fca" + - "3fc1232e5cd20c8de182ed81178503dc6437f4e7ef12b52cc5e8de020652f1c4" + HostConfig: + MaximumIOps: 0 + MaximumIOBps: 0 + BlkioWeight: 0 + BlkioWeightDevice: + - {} + BlkioDeviceReadBps: + - {} + BlkioDeviceWriteBps: + - {} + BlkioDeviceReadIOps: + - {} + BlkioDeviceWriteIOps: + - {} + ContainerIDFile: "" + CpusetCpus: "" + CpusetMems: "" + CpuPercent: 80 + CpuShares: 0 + CpuPeriod: 100000 + CpuRealtimePeriod: 1000000 + CpuRealtimeRuntime: 10000 + Devices: [] + DeviceRequests: + - Driver: "nvidia" + Count: -1 + DeviceIDs": ["0", "1", "GPU-fef8089b-4820-abfc-e83e-94318197576e"] + Capabilities: [["gpu", "nvidia", "compute"]] + Options: + property1: "string" + property2: "string" + IpcMode: "" + Memory: 0 + MemorySwap: 0 + MemoryReservation: 0 + OomKillDisable: false + OomScoreAdj: 500 + NetworkMode: "bridge" + PidMode: "" + PortBindings: {} + Privileged: false + ReadonlyRootfs: false + PublishAllPorts: false + RestartPolicy: + MaximumRetryCount: 2 + Name: "on-failure" + LogConfig: + Type: "json-file" + Sysctls: + net.ipv4.ip_forward: "1" + Ulimits: + - {} + VolumeDriver: "" + ShmSize: 67108864 + HostnamePath: "/var/lib/docker/containers/ba033ac4401106a3b513bc9d639eee123ad78ca3616b921167cd74b20e25ed39/hostname" + HostsPath: "/var/lib/docker/containers/ba033ac4401106a3b513bc9d639eee123ad78ca3616b921167cd74b20e25ed39/hosts" + LogPath: "/var/lib/docker/containers/1eb5fabf5a03807136561b3c00adcd2992b535d624d5e18b6cdc6a6844d9767b/1eb5fabf5a03807136561b3c00adcd2992b535d624d5e18b6cdc6a6844d9767b-json.log" + Id: "ba033ac4401106a3b513bc9d639eee123ad78ca3616b921167cd74b20e25ed39" + Image: "04c5d3b7b0656168630d3ba35d8889bd0e9caafcaeb3004d2bfbc47e7c5d35d2" + MountLabel: "" + Name: "/boring_euclid" + NetworkSettings: + Bridge: "" + SandboxID: "" + HairpinMode: false + LinkLocalIPv6Address: "" + LinkLocalIPv6PrefixLen: 0 + SandboxKey: "" + EndpointID: "" + Gateway: "" + GlobalIPv6Address: "" + GlobalIPv6PrefixLen: 0 + IPAddress: "" + IPPrefixLen: 0 + IPv6Gateway: "" + MacAddress: "" + Networks: + bridge: + NetworkID: "7ea29fc1412292a2d7bba362f9253545fecdfa8ce9a6e37dd10ba8bee7129812" + EndpointID: "7587b82f0dada3656fda26588aee72630c6fab1536d36e394b2bfbcf898c971d" + Gateway: "172.17.0.1" + IPAddress: "172.17.0.2" + IPPrefixLen: 16 + IPv6Gateway: "" + GlobalIPv6Address: "" + GlobalIPv6PrefixLen: 0 + MacAddress: "02:42:ac:12:00:02" + Path: "/bin/sh" + ProcessLabel: "" + ResolvConfPath: "/var/lib/docker/containers/ba033ac4401106a3b513bc9d639eee123ad78ca3616b921167cd74b20e25ed39/resolv.conf" + RestartCount: 1 + State: + Error: "" + ExitCode: 9 + FinishedAt: "2015-01-06T15:47:32.080254511Z" + Health: + Status: "healthy" + FailingStreak: 0 + Log: + - Start: "2019-12-22T10:59:05.6385933Z" + End: "2019-12-22T10:59:05.8078452Z" + ExitCode: 0 + Output: "" + OOMKilled: false + Dead: false + Paused: false + Pid: 0 + Restarting: false + Running: true + StartedAt: "2015-01-06T15:47:32.072697474Z" + Status: "running" + Mounts: + - Name: "fac362...80535" + Source: "/data" + Destination: "/data" + Driver: "local" + Mode: "ro,Z" + RW: false + Propagation: "" + 404: + description: "no such container" + schema: + $ref: "#/definitions/ErrorResponse" + examples: + application/json: + message: "No such container: c2ada9df5af8" + 500: + description: "server error" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "id" + in: "path" + required: true + description: "ID or name of the container" + type: "string" + - name: "size" + in: "query" + type: "boolean" + default: false + description: "Return the size of container as fields `SizeRw` and `SizeRootFs`" + tags: ["Container"] + /containers/{id}/top: + get: + summary: "List processes running inside a container" + description: | + On Unix systems, this is done by running the `ps` command. This endpoint + is not supported on Windows. + operationId: "ContainerTop" + responses: + 200: + description: "no error" + schema: + type: "object" + title: "ContainerTopResponse" + description: "OK response to ContainerTop operation" + properties: + Titles: + description: "The ps column titles" + type: "array" + items: + type: "string" + Processes: + description: | + Each process running in the container, where each is process + is an array of values corresponding to the titles. + type: "array" + items: + type: "array" + items: + type: "string" + examples: + application/json: + Titles: + - "UID" + - "PID" + - "PPID" + - "C" + - "STIME" + - "TTY" + - "TIME" + - "CMD" + Processes: + - + - "root" + - "13642" + - "882" + - "0" + - "17:03" + - "pts/0" + - "00:00:00" + - "/bin/bash" + - + - "root" + - "13735" + - "13642" + - "0" + - "17:06" + - "pts/0" + - "00:00:00" + - "sleep 10" + 404: + description: "no such container" + schema: + $ref: "#/definitions/ErrorResponse" + examples: + application/json: + message: "No such container: c2ada9df5af8" + 500: + description: "server error" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "id" + in: "path" + required: true + description: "ID or name of the container" + type: "string" + - name: "ps_args" + in: "query" + description: "The arguments to pass to `ps`. For example, `aux`" + type: "string" + default: "-ef" + tags: ["Container"] + /containers/{id}/logs: + get: + summary: "Get container logs" + description: | + Get `stdout` and `stderr` logs from a container. + + Note: This endpoint works only for containers with the `json-file` or + `journald` logging driver. + produces: + - "application/vnd.docker.raw-stream" + - "application/vnd.docker.multiplexed-stream" + operationId: "ContainerLogs" + responses: + 200: + description: | + logs returned as a stream in response body. + For the stream format, [see the documentation for the attach endpoint](#operation/ContainerAttach). + Note that unlike the attach endpoint, the logs endpoint does not + upgrade the connection and does not set Content-Type. + schema: + type: "string" + format: "binary" + 404: + description: "no such container" + schema: + $ref: "#/definitions/ErrorResponse" + examples: + application/json: + message: "No such container: c2ada9df5af8" + 500: + description: "server error" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "id" + in: "path" + required: true + description: "ID or name of the container" + type: "string" + - name: "follow" + in: "query" + description: "Keep connection after returning logs." + type: "boolean" + default: false + - name: "stdout" + in: "query" + description: "Return logs from `stdout`" + type: "boolean" + default: false + - name: "stderr" + in: "query" + description: "Return logs from `stderr`" + type: "boolean" + default: false + - name: "since" + in: "query" + description: "Only return logs since this time, as a UNIX timestamp" + type: "integer" + default: 0 + - name: "until" + in: "query" + description: "Only return logs before this time, as a UNIX timestamp" + type: "integer" + default: 0 + - name: "timestamps" + in: "query" + description: "Add timestamps to every log line" + type: "boolean" + default: false + - name: "tail" + in: "query" + description: | + Only return this number of log lines from the end of the logs. + Specify as an integer or `all` to output all log lines. + type: "string" + default: "all" + tags: ["Container"] + /containers/{id}/changes: + get: + summary: "Get changes on a container’s filesystem" + description: | + Returns which files in a container's filesystem have been added, deleted, + or modified. The `Kind` of modification can be one of: + + - `0`: Modified + - `1`: Added + - `2`: Deleted + operationId: "ContainerChanges" + produces: ["application/json"] + responses: + 200: + description: "The list of changes" + schema: + type: "array" + items: + type: "object" + x-go-name: "ContainerChangeResponseItem" + title: "ContainerChangeResponseItem" + description: "change item in response to ContainerChanges operation" + required: [Path, Kind] + properties: + Path: + description: "Path to file that has changed" + type: "string" + x-nullable: false + Kind: + description: "Kind of change" + type: "integer" + format: "uint8" + enum: [0, 1, 2] + x-nullable: false + examples: + application/json: + - Path: "/dev" + Kind: 0 + - Path: "/dev/kmsg" + Kind: 1 + - Path: "/test" + Kind: 1 + 404: + description: "no such container" + schema: + $ref: "#/definitions/ErrorResponse" + examples: + application/json: + message: "No such container: c2ada9df5af8" + 500: + description: "server error" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "id" + in: "path" + required: true + description: "ID or name of the container" + type: "string" + tags: ["Container"] + /containers/{id}/export: + get: + summary: "Export a container" + description: "Export the contents of a container as a tarball." + operationId: "ContainerExport" + produces: + - "application/octet-stream" + responses: + 200: + description: "no error" + 404: + description: "no such container" + schema: + $ref: "#/definitions/ErrorResponse" + examples: + application/json: + message: "No such container: c2ada9df5af8" + 500: + description: "server error" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "id" + in: "path" + required: true + description: "ID or name of the container" + type: "string" + tags: ["Container"] + /containers/{id}/stats: + get: + summary: "Get container stats based on resource usage" + description: | + This endpoint returns a live stream of a container’s resource usage + statistics. + + The `precpu_stats` is the CPU statistic of the *previous* read, and is + used to calculate the CPU usage percentage. It is not an exact copy + of the `cpu_stats` field. + + If either `precpu_stats.online_cpus` or `cpu_stats.online_cpus` is + nil then for compatibility with older daemons the length of the + corresponding `cpu_usage.percpu_usage` array should be used. + + On a cgroup v2 host, the following fields are not set + * `blkio_stats`: all fields other than `io_service_bytes_recursive` + * `cpu_stats`: `cpu_usage.percpu_usage` + * `memory_stats`: `max_usage` and `failcnt` + Also, `memory_stats.stats` fields are incompatible with cgroup v1. + + To calculate the values shown by the `stats` command of the docker cli tool + the following formulas can be used: + * used_memory = `memory_stats.usage - memory_stats.stats.cache` + * available_memory = `memory_stats.limit` + * Memory usage % = `(used_memory / available_memory) * 100.0` + * cpu_delta = `cpu_stats.cpu_usage.total_usage - precpu_stats.cpu_usage.total_usage` + * system_cpu_delta = `cpu_stats.system_cpu_usage - precpu_stats.system_cpu_usage` + * number_cpus = `lenght(cpu_stats.cpu_usage.percpu_usage)` or `cpu_stats.online_cpus` + * CPU usage % = `(cpu_delta / system_cpu_delta) * number_cpus * 100.0` + operationId: "ContainerStats" + produces: ["application/json"] + responses: + 200: + description: "no error" + schema: + type: "object" + examples: + application/json: + read: "2015-01-08T22:57:31.547920715Z" + pids_stats: + current: 3 + networks: + eth0: + rx_bytes: 5338 + rx_dropped: 0 + rx_errors: 0 + rx_packets: 36 + tx_bytes: 648 + tx_dropped: 0 + tx_errors: 0 + tx_packets: 8 + eth5: + rx_bytes: 4641 + rx_dropped: 0 + rx_errors: 0 + rx_packets: 26 + tx_bytes: 690 + tx_dropped: 0 + tx_errors: 0 + tx_packets: 9 + memory_stats: + stats: + total_pgmajfault: 0 + cache: 0 + mapped_file: 0 + total_inactive_file: 0 + pgpgout: 414 + rss: 6537216 + total_mapped_file: 0 + writeback: 0 + unevictable: 0 + pgpgin: 477 + total_unevictable: 0 + pgmajfault: 0 + total_rss: 6537216 + total_rss_huge: 6291456 + total_writeback: 0 + total_inactive_anon: 0 + rss_huge: 6291456 + hierarchical_memory_limit: 67108864 + total_pgfault: 964 + total_active_file: 0 + active_anon: 6537216 + total_active_anon: 6537216 + total_pgpgout: 414 + total_cache: 0 + inactive_anon: 0 + active_file: 0 + pgfault: 964 + inactive_file: 0 + total_pgpgin: 477 + max_usage: 6651904 + usage: 6537216 + failcnt: 0 + limit: 67108864 + blkio_stats: {} + cpu_stats: + cpu_usage: + percpu_usage: + - 8646879 + - 24472255 + - 36438778 + - 30657443 + usage_in_usermode: 50000000 + total_usage: 100215355 + usage_in_kernelmode: 30000000 + system_cpu_usage: 739306590000000 + online_cpus: 4 + throttling_data: + periods: 0 + throttled_periods: 0 + throttled_time: 0 + precpu_stats: + cpu_usage: + percpu_usage: + - 8646879 + - 24350896 + - 36438778 + - 30657443 + usage_in_usermode: 50000000 + total_usage: 100093996 + usage_in_kernelmode: 30000000 + system_cpu_usage: 9492140000000 + online_cpus: 4 + throttling_data: + periods: 0 + throttled_periods: 0 + throttled_time: 0 + 404: + description: "no such container" + schema: + $ref: "#/definitions/ErrorResponse" + examples: + application/json: + message: "No such container: c2ada9df5af8" + 500: + description: "server error" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "id" + in: "path" + required: true + description: "ID or name of the container" + type: "string" + - name: "stream" + in: "query" + description: | + Stream the output. If false, the stats will be output once and then + it will disconnect. + type: "boolean" + default: true + - name: "one-shot" + in: "query" + description: | + Only get a single stat instead of waiting for 2 cycles. Must be used + with `stream=false`. + type: "boolean" + default: false + tags: ["Container"] + /containers/{id}/resize: + post: + summary: "Resize a container TTY" + description: "Resize the TTY for a container." + operationId: "ContainerResize" + consumes: + - "application/octet-stream" + produces: + - "text/plain" + responses: + 200: + description: "no error" + 404: + description: "no such container" + schema: + $ref: "#/definitions/ErrorResponse" + examples: + application/json: + message: "No such container: c2ada9df5af8" + 500: + description: "cannot resize container" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "id" + in: "path" + required: true + description: "ID or name of the container" + type: "string" + - name: "h" + in: "query" + description: "Height of the TTY session in characters" + type: "integer" + - name: "w" + in: "query" + description: "Width of the TTY session in characters" + type: "integer" + tags: ["Container"] + /containers/{id}/start: + post: + summary: "Start a container" + operationId: "ContainerStart" + responses: + 204: + description: "no error" + 304: + description: "container already started" + 404: + description: "no such container" + schema: + $ref: "#/definitions/ErrorResponse" + examples: + application/json: + message: "No such container: c2ada9df5af8" + 500: + description: "server error" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "id" + in: "path" + required: true + description: "ID or name of the container" + type: "string" + - name: "detachKeys" + in: "query" + description: | + Override the key sequence for detaching a container. Format is a + single character `[a-Z]` or `ctrl-` where `` is one + of: `a-z`, `@`, `^`, `[`, `,` or `_`. + type: "string" + tags: ["Container"] + /containers/{id}/stop: + post: + summary: "Stop a container" + operationId: "ContainerStop" + responses: + 204: + description: "no error" + 304: + description: "container already stopped" + 404: + description: "no such container" + schema: + $ref: "#/definitions/ErrorResponse" + examples: + application/json: + message: "No such container: c2ada9df5af8" + 500: + description: "server error" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "id" + in: "path" + required: true + description: "ID or name of the container" + type: "string" + - name: "signal" + in: "query" + description: | + Signal to send to the container as an integer or string (e.g. `SIGINT`). + type: "string" + - name: "t" + in: "query" + description: "Number of seconds to wait before killing the container" + type: "integer" + tags: ["Container"] + /containers/{id}/restart: + post: + summary: "Restart a container" + operationId: "ContainerRestart" + responses: + 204: + description: "no error" + 404: + description: "no such container" + schema: + $ref: "#/definitions/ErrorResponse" + examples: + application/json: + message: "No such container: c2ada9df5af8" + 500: + description: "server error" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "id" + in: "path" + required: true + description: "ID or name of the container" + type: "string" + - name: "signal" + in: "query" + description: | + Signal to send to the container as an integer or string (e.g. `SIGINT`). + type: "string" + - name: "t" + in: "query" + description: "Number of seconds to wait before killing the container" + type: "integer" + tags: ["Container"] + /containers/{id}/kill: + post: + summary: "Kill a container" + description: | + Send a POSIX signal to a container, defaulting to killing to the + container. + operationId: "ContainerKill" + responses: + 204: + description: "no error" + 404: + description: "no such container" + schema: + $ref: "#/definitions/ErrorResponse" + examples: + application/json: + message: "No such container: c2ada9df5af8" + 409: + description: "container is not running" + schema: + $ref: "#/definitions/ErrorResponse" + examples: + application/json: + message: "Container d37cde0fe4ad63c3a7252023b2f9800282894247d145cb5933ddf6e52cc03a28 is not running" + 500: + description: "server error" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "id" + in: "path" + required: true + description: "ID or name of the container" + type: "string" + - name: "signal" + in: "query" + description: | + Signal to send to the container as an integer or string (e.g. `SIGINT`). + type: "string" + default: "SIGKILL" + tags: ["Container"] + /containers/{id}/update: + post: + summary: "Update a container" + description: | + Change various configuration options of a container without having to + recreate it. + operationId: "ContainerUpdate" + consumes: ["application/json"] + produces: ["application/json"] + responses: + 200: + description: "The container has been updated." + schema: + type: "object" + title: "ContainerUpdateResponse" + description: "OK response to ContainerUpdate operation" + properties: + Warnings: + type: "array" + items: + type: "string" + 404: + description: "no such container" + schema: + $ref: "#/definitions/ErrorResponse" + examples: + application/json: + message: "No such container: c2ada9df5af8" + 500: + description: "server error" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "id" + in: "path" + required: true + description: "ID or name of the container" + type: "string" + - name: "update" + in: "body" + required: true + schema: + allOf: + - $ref: "#/definitions/Resources" + - type: "object" + properties: + RestartPolicy: + $ref: "#/definitions/RestartPolicy" + example: + BlkioWeight: 300 + CpuShares: 512 + CpuPeriod: 100000 + CpuQuota: 50000 + CpuRealtimePeriod: 1000000 + CpuRealtimeRuntime: 10000 + CpusetCpus: "0,1" + CpusetMems: "0" + Memory: 314572800 + MemorySwap: 514288000 + MemoryReservation: 209715200 + RestartPolicy: + MaximumRetryCount: 4 + Name: "on-failure" + tags: ["Container"] + /containers/{id}/rename: + post: + summary: "Rename a container" + operationId: "ContainerRename" + responses: + 204: + description: "no error" + 404: + description: "no such container" + schema: + $ref: "#/definitions/ErrorResponse" + examples: + application/json: + message: "No such container: c2ada9df5af8" + 409: + description: "name already in use" + schema: + $ref: "#/definitions/ErrorResponse" + 500: + description: "server error" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "id" + in: "path" + required: true + description: "ID or name of the container" + type: "string" + - name: "name" + in: "query" + required: true + description: "New name for the container" + type: "string" + tags: ["Container"] + /containers/{id}/pause: + post: + summary: "Pause a container" + description: | + Use the freezer cgroup to suspend all processes in a container. + + Traditionally, when suspending a process the `SIGSTOP` signal is used, + which is observable by the process being suspended. With the freezer + cgroup the process is unaware, and unable to capture, that it is being + suspended, and subsequently resumed. + operationId: "ContainerPause" + responses: + 204: + description: "no error" + 404: + description: "no such container" + schema: + $ref: "#/definitions/ErrorResponse" + examples: + application/json: + message: "No such container: c2ada9df5af8" + 500: + description: "server error" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "id" + in: "path" + required: true + description: "ID or name of the container" + type: "string" + tags: ["Container"] + /containers/{id}/unpause: + post: + summary: "Unpause a container" + description: "Resume a container which has been paused." + operationId: "ContainerUnpause" + responses: + 204: + description: "no error" + 404: + description: "no such container" + schema: + $ref: "#/definitions/ErrorResponse" + examples: + application/json: + message: "No such container: c2ada9df5af8" + 500: + description: "server error" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "id" + in: "path" + required: true + description: "ID or name of the container" + type: "string" + tags: ["Container"] + /containers/{id}/attach: + post: + summary: "Attach to a container" + description: | + Attach to a container to read its output or send it input. You can attach + to the same container multiple times and you can reattach to containers + that have been detached. + + Either the `stream` or `logs` parameter must be `true` for this endpoint + to do anything. + + See the [documentation for the `docker attach` command](https://docs.docker.com/engine/reference/commandline/attach/) + for more details. + + ### Hijacking + + This endpoint hijacks the HTTP connection to transport `stdin`, `stdout`, + and `stderr` on the same socket. + + This is the response from the daemon for an attach request: + + ``` + HTTP/1.1 200 OK + Content-Type: application/vnd.docker.raw-stream + + [STREAM] + ``` + + After the headers and two new lines, the TCP connection can now be used + for raw, bidirectional communication between the client and server. + + To hint potential proxies about connection hijacking, the Docker client + can also optionally send connection upgrade headers. + + For example, the client sends this request to upgrade the connection: + + ``` + POST /containers/16253994b7c4/attach?stream=1&stdout=1 HTTP/1.1 + Upgrade: tcp + Connection: Upgrade + ``` + + The Docker daemon will respond with a `101 UPGRADED` response, and will + similarly follow with the raw stream: + + ``` + HTTP/1.1 101 UPGRADED + Content-Type: application/vnd.docker.raw-stream + Connection: Upgrade + Upgrade: tcp + + [STREAM] + ``` + + ### Stream format + + When the TTY setting is disabled in [`POST /containers/create`](#operation/ContainerCreate), + the HTTP Content-Type header is set to application/vnd.docker.multiplexed-stream + and the stream over the hijacked connected is multiplexed to separate out + `stdout` and `stderr`. The stream consists of a series of frames, each + containing a header and a payload. + + The header contains the information which the stream writes (`stdout` or + `stderr`). It also contains the size of the associated frame encoded in + the last four bytes (`uint32`). + + It is encoded on the first eight bytes like this: + + ```go + header := [8]byte{STREAM_TYPE, 0, 0, 0, SIZE1, SIZE2, SIZE3, SIZE4} + ``` + + `STREAM_TYPE` can be: + + - 0: `stdin` (is written on `stdout`) + - 1: `stdout` + - 2: `stderr` + + `SIZE1, SIZE2, SIZE3, SIZE4` are the four bytes of the `uint32` size + encoded as big endian. + + Following the header is the payload, which is the specified number of + bytes of `STREAM_TYPE`. + + The simplest way to implement this protocol is the following: + + 1. Read 8 bytes. + 2. Choose `stdout` or `stderr` depending on the first byte. + 3. Extract the frame size from the last four bytes. + 4. Read the extracted size and output it on the correct output. + 5. Goto 1. + + ### Stream format when using a TTY + + When the TTY setting is enabled in [`POST /containers/create`](#operation/ContainerCreate), + the stream is not multiplexed. The data exchanged over the hijacked + connection is simply the raw data from the process PTY and client's + `stdin`. + + operationId: "ContainerAttach" + produces: + - "application/vnd.docker.raw-stream" + - "application/vnd.docker.multiplexed-stream" + responses: + 101: + description: "no error, hints proxy about hijacking" + 200: + description: "no error, no upgrade header found" + 400: + description: "bad parameter" + schema: + $ref: "#/definitions/ErrorResponse" + 404: + description: "no such container" + schema: + $ref: "#/definitions/ErrorResponse" + examples: + application/json: + message: "No such container: c2ada9df5af8" + 500: + description: "server error" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "id" + in: "path" + required: true + description: "ID or name of the container" + type: "string" + - name: "detachKeys" + in: "query" + description: | + Override the key sequence for detaching a container.Format is a single + character `[a-Z]` or `ctrl-` where `` is one of: `a-z`, + `@`, `^`, `[`, `,` or `_`. + type: "string" + - name: "logs" + in: "query" + description: | + Replay previous logs from the container. + + This is useful for attaching to a container that has started and you + want to output everything since the container started. + + If `stream` is also enabled, once all the previous output has been + returned, it will seamlessly transition into streaming current + output. + type: "boolean" + default: false + - name: "stream" + in: "query" + description: | + Stream attached streams from the time the request was made onwards. + type: "boolean" + default: false + - name: "stdin" + in: "query" + description: "Attach to `stdin`" + type: "boolean" + default: false + - name: "stdout" + in: "query" + description: "Attach to `stdout`" + type: "boolean" + default: false + - name: "stderr" + in: "query" + description: "Attach to `stderr`" + type: "boolean" + default: false + tags: ["Container"] + /containers/{id}/attach/ws: + get: + summary: "Attach to a container via a websocket" + operationId: "ContainerAttachWebsocket" + responses: + 101: + description: "no error, hints proxy about hijacking" + 200: + description: "no error, no upgrade header found" + 400: + description: "bad parameter" + schema: + $ref: "#/definitions/ErrorResponse" + 404: + description: "no such container" + schema: + $ref: "#/definitions/ErrorResponse" + examples: + application/json: + message: "No such container: c2ada9df5af8" + 500: + description: "server error" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "id" + in: "path" + required: true + description: "ID or name of the container" + type: "string" + - name: "detachKeys" + in: "query" + description: | + Override the key sequence for detaching a container.Format is a single + character `[a-Z]` or `ctrl-` where `` is one of: `a-z`, + `@`, `^`, `[`, `,`, or `_`. + type: "string" + - name: "logs" + in: "query" + description: "Return logs" + type: "boolean" + default: false + - name: "stream" + in: "query" + description: "Return stream" + type: "boolean" + default: false + - name: "stdin" + in: "query" + description: "Attach to `stdin`" + type: "boolean" + default: false + - name: "stdout" + in: "query" + description: "Attach to `stdout`" + type: "boolean" + default: false + - name: "stderr" + in: "query" + description: "Attach to `stderr`" + type: "boolean" + default: false + tags: ["Container"] + /containers/{id}/wait: + post: + summary: "Wait for a container" + description: "Block until a container stops, then returns the exit code." + operationId: "ContainerWait" + produces: ["application/json"] + responses: + 200: + description: "The container has exit." + schema: + $ref: "#/definitions/ContainerWaitResponse" + 400: + description: "bad parameter" + schema: + $ref: "#/definitions/ErrorResponse" + 404: + description: "no such container" + schema: + $ref: "#/definitions/ErrorResponse" + examples: + application/json: + message: "No such container: c2ada9df5af8" + 500: + description: "server error" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "id" + in: "path" + required: true + description: "ID or name of the container" + type: "string" + - name: "condition" + in: "query" + description: | + Wait until a container state reaches the given condition. + + Defaults to `not-running` if omitted or empty. + type: "string" + enum: + - "not-running" + - "next-exit" + - "removed" + default: "not-running" + tags: ["Container"] + /containers/{id}: + delete: + summary: "Remove a container" + operationId: "ContainerDelete" + responses: + 204: + description: "no error" + 400: + description: "bad parameter" + schema: + $ref: "#/definitions/ErrorResponse" + 404: + description: "no such container" + schema: + $ref: "#/definitions/ErrorResponse" + examples: + application/json: + message: "No such container: c2ada9df5af8" + 409: + description: "conflict" + schema: + $ref: "#/definitions/ErrorResponse" + examples: + application/json: + message: | + You cannot remove a running container: c2ada9df5af8. Stop the + container before attempting removal or force remove + 500: + description: "server error" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "id" + in: "path" + required: true + description: "ID or name of the container" + type: "string" + - name: "v" + in: "query" + description: "Remove anonymous volumes associated with the container." + type: "boolean" + default: false + - name: "force" + in: "query" + description: "If the container is running, kill it before removing it." + type: "boolean" + default: false + - name: "link" + in: "query" + description: "Remove the specified link associated with the container." + type: "boolean" + default: false + tags: ["Container"] + /containers/{id}/archive: + head: + summary: "Get information about files in a container" + description: | + A response header `X-Docker-Container-Path-Stat` is returned, containing + a base64 - encoded JSON object with some filesystem header information + about the path. + operationId: "ContainerArchiveInfo" + responses: + 200: + description: "no error" + headers: + X-Docker-Container-Path-Stat: + type: "string" + description: | + A base64 - encoded JSON object with some filesystem header + information about the path + 400: + description: "Bad parameter" + schema: + $ref: "#/definitions/ErrorResponse" + 404: + description: "Container or path does not exist" + schema: + $ref: "#/definitions/ErrorResponse" + examples: + application/json: + message: "No such container: c2ada9df5af8" + 500: + description: "Server error" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "id" + in: "path" + required: true + description: "ID or name of the container" + type: "string" + - name: "path" + in: "query" + required: true + description: "Resource in the container’s filesystem to archive." + type: "string" + tags: ["Container"] + get: + summary: "Get an archive of a filesystem resource in a container" + description: "Get a tar archive of a resource in the filesystem of container id." + operationId: "ContainerArchive" + produces: ["application/x-tar"] + responses: + 200: + description: "no error" + 400: + description: "Bad parameter" + schema: + $ref: "#/definitions/ErrorResponse" + 404: + description: "Container or path does not exist" + schema: + $ref: "#/definitions/ErrorResponse" + examples: + application/json: + message: "No such container: c2ada9df5af8" + 500: + description: "server error" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "id" + in: "path" + required: true + description: "ID or name of the container" + type: "string" + - name: "path" + in: "query" + required: true + description: "Resource in the container’s filesystem to archive." + type: "string" + tags: ["Container"] + put: + summary: "Extract an archive of files or folders to a directory in a container" + description: | + Upload a tar archive to be extracted to a path in the filesystem of container id. + `path` parameter is asserted to be a directory. If it exists as a file, 400 error + will be returned with message "not a directory". + operationId: "PutContainerArchive" + consumes: ["application/x-tar", "application/octet-stream"] + responses: + 200: + description: "The content was extracted successfully" + 400: + description: "Bad parameter" + schema: + $ref: "#/definitions/ErrorResponse" + examples: + application/json: + message: "not a directory" + 403: + description: "Permission denied, the volume or container rootfs is marked as read-only." + schema: + $ref: "#/definitions/ErrorResponse" + 404: + description: "No such container or path does not exist inside the container" + schema: + $ref: "#/definitions/ErrorResponse" + examples: + application/json: + message: "No such container: c2ada9df5af8" + 500: + description: "Server error" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "id" + in: "path" + required: true + description: "ID or name of the container" + type: "string" + - name: "path" + in: "query" + required: true + description: "Path to a directory in the container to extract the archive’s contents into. " + type: "string" + - name: "noOverwriteDirNonDir" + in: "query" + description: | + If `1`, `true`, or `True` then it will be an error if unpacking the + given content would cause an existing directory to be replaced with + a non-directory and vice versa. + type: "string" + - name: "copyUIDGID" + in: "query" + description: | + If `1`, `true`, then it will copy UID/GID maps to the dest file or + dir + type: "string" + - name: "inputStream" + in: "body" + required: true + description: | + The input stream must be a tar archive compressed with one of the + following algorithms: `identity` (no compression), `gzip`, `bzip2`, + or `xz`. + schema: + type: "string" + format: "binary" + tags: ["Container"] + /containers/prune: + post: + summary: "Delete stopped containers" + produces: + - "application/json" + operationId: "ContainerPrune" + parameters: + - name: "filters" + in: "query" + description: | + Filters to process on the prune list, encoded as JSON (a `map[string][]string`). + + Available filters: + - `until=` Prune containers created before this timestamp. The `` can be Unix timestamps, date formatted timestamps, or Go duration strings (e.g. `10m`, `1h30m`) computed relative to the daemon machine’s time. + - `label` (`label=`, `label==`, `label!=`, or `label!==`) Prune containers with (or without, in case `label!=...` is used) the specified labels. + type: "string" + responses: + 200: + description: "No error" + schema: + type: "object" + title: "ContainerPruneResponse" + properties: + ContainersDeleted: + description: "Container IDs that were deleted" + type: "array" + items: + type: "string" + SpaceReclaimed: + description: "Disk space reclaimed in bytes" + type: "integer" + format: "int64" + 500: + description: "Server error" + schema: + $ref: "#/definitions/ErrorResponse" + tags: ["Container"] + /images/json: + get: + summary: "List Images" + description: "Returns a list of images on the server. Note that it uses a different, smaller representation of an image than inspecting a single image." + operationId: "ImageList" + produces: + - "application/json" + responses: + 200: + description: "Summary image data for the images matching the query" + schema: + type: "array" + items: + $ref: "#/definitions/ImageSummary" + 500: + description: "server error" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "all" + in: "query" + description: "Show all images. Only images from a final layer (no children) are shown by default." + type: "boolean" + default: false + - name: "filters" + in: "query" + description: | + A JSON encoded value of the filters (a `map[string][]string`) to + process on the images list. + + Available filters: + + - `before`=(`[:]`, `` or ``) + - `dangling=true` + - `label=key` or `label="key=value"` of an image label + - `reference`=(`[:]`) + - `since`=(`[:]`, `` or ``) + type: "string" + - name: "shared-size" + in: "query" + description: "Compute and show shared size as a `SharedSize` field on each image." + type: "boolean" + default: false + - name: "digests" + in: "query" + description: "Show digest information as a `RepoDigests` field on each image." + type: "boolean" + default: false + tags: ["Image"] + /build: + post: + summary: "Build an image" + description: | + Build an image from a tar archive with a `Dockerfile` in it. + + The `Dockerfile` specifies how the image is built from the tar archive. It is typically in the archive's root, but can be at a different path or have a different name by specifying the `dockerfile` parameter. [See the `Dockerfile` reference for more information](https://docs.docker.com/engine/reference/builder/). + + The Docker daemon performs a preliminary validation of the `Dockerfile` before starting the build, and returns an error if the syntax is incorrect. After that, each instruction is run one-by-one until the ID of the new image is output. + + The build is canceled if the client drops the connection by quitting or being killed. + operationId: "ImageBuild" + consumes: + - "application/octet-stream" + produces: + - "application/json" + parameters: + - name: "inputStream" + in: "body" + description: "A tar archive compressed with one of the following algorithms: identity (no compression), gzip, bzip2, xz." + schema: + type: "string" + format: "binary" + - name: "dockerfile" + in: "query" + description: "Path within the build context to the `Dockerfile`. This is ignored if `remote` is specified and points to an external `Dockerfile`." + type: "string" + default: "Dockerfile" + - name: "t" + in: "query" + description: "A name and optional tag to apply to the image in the `name:tag` format. If you omit the tag the default `latest` value is assumed. You can provide several `t` parameters." + type: "string" + - name: "extrahosts" + in: "query" + description: "Extra hosts to add to /etc/hosts" + type: "string" + - name: "remote" + in: "query" + description: "A Git repository URI or HTTP/HTTPS context URI. If the URI points to a single text file, the file’s contents are placed into a file called `Dockerfile` and the image is built from that file. If the URI points to a tarball, the file is downloaded by the daemon and the contents therein used as the context for the build. If the URI points to a tarball and the `dockerfile` parameter is also specified, there must be a file with the corresponding path inside the tarball." + type: "string" + - name: "q" + in: "query" + description: "Suppress verbose build output." + type: "boolean" + default: false + - name: "nocache" + in: "query" + description: "Do not use the cache when building the image." + type: "boolean" + default: false + - name: "cachefrom" + in: "query" + description: "JSON array of images used for build cache resolution." + type: "string" + - name: "pull" + in: "query" + description: "Attempt to pull the image even if an older image exists locally." + type: "string" + - name: "rm" + in: "query" + description: "Remove intermediate containers after a successful build." + type: "boolean" + default: true + - name: "forcerm" + in: "query" + description: "Always remove intermediate containers, even upon failure." + type: "boolean" + default: false + - name: "memory" + in: "query" + description: "Set memory limit for build." + type: "integer" + - name: "memswap" + in: "query" + description: "Total memory (memory + swap). Set as `-1` to disable swap." + type: "integer" + - name: "cpushares" + in: "query" + description: "CPU shares (relative weight)." + type: "integer" + - name: "cpusetcpus" + in: "query" + description: "CPUs in which to allow execution (e.g., `0-3`, `0,1`)." + type: "string" + - name: "cpuperiod" + in: "query" + description: "The length of a CPU period in microseconds." + type: "integer" + - name: "cpuquota" + in: "query" + description: "Microseconds of CPU time that the container can get in a CPU period." + type: "integer" + - name: "buildargs" + in: "query" + description: > + JSON map of string pairs for build-time variables. Users pass these values at build-time. Docker + uses the buildargs as the environment context for commands run via the `Dockerfile` RUN + instruction, or for variable expansion in other `Dockerfile` instructions. This is not meant for + passing secret values. + + + For example, the build arg `FOO=bar` would become `{"FOO":"bar"}` in JSON. This would result in the + query parameter `buildargs={"FOO":"bar"}`. Note that `{"FOO":"bar"}` should be URI component encoded. + + + [Read more about the buildargs instruction.](https://docs.docker.com/engine/reference/builder/#arg) + type: "string" + - name: "shmsize" + in: "query" + description: "Size of `/dev/shm` in bytes. The size must be greater than 0. If omitted the system uses 64MB." + type: "integer" + - name: "squash" + in: "query" + description: "Squash the resulting images layers into a single layer. *(Experimental release only.)*" + type: "boolean" + - name: "labels" + in: "query" + description: "Arbitrary key/value labels to set on the image, as a JSON map of string pairs." + type: "string" + - name: "networkmode" + in: "query" + description: | + Sets the networking mode for the run commands during build. Supported + standard values are: `bridge`, `host`, `none`, and `container:`. + Any other value is taken as a custom network's name or ID to which this + container should connect to. + type: "string" + - name: "Content-type" + in: "header" + type: "string" + enum: + - "application/x-tar" + default: "application/x-tar" + - name: "X-Registry-Config" + in: "header" + description: | + This is a base64-encoded JSON object with auth configurations for multiple registries that a build may refer to. + + The key is a registry URL, and the value is an auth configuration object, [as described in the authentication section](#section/Authentication). For example: + + ``` + { + "docker.example.com": { + "username": "janedoe", + "password": "hunter2" + }, + "https://index.docker.io/v1/": { + "username": "mobydock", + "password": "conta1n3rize14" + } + } + ``` + + Only the registry domain name (and port if not the default 443) are required. However, for legacy reasons, the Docker Hub registry must be specified with both a `https://` prefix and a `/v1/` suffix even though Docker will prefer to use the v2 registry API. + type: "string" + - name: "platform" + in: "query" + description: "Platform in the format os[/arch[/variant]]" + type: "string" + default: "" + - name: "target" + in: "query" + description: "Target build stage" + type: "string" + default: "" + - name: "outputs" + in: "query" + description: "BuildKit output configuration" + type: "string" + default: "" + responses: + 200: + description: "no error" + 400: + description: "Bad parameter" + schema: + $ref: "#/definitions/ErrorResponse" + 500: + description: "server error" + schema: + $ref: "#/definitions/ErrorResponse" + tags: ["Image"] + /build/prune: + post: + summary: "Delete builder cache" + produces: + - "application/json" + operationId: "BuildPrune" + parameters: + - name: "keep-storage" + in: "query" + description: "Amount of disk space in bytes to keep for cache" + type: "integer" + format: "int64" + - name: "all" + in: "query" + type: "boolean" + description: "Remove all types of build cache" + - name: "filters" + in: "query" + type: "string" + description: | + A JSON encoded value of the filters (a `map[string][]string`) to + process on the list of build cache objects. + + Available filters: + + - `until=`: duration relative to daemon's time, during which build cache was not used, in Go's duration format (e.g., '24h') + - `id=` + - `parent=` + - `type=` + - `description=` + - `inuse` + - `shared` + - `private` + responses: + 200: + description: "No error" + schema: + type: "object" + title: "BuildPruneResponse" + properties: + CachesDeleted: + type: "array" + items: + description: "ID of build cache object" + type: "string" + SpaceReclaimed: + description: "Disk space reclaimed in bytes" + type: "integer" + format: "int64" + 500: + description: "Server error" + schema: + $ref: "#/definitions/ErrorResponse" + tags: ["Image"] + /images/create: + post: + summary: "Create an image" + description: "Create an image by either pulling it from a registry or importing it." + operationId: "ImageCreate" + consumes: + - "text/plain" + - "application/octet-stream" + produces: + - "application/json" + responses: + 200: + description: "no error" + 404: + description: "repository does not exist or no read access" + schema: + $ref: "#/definitions/ErrorResponse" + 500: + description: "server error" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "fromImage" + in: "query" + description: "Name of the image to pull. The name may include a tag or digest. This parameter may only be used when pulling an image. The pull is cancelled if the HTTP connection is closed." + type: "string" + - name: "fromSrc" + in: "query" + description: "Source to import. The value may be a URL from which the image can be retrieved or `-` to read the image from the request body. This parameter may only be used when importing an image." + type: "string" + - name: "repo" + in: "query" + description: "Repository name given to an image when it is imported. The repo may include a tag. This parameter may only be used when importing an image." + type: "string" + - name: "tag" + in: "query" + description: "Tag or digest. If empty when pulling an image, this causes all tags for the given image to be pulled." + type: "string" + - name: "message" + in: "query" + description: "Set commit message for imported image." + type: "string" + - name: "inputImage" + in: "body" + description: "Image content if the value `-` has been specified in fromSrc query parameter" + schema: + type: "string" + required: false + - name: "X-Registry-Auth" + in: "header" + description: | + A base64url-encoded auth configuration. + + Refer to the [authentication section](#section/Authentication) for + details. + type: "string" + - name: "changes" + in: "query" + description: | + Apply `Dockerfile` instructions to the image that is created, + for example: `changes=ENV DEBUG=true`. + Note that `ENV DEBUG=true` should be URI component encoded. + + Supported `Dockerfile` instructions: + `CMD`|`ENTRYPOINT`|`ENV`|`EXPOSE`|`ONBUILD`|`USER`|`VOLUME`|`WORKDIR` + type: "array" + items: + type: "string" + - name: "platform" + in: "query" + description: | + Platform in the format os[/arch[/variant]]. + + When used in combination with the `fromImage` option, the daemon checks + if the given image is present in the local image cache with the given + OS and Architecture, and otherwise attempts to pull the image. If the + option is not set, the host's native OS and Architecture are used. + If the given image does not exist in the local image cache, the daemon + attempts to pull the image with the host's native OS and Architecture. + If the given image does exists in the local image cache, but its OS or + architecture does not match, a warning is produced. + + When used with the `fromSrc` option to import an image from an archive, + this option sets the platform information for the imported image. If + the option is not set, the host's native OS and Architecture are used + for the imported image. + type: "string" + default: "" + tags: ["Image"] + /images/{name}/json: + get: + summary: "Inspect an image" + description: "Return low-level information about an image." + operationId: "ImageInspect" + produces: + - "application/json" + responses: + 200: + description: "No error" + schema: + $ref: "#/definitions/ImageInspect" + 404: + description: "No such image" + schema: + $ref: "#/definitions/ErrorResponse" + examples: + application/json: + message: "No such image: someimage (tag: latest)" + 500: + description: "Server error" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "name" + in: "path" + description: "Image name or id" + type: "string" + required: true + tags: ["Image"] + /images/{name}/history: + get: + summary: "Get the history of an image" + description: "Return parent layers of an image." + operationId: "ImageHistory" + produces: ["application/json"] + responses: + 200: + description: "List of image layers" + schema: + type: "array" + items: + type: "object" + x-go-name: HistoryResponseItem + title: "HistoryResponseItem" + description: "individual image layer information in response to ImageHistory operation" + required: [Id, Created, CreatedBy, Tags, Size, Comment] + properties: + Id: + type: "string" + x-nullable: false + Created: + type: "integer" + format: "int64" + x-nullable: false + CreatedBy: + type: "string" + x-nullable: false + Tags: + type: "array" + items: + type: "string" + Size: + type: "integer" + format: "int64" + x-nullable: false + Comment: + type: "string" + x-nullable: false + examples: + application/json: + - Id: "3db9c44f45209632d6050b35958829c3a2aa256d81b9a7be45b362ff85c54710" + Created: 1398108230 + CreatedBy: "/bin/sh -c #(nop) ADD file:eb15dbd63394e063b805a3c32ca7bf0266ef64676d5a6fab4801f2e81e2a5148 in /" + Tags: + - "ubuntu:lucid" + - "ubuntu:10.04" + Size: 182964289 + Comment: "" + - Id: "6cfa4d1f33fb861d4d114f43b25abd0ac737509268065cdfd69d544a59c85ab8" + Created: 1398108222 + CreatedBy: "/bin/sh -c #(nop) MAINTAINER Tianon Gravi - mkimage-debootstrap.sh -i iproute,iputils-ping,ubuntu-minimal -t lucid.tar.xz lucid http://archive.ubuntu.com/ubuntu/" + Tags: [] + Size: 0 + Comment: "" + - Id: "511136ea3c5a64f264b78b5433614aec563103b4d4702f3ba7d4d2698e22c158" + Created: 1371157430 + CreatedBy: "" + Tags: + - "scratch12:latest" + - "scratch:latest" + Size: 0 + Comment: "Imported from -" + 404: + description: "No such image" + schema: + $ref: "#/definitions/ErrorResponse" + 500: + description: "Server error" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "name" + in: "path" + description: "Image name or ID" + type: "string" + required: true + tags: ["Image"] + /images/{name}/push: + post: + summary: "Push an image" + description: | + Push an image to a registry. + + If you wish to push an image on to a private registry, that image must + already have a tag which references the registry. For example, + `registry.example.com/myimage:latest`. + + The push is cancelled if the HTTP connection is closed. + operationId: "ImagePush" + consumes: + - "application/octet-stream" + responses: + 200: + description: "No error" + 404: + description: "No such image" + schema: + $ref: "#/definitions/ErrorResponse" + 500: + description: "Server error" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "name" + in: "path" + description: "Image name or ID." + type: "string" + required: true + - name: "tag" + in: "query" + description: "The tag to associate with the image on the registry." + type: "string" + - name: "X-Registry-Auth" + in: "header" + description: | + A base64url-encoded auth configuration. + + Refer to the [authentication section](#section/Authentication) for + details. + type: "string" + required: true + tags: ["Image"] + /images/{name}/tag: + post: + summary: "Tag an image" + description: "Tag an image so that it becomes part of a repository." + operationId: "ImageTag" + responses: + 201: + description: "No error" + 400: + description: "Bad parameter" + schema: + $ref: "#/definitions/ErrorResponse" + 404: + description: "No such image" + schema: + $ref: "#/definitions/ErrorResponse" + 409: + description: "Conflict" + schema: + $ref: "#/definitions/ErrorResponse" + 500: + description: "Server error" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "name" + in: "path" + description: "Image name or ID to tag." + type: "string" + required: true + - name: "repo" + in: "query" + description: "The repository to tag in. For example, `someuser/someimage`." + type: "string" + - name: "tag" + in: "query" + description: "The name of the new tag." + type: "string" + tags: ["Image"] + /images/{name}: + delete: + summary: "Remove an image" + description: | + Remove an image, along with any untagged parent images that were + referenced by that image. + + Images can't be removed if they have descendant images, are being + used by a running container or are being used by a build. + operationId: "ImageDelete" + produces: ["application/json"] + responses: + 200: + description: "The image was deleted successfully" + schema: + type: "array" + items: + $ref: "#/definitions/ImageDeleteResponseItem" + examples: + application/json: + - Untagged: "3e2f21a89f" + - Deleted: "3e2f21a89f" + - Deleted: "53b4f83ac9" + 404: + description: "No such image" + schema: + $ref: "#/definitions/ErrorResponse" + 409: + description: "Conflict" + schema: + $ref: "#/definitions/ErrorResponse" + 500: + description: "Server error" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "name" + in: "path" + description: "Image name or ID" + type: "string" + required: true + - name: "force" + in: "query" + description: "Remove the image even if it is being used by stopped containers or has other tags" + type: "boolean" + default: false + - name: "noprune" + in: "query" + description: "Do not delete untagged parent images" + type: "boolean" + default: false + tags: ["Image"] + /images/search: + get: + summary: "Search images" + description: "Search for an image on Docker Hub." + operationId: "ImageSearch" + produces: + - "application/json" + responses: + 200: + description: "No error" + schema: + type: "array" + items: + type: "object" + title: "ImageSearchResponseItem" + properties: + description: + type: "string" + is_official: + type: "boolean" + is_automated: + type: "boolean" + name: + type: "string" + star_count: + type: "integer" + examples: + application/json: + - description: "" + is_official: false + is_automated: false + name: "wma55/u1210sshd" + star_count: 0 + - description: "" + is_official: false + is_automated: false + name: "jdswinbank/sshd" + star_count: 0 + - description: "" + is_official: false + is_automated: false + name: "vgauthier/sshd" + star_count: 0 + 500: + description: "Server error" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "term" + in: "query" + description: "Term to search" + type: "string" + required: true + - name: "limit" + in: "query" + description: "Maximum number of results to return" + type: "integer" + - name: "filters" + in: "query" + description: | + A JSON encoded value of the filters (a `map[string][]string`) to process on the images list. Available filters: + + - `is-automated=(true|false)` + - `is-official=(true|false)` + - `stars=` Matches images that has at least 'number' stars. + type: "string" + tags: ["Image"] + /images/prune: + post: + summary: "Delete unused images" + produces: + - "application/json" + operationId: "ImagePrune" + parameters: + - name: "filters" + in: "query" + description: | + Filters to process on the prune list, encoded as JSON (a `map[string][]string`). Available filters: + + - `dangling=` When set to `true` (or `1`), prune only + unused *and* untagged images. When set to `false` + (or `0`), all unused images are pruned. + - `until=` Prune images created before this timestamp. The `` can be Unix timestamps, date formatted timestamps, or Go duration strings (e.g. `10m`, `1h30m`) computed relative to the daemon machine’s time. + - `label` (`label=`, `label==`, `label!=`, or `label!==`) Prune images with (or without, in case `label!=...` is used) the specified labels. + type: "string" + responses: + 200: + description: "No error" + schema: + type: "object" + title: "ImagePruneResponse" + properties: + ImagesDeleted: + description: "Images that were deleted" + type: "array" + items: + $ref: "#/definitions/ImageDeleteResponseItem" + SpaceReclaimed: + description: "Disk space reclaimed in bytes" + type: "integer" + format: "int64" + 500: + description: "Server error" + schema: + $ref: "#/definitions/ErrorResponse" + tags: ["Image"] + /auth: + post: + summary: "Check auth configuration" + description: | + Validate credentials for a registry and, if available, get an identity + token for accessing the registry without password. + operationId: "SystemAuth" + consumes: ["application/json"] + produces: ["application/json"] + responses: + 200: + description: "An identity token was generated successfully." + schema: + type: "object" + title: "SystemAuthResponse" + required: [Status] + properties: + Status: + description: "The status of the authentication" + type: "string" + x-nullable: false + IdentityToken: + description: "An opaque token used to authenticate a user after a successful login" + type: "string" + x-nullable: false + examples: + application/json: + Status: "Login Succeeded" + IdentityToken: "9cbaf023786cd7..." + 204: + description: "No error" + 401: + description: "Auth error" + schema: + $ref: "#/definitions/ErrorResponse" + 500: + description: "Server error" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "authConfig" + in: "body" + description: "Authentication to check" + schema: + $ref: "#/definitions/AuthConfig" + tags: ["System"] + /info: + get: + summary: "Get system information" + operationId: "SystemInfo" + produces: + - "application/json" + responses: + 200: + description: "No error" + schema: + $ref: "#/definitions/SystemInfo" + 500: + description: "Server error" + schema: + $ref: "#/definitions/ErrorResponse" + tags: ["System"] + /version: + get: + summary: "Get version" + description: "Returns the version of Docker that is running and various information about the system that Docker is running on." + operationId: "SystemVersion" + produces: ["application/json"] + responses: + 200: + description: "no error" + schema: + $ref: "#/definitions/SystemVersion" + 500: + description: "server error" + schema: + $ref: "#/definitions/ErrorResponse" + tags: ["System"] + /_ping: + get: + summary: "Ping" + description: "This is a dummy endpoint you can use to test if the server is accessible." + operationId: "SystemPing" + produces: ["text/plain"] + responses: + 200: + description: "no error" + schema: + type: "string" + example: "OK" + headers: + API-Version: + type: "string" + description: "Max API Version the server supports" + Builder-Version: + type: "string" + description: | + Default version of docker image builder + + The default on Linux is version "2" (BuildKit), but the daemon + can be configured to recommend version "1" (classic Builder). + Windows does not yet support BuildKit for native Windows images, + and uses "1" (classic builder) as a default. + + This value is a recommendation as advertised by the daemon, and + it is up to the client to choose which builder to use. + default: "2" + Docker-Experimental: + type: "boolean" + description: "If the server is running with experimental mode enabled" + Swarm: + type: "string" + enum: ["inactive", "pending", "error", "locked", "active/worker", "active/manager"] + description: | + Contains information about Swarm status of the daemon, + and if the daemon is acting as a manager or worker node. + default: "inactive" + Cache-Control: + type: "string" + default: "no-cache, no-store, must-revalidate" + Pragma: + type: "string" + default: "no-cache" + 500: + description: "server error" + schema: + $ref: "#/definitions/ErrorResponse" + headers: + Cache-Control: + type: "string" + default: "no-cache, no-store, must-revalidate" + Pragma: + type: "string" + default: "no-cache" + tags: ["System"] + head: + summary: "Ping" + description: "This is a dummy endpoint you can use to test if the server is accessible." + operationId: "SystemPingHead" + produces: ["text/plain"] + responses: + 200: + description: "no error" + schema: + type: "string" + example: "(empty)" + headers: + API-Version: + type: "string" + description: "Max API Version the server supports" + Builder-Version: + type: "string" + description: "Default version of docker image builder" + Docker-Experimental: + type: "boolean" + description: "If the server is running with experimental mode enabled" + Swarm: + type: "string" + enum: ["inactive", "pending", "error", "locked", "active/worker", "active/manager"] + description: | + Contains information about Swarm status of the daemon, + and if the daemon is acting as a manager or worker node. + default: "inactive" + Cache-Control: + type: "string" + default: "no-cache, no-store, must-revalidate" + Pragma: + type: "string" + default: "no-cache" + 500: + description: "server error" + schema: + $ref: "#/definitions/ErrorResponse" + tags: ["System"] + /commit: + post: + summary: "Create a new image from a container" + operationId: "ImageCommit" + consumes: + - "application/json" + produces: + - "application/json" + responses: + 201: + description: "no error" + schema: + $ref: "#/definitions/IdResponse" + 404: + description: "no such container" + schema: + $ref: "#/definitions/ErrorResponse" + examples: + application/json: + message: "No such container: c2ada9df5af8" + 500: + description: "server error" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "containerConfig" + in: "body" + description: "The container configuration" + schema: + $ref: "#/definitions/ContainerConfig" + - name: "container" + in: "query" + description: "The ID or name of the container to commit" + type: "string" + - name: "repo" + in: "query" + description: "Repository name for the created image" + type: "string" + - name: "tag" + in: "query" + description: "Tag name for the create image" + type: "string" + - name: "comment" + in: "query" + description: "Commit message" + type: "string" + - name: "author" + in: "query" + description: "Author of the image (e.g., `John Hannibal Smith `)" + type: "string" + - name: "pause" + in: "query" + description: "Whether to pause the container before committing" + type: "boolean" + default: true + - name: "changes" + in: "query" + description: "`Dockerfile` instructions to apply while committing" + type: "string" + tags: ["Image"] + /events: + get: + summary: "Monitor events" + description: | + Stream real-time events from the server. + + Various objects within Docker report events when something happens to them. + + Containers report these events: `attach`, `commit`, `copy`, `create`, `destroy`, `detach`, `die`, `exec_create`, `exec_detach`, `exec_start`, `exec_die`, `export`, `health_status`, `kill`, `oom`, `pause`, `rename`, `resize`, `restart`, `start`, `stop`, `top`, `unpause`, `update`, and `prune` + + Images report these events: `delete`, `import`, `load`, `pull`, `push`, `save`, `tag`, `untag`, and `prune` + + Volumes report these events: `create`, `mount`, `unmount`, `destroy`, and `prune` + + Networks report these events: `create`, `connect`, `disconnect`, `destroy`, `update`, `remove`, and `prune` + + The Docker daemon reports these events: `reload` + + Services report these events: `create`, `update`, and `remove` + + Nodes report these events: `create`, `update`, and `remove` + + Secrets report these events: `create`, `update`, and `remove` + + Configs report these events: `create`, `update`, and `remove` + + The Builder reports `prune` events + + operationId: "SystemEvents" + produces: + - "application/json" + responses: + 200: + description: "no error" + schema: + $ref: "#/definitions/EventMessage" + 400: + description: "bad parameter" + schema: + $ref: "#/definitions/ErrorResponse" + 500: + description: "server error" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "since" + in: "query" + description: "Show events created since this timestamp then stream new events." + type: "string" + - name: "until" + in: "query" + description: "Show events created until this timestamp then stop streaming." + type: "string" + - name: "filters" + in: "query" + description: | + A JSON encoded value of filters (a `map[string][]string`) to process on the event list. Available filters: + + - `config=` config name or ID + - `container=` container name or ID + - `daemon=` daemon name or ID + - `event=` event type + - `image=` image name or ID + - `label=` image or container label + - `network=` network name or ID + - `node=` node ID + - `plugin`= plugin name or ID + - `scope`= local or swarm + - `secret=` secret name or ID + - `service=` service name or ID + - `type=` object to filter by, one of `container`, `image`, `volume`, `network`, `daemon`, `plugin`, `node`, `service`, `secret` or `config` + - `volume=` volume name + type: "string" + tags: ["System"] + /system/df: + get: + summary: "Get data usage information" + operationId: "SystemDataUsage" + responses: + 200: + description: "no error" + schema: + type: "object" + title: "SystemDataUsageResponse" + properties: + LayersSize: + type: "integer" + format: "int64" + Images: + type: "array" + items: + $ref: "#/definitions/ImageSummary" + Containers: + type: "array" + items: + $ref: "#/definitions/ContainerSummary" + Volumes: + type: "array" + items: + $ref: "#/definitions/Volume" + BuildCache: + type: "array" + items: + $ref: "#/definitions/BuildCache" + example: + LayersSize: 1092588 + Images: + - + Id: "sha256:2b8fd9751c4c0f5dd266fcae00707e67a2545ef34f9a29354585f93dac906749" + ParentId: "" + RepoTags: + - "busybox:latest" + RepoDigests: + - "busybox@sha256:a59906e33509d14c036c8678d687bd4eec81ed7c4b8ce907b888c607f6a1e0e6" + Created: 1466724217 + Size: 1092588 + SharedSize: 0 + VirtualSize: 1092588 + Labels: {} + Containers: 1 + Containers: + - + Id: "e575172ed11dc01bfce087fb27bee502db149e1a0fad7c296ad300bbff178148" + Names: + - "/top" + Image: "busybox" + ImageID: "sha256:2b8fd9751c4c0f5dd266fcae00707e67a2545ef34f9a29354585f93dac906749" + Command: "top" + Created: 1472592424 + Ports: [] + SizeRootFs: 1092588 + Labels: {} + State: "exited" + Status: "Exited (0) 56 minutes ago" + HostConfig: + NetworkMode: "default" + NetworkSettings: + Networks: + bridge: + IPAMConfig: null + Links: null + Aliases: null + NetworkID: "d687bc59335f0e5c9ee8193e5612e8aee000c8c62ea170cfb99c098f95899d92" + EndpointID: "8ed5115aeaad9abb174f68dcf135b49f11daf597678315231a32ca28441dec6a" + Gateway: "172.18.0.1" + IPAddress: "172.18.0.2" + IPPrefixLen: 16 + IPv6Gateway: "" + GlobalIPv6Address: "" + GlobalIPv6PrefixLen: 0 + MacAddress: "02:42:ac:12:00:02" + Mounts: [] + Volumes: + - + Name: "my-volume" + Driver: "local" + Mountpoint: "/var/lib/docker/volumes/my-volume/_data" + Labels: null + Scope: "local" + Options: null + UsageData: + Size: 10920104 + RefCount: 2 + BuildCache: + - + ID: "hw53o5aio51xtltp5xjp8v7fx" + Parents: [] + Type: "regular" + Description: "pulled from docker.io/library/debian@sha256:234cb88d3020898631af0ccbbcca9a66ae7306ecd30c9720690858c1b007d2a0" + InUse: false + Shared: true + Size: 0 + CreatedAt: "2021-06-28T13:31:01.474619385Z" + LastUsedAt: "2021-07-07T22:02:32.738075951Z" + UsageCount: 26 + - + ID: "ndlpt0hhvkqcdfkputsk4cq9c" + Parents: ["ndlpt0hhvkqcdfkputsk4cq9c"] + Type: "regular" + Description: "mount / from exec /bin/sh -c echo 'Binary::apt::APT::Keep-Downloaded-Packages \"true\";' > /etc/apt/apt.conf.d/keep-cache" + InUse: false + Shared: true + Size: 51 + CreatedAt: "2021-06-28T13:31:03.002625487Z" + LastUsedAt: "2021-07-07T22:02:32.773909517Z" + UsageCount: 26 + 500: + description: "server error" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "type" + in: "query" + description: | + Object types, for which to compute and return data. + type: "array" + collectionFormat: multi + items: + type: "string" + enum: ["container", "image", "volume", "build-cache"] + tags: ["System"] + /images/{name}/get: + get: + summary: "Export an image" + description: | + Get a tarball containing all images and metadata for a repository. + + If `name` is a specific name and tag (e.g. `ubuntu:latest`), then only that image (and its parents) are returned. If `name` is an image ID, similarly only that image (and its parents) are returned, but with the exclusion of the `repositories` file in the tarball, as there were no image names referenced. + + ### Image tarball format + + An image tarball contains one directory per image layer (named using its long ID), each containing these files: + + - `VERSION`: currently `1.0` - the file format version + - `json`: detailed layer information, similar to `docker inspect layer_id` + - `layer.tar`: A tarfile containing the filesystem changes in this layer + + The `layer.tar` file contains `aufs` style `.wh..wh.aufs` files and directories for storing attribute changes and deletions. + + If the tarball defines a repository, the tarball should also include a `repositories` file at the root that contains a list of repository and tag names mapped to layer IDs. + + ```json + { + "hello-world": { + "latest": "565a9d68a73f6706862bfe8409a7f659776d4d60a8d096eb4a3cbce6999cc2a1" + } + } + ``` + operationId: "ImageGet" + produces: + - "application/x-tar" + responses: + 200: + description: "no error" + schema: + type: "string" + format: "binary" + 500: + description: "server error" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "name" + in: "path" + description: "Image name or ID" + type: "string" + required: true + tags: ["Image"] + /images/get: + get: + summary: "Export several images" + description: | + Get a tarball containing all images and metadata for several image + repositories. + + For each value of the `names` parameter: if it is a specific name and + tag (e.g. `ubuntu:latest`), then only that image (and its parents) are + returned; if it is an image ID, similarly only that image (and its parents) + are returned and there would be no names referenced in the 'repositories' + file for this image ID. + + For details on the format, see the [export image endpoint](#operation/ImageGet). + operationId: "ImageGetAll" + produces: + - "application/x-tar" + responses: + 200: + description: "no error" + schema: + type: "string" + format: "binary" + 500: + description: "server error" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "names" + in: "query" + description: "Image names to filter by" + type: "array" + items: + type: "string" + tags: ["Image"] + /images/load: + post: + summary: "Import images" + description: | + Load a set of images and tags into a repository. + + For details on the format, see the [export image endpoint](#operation/ImageGet). + operationId: "ImageLoad" + consumes: + - "application/x-tar" + produces: + - "application/json" + responses: + 200: + description: "no error" + 500: + description: "server error" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "imagesTarball" + in: "body" + description: "Tar archive containing images" + schema: + type: "string" + format: "binary" + - name: "quiet" + in: "query" + description: "Suppress progress details during load." + type: "boolean" + default: false + tags: ["Image"] + /containers/{id}/exec: + post: + summary: "Create an exec instance" + description: "Run a command inside a running container." + operationId: "ContainerExec" + consumes: + - "application/json" + produces: + - "application/json" + responses: + 201: + description: "no error" + schema: + $ref: "#/definitions/IdResponse" + 404: + description: "no such container" + schema: + $ref: "#/definitions/ErrorResponse" + examples: + application/json: + message: "No such container: c2ada9df5af8" + 409: + description: "container is paused" + schema: + $ref: "#/definitions/ErrorResponse" + 500: + description: "Server error" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "execConfig" + in: "body" + description: "Exec configuration" + schema: + type: "object" + title: "ExecConfig" + properties: + AttachStdin: + type: "boolean" + description: "Attach to `stdin` of the exec command." + AttachStdout: + type: "boolean" + description: "Attach to `stdout` of the exec command." + AttachStderr: + type: "boolean" + description: "Attach to `stderr` of the exec command." + ConsoleSize: + type: "array" + description: "Initial console size, as an `[height, width]` array." + x-nullable: true + minItems: 2 + maxItems: 2 + items: + type: "integer" + minimum: 0 + DetachKeys: + type: "string" + description: | + Override the key sequence for detaching a container. Format is + a single character `[a-Z]` or `ctrl-` where `` + is one of: `a-z`, `@`, `^`, `[`, `,` or `_`. + Tty: + type: "boolean" + description: "Allocate a pseudo-TTY." + Env: + description: | + A list of environment variables in the form `["VAR=value", ...]`. + type: "array" + items: + type: "string" + Cmd: + type: "array" + description: "Command to run, as a string or array of strings." + items: + type: "string" + Privileged: + type: "boolean" + description: "Runs the exec process with extended privileges." + default: false + User: + type: "string" + description: | + The user, and optionally, group to run the exec process inside + the container. Format is one of: `user`, `user:group`, `uid`, + or `uid:gid`. + WorkingDir: + type: "string" + description: | + The working directory for the exec process inside the container. + example: + AttachStdin: false + AttachStdout: true + AttachStderr: true + DetachKeys: "ctrl-p,ctrl-q" + Tty: false + Cmd: + - "date" + Env: + - "FOO=bar" + - "BAZ=quux" + required: true + - name: "id" + in: "path" + description: "ID or name of container" + type: "string" + required: true + tags: ["Exec"] + /exec/{id}/start: + post: + summary: "Start an exec instance" + description: | + Starts a previously set up exec instance. If detach is true, this endpoint + returns immediately after starting the command. Otherwise, it sets up an + interactive session with the command. + operationId: "ExecStart" + consumes: + - "application/json" + produces: + - "application/vnd.docker.raw-stream" + - "application/vnd.docker.multiplexed-stream" + responses: + 200: + description: "No error" + 404: + description: "No such exec instance" + schema: + $ref: "#/definitions/ErrorResponse" + 409: + description: "Container is stopped or paused" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "execStartConfig" + in: "body" + schema: + type: "object" + title: "ExecStartConfig" + properties: + Detach: + type: "boolean" + description: "Detach from the command." + Tty: + type: "boolean" + description: "Allocate a pseudo-TTY." + ConsoleSize: + type: "array" + description: "Initial console size, as an `[height, width]` array." + x-nullable: true + minItems: 2 + maxItems: 2 + items: + type: "integer" + minimum: 0 + example: + Detach: false + Tty: true + ConsoleSize: [80, 64] + - name: "id" + in: "path" + description: "Exec instance ID" + required: true + type: "string" + tags: ["Exec"] + /exec/{id}/resize: + post: + summary: "Resize an exec instance" + description: | + Resize the TTY session used by an exec instance. This endpoint only works + if `tty` was specified as part of creating and starting the exec instance. + operationId: "ExecResize" + responses: + 200: + description: "No error" + 400: + description: "bad parameter" + schema: + $ref: "#/definitions/ErrorResponse" + 404: + description: "No such exec instance" + schema: + $ref: "#/definitions/ErrorResponse" + 500: + description: "Server error" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "id" + in: "path" + description: "Exec instance ID" + required: true + type: "string" + - name: "h" + in: "query" + description: "Height of the TTY session in characters" + type: "integer" + - name: "w" + in: "query" + description: "Width of the TTY session in characters" + type: "integer" + tags: ["Exec"] + /exec/{id}/json: + get: + summary: "Inspect an exec instance" + description: "Return low-level information about an exec instance." + operationId: "ExecInspect" + produces: + - "application/json" + responses: + 200: + description: "No error" + schema: + type: "object" + title: "ExecInspectResponse" + properties: + CanRemove: + type: "boolean" + DetachKeys: + type: "string" + ID: + type: "string" + Running: + type: "boolean" + ExitCode: + type: "integer" + ProcessConfig: + $ref: "#/definitions/ProcessConfig" + OpenStdin: + type: "boolean" + OpenStderr: + type: "boolean" + OpenStdout: + type: "boolean" + ContainerID: + type: "string" + Pid: + type: "integer" + description: "The system process ID for the exec process." + examples: + application/json: + CanRemove: false + ContainerID: "b53ee82b53a40c7dca428523e34f741f3abc51d9f297a14ff874bf761b995126" + DetachKeys: "" + ExitCode: 2 + ID: "f33bbfb39f5b142420f4759b2348913bd4a8d1a6d7fd56499cb41a1bb91d7b3b" + OpenStderr: true + OpenStdin: true + OpenStdout: true + ProcessConfig: + arguments: + - "-c" + - "exit 2" + entrypoint: "sh" + privileged: false + tty: true + user: "1000" + Running: false + Pid: 42000 + 404: + description: "No such exec instance" + schema: + $ref: "#/definitions/ErrorResponse" + 500: + description: "Server error" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "id" + in: "path" + description: "Exec instance ID" + required: true + type: "string" + tags: ["Exec"] + + /volumes: + get: + summary: "List volumes" + operationId: "VolumeList" + produces: ["application/json"] + responses: + 200: + description: "Summary volume data that matches the query" + schema: + $ref: "#/definitions/VolumeListResponse" + 500: + description: "Server error" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "filters" + in: "query" + description: | + JSON encoded value of the filters (a `map[string][]string`) to + process on the volumes list. Available filters: + + - `dangling=` When set to `true` (or `1`), returns all + volumes that are not in use by a container. When set to `false` + (or `0`), only volumes that are in use by one or more + containers are returned. + - `driver=` Matches volumes based on their driver. + - `label=` or `label=:` Matches volumes based on + the presence of a `label` alone or a `label` and a value. + - `name=` Matches all or part of a volume name. + type: "string" + format: "json" + tags: ["Volume"] + + /volumes/create: + post: + summary: "Create a volume" + operationId: "VolumeCreate" + consumes: ["application/json"] + produces: ["application/json"] + responses: + 201: + description: "The volume was created successfully" + schema: + $ref: "#/definitions/Volume" + 500: + description: "Server error" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "volumeConfig" + in: "body" + required: true + description: "Volume configuration" + schema: + $ref: "#/definitions/VolumeCreateOptions" + tags: ["Volume"] + + /volumes/{name}: + get: + summary: "Inspect a volume" + operationId: "VolumeInspect" + produces: ["application/json"] + responses: + 200: + description: "No error" + schema: + $ref: "#/definitions/Volume" + 404: + description: "No such volume" + schema: + $ref: "#/definitions/ErrorResponse" + 500: + description: "Server error" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "name" + in: "path" + required: true + description: "Volume name or ID" + type: "string" + tags: ["Volume"] + + put: + summary: | + "Update a volume. Valid only for Swarm cluster volumes" + operationId: "VolumeUpdate" + consumes: ["application/json"] + produces: ["application/json"] + responses: + 200: + description: "no error" + 400: + description: "bad parameter" + schema: + $ref: "#/definitions/ErrorResponse" + 404: + description: "no such volume" + schema: + $ref: "#/definitions/ErrorResponse" + 500: + description: "server error" + schema: + $ref: "#/definitions/ErrorResponse" + 503: + description: "node is not part of a swarm" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "name" + in: "path" + description: "The name or ID of the volume" + type: "string" + required: true + - name: "body" + in: "body" + schema: + # though the schema for is an object that contains only a + # ClusterVolumeSpec, wrapping the ClusterVolumeSpec in this object + # means that if, later on, we support things like changing the + # labels, we can do so without duplicating that information to the + # ClusterVolumeSpec. + type: "object" + description: "Volume configuration" + properties: + Spec: + $ref: "#/definitions/ClusterVolumeSpec" + description: | + The spec of the volume to update. Currently, only Availability may + change. All other fields must remain unchanged. + - name: "version" + in: "query" + description: | + The version number of the volume being updated. This is required to + avoid conflicting writes. Found in the volume's `ClusterVolume` + field. + type: "integer" + format: "int64" + required: true + tags: ["Volume"] + + delete: + summary: "Remove a volume" + description: "Instruct the driver to remove the volume." + operationId: "VolumeDelete" + responses: + 204: + description: "The volume was removed" + 404: + description: "No such volume or volume driver" + schema: + $ref: "#/definitions/ErrorResponse" + 409: + description: "Volume is in use and cannot be removed" + schema: + $ref: "#/definitions/ErrorResponse" + 500: + description: "Server error" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "name" + in: "path" + required: true + description: "Volume name or ID" + type: "string" + - name: "force" + in: "query" + description: "Force the removal of the volume" + type: "boolean" + default: false + tags: ["Volume"] + + /volumes/prune: + post: + summary: "Delete unused volumes" + produces: + - "application/json" + operationId: "VolumePrune" + parameters: + - name: "filters" + in: "query" + description: | + Filters to process on the prune list, encoded as JSON (a `map[string][]string`). + + Available filters: + - `label` (`label=`, `label==`, `label!=`, or `label!==`) Prune volumes with (or without, in case `label!=...` is used) the specified labels. + - `all` (`all=true`) - Consider all (local) volumes for pruning and not just anonymous volumes. + type: "string" + responses: + 200: + description: "No error" + schema: + type: "object" + title: "VolumePruneResponse" + properties: + VolumesDeleted: + description: "Volumes that were deleted" + type: "array" + items: + type: "string" + SpaceReclaimed: + description: "Disk space reclaimed in bytes" + type: "integer" + format: "int64" + 500: + description: "Server error" + schema: + $ref: "#/definitions/ErrorResponse" + tags: ["Volume"] + /networks: + get: + summary: "List networks" + description: | + Returns a list of networks. For details on the format, see the + [network inspect endpoint](#operation/NetworkInspect). + + Note that it uses a different, smaller representation of a network than + inspecting a single network. For example, the list of containers attached + to the network is not propagated in API versions 1.28 and up. + operationId: "NetworkList" + produces: + - "application/json" + responses: + 200: + description: "No error" + schema: + type: "array" + items: + $ref: "#/definitions/Network" + examples: + application/json: + - Name: "bridge" + Id: "f2de39df4171b0dc801e8002d1d999b77256983dfc63041c0f34030aa3977566" + Created: "2016-10-19T06:21:00.416543526Z" + Scope: "local" + Driver: "bridge" + EnableIPv6: false + Internal: false + Attachable: false + Ingress: false + IPAM: + Driver: "default" + Config: + - + Subnet: "172.17.0.0/16" + Options: + com.docker.network.bridge.default_bridge: "true" + com.docker.network.bridge.enable_icc: "true" + com.docker.network.bridge.enable_ip_masquerade: "true" + com.docker.network.bridge.host_binding_ipv4: "0.0.0.0" + com.docker.network.bridge.name: "docker0" + com.docker.network.driver.mtu: "1500" + - Name: "none" + Id: "e086a3893b05ab69242d3c44e49483a3bbbd3a26b46baa8f61ab797c1088d794" + Created: "0001-01-01T00:00:00Z" + Scope: "local" + Driver: "null" + EnableIPv6: false + Internal: false + Attachable: false + Ingress: false + IPAM: + Driver: "default" + Config: [] + Containers: {} + Options: {} + - Name: "host" + Id: "13e871235c677f196c4e1ecebb9dc733b9b2d2ab589e30c539efeda84a24215e" + Created: "0001-01-01T00:00:00Z" + Scope: "local" + Driver: "host" + EnableIPv6: false + Internal: false + Attachable: false + Ingress: false + IPAM: + Driver: "default" + Config: [] + Containers: {} + Options: {} + 500: + description: "Server error" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "filters" + in: "query" + description: | + JSON encoded value of the filters (a `map[string][]string`) to process + on the networks list. + + Available filters: + + - `dangling=` When set to `true` (or `1`), returns all + networks that are not in use by a container. When set to `false` + (or `0`), only networks that are in use by one or more + containers are returned. + - `driver=` Matches a network's driver. + - `id=` Matches all or part of a network ID. + - `label=` or `label==` of a network label. + - `name=` Matches all or part of a network name. + - `scope=["swarm"|"global"|"local"]` Filters networks by scope (`swarm`, `global`, or `local`). + - `type=["custom"|"builtin"]` Filters networks by type. The `custom` keyword returns all user-defined networks. + type: "string" + tags: ["Network"] + + /networks/{id}: + get: + summary: "Inspect a network" + operationId: "NetworkInspect" + produces: + - "application/json" + responses: + 200: + description: "No error" + schema: + $ref: "#/definitions/Network" + 404: + description: "Network not found" + schema: + $ref: "#/definitions/ErrorResponse" + 500: + description: "Server error" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "id" + in: "path" + description: "Network ID or name" + required: true + type: "string" + - name: "verbose" + in: "query" + description: "Detailed inspect output for troubleshooting" + type: "boolean" + default: false + - name: "scope" + in: "query" + description: "Filter the network by scope (swarm, global, or local)" + type: "string" + tags: ["Network"] + + delete: + summary: "Remove a network" + operationId: "NetworkDelete" + responses: + 204: + description: "No error" + 403: + description: "operation not supported for pre-defined networks" + schema: + $ref: "#/definitions/ErrorResponse" + 404: + description: "no such network" + schema: + $ref: "#/definitions/ErrorResponse" + 500: + description: "Server error" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "id" + in: "path" + description: "Network ID or name" + required: true + type: "string" + tags: ["Network"] + + /networks/create: + post: + summary: "Create a network" + operationId: "NetworkCreate" + consumes: + - "application/json" + produces: + - "application/json" + responses: + 201: + description: "No error" + schema: + type: "object" + title: "NetworkCreateResponse" + properties: + Id: + description: "The ID of the created network." + type: "string" + Warning: + type: "string" + example: + Id: "22be93d5babb089c5aab8dbc369042fad48ff791584ca2da2100db837a1c7c30" + Warning: "" + 403: + description: "operation not supported for pre-defined networks" + schema: + $ref: "#/definitions/ErrorResponse" + 404: + description: "plugin not found" + schema: + $ref: "#/definitions/ErrorResponse" + 500: + description: "Server error" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "networkConfig" + in: "body" + description: "Network configuration" + required: true + schema: + type: "object" + title: "NetworkCreateRequest" + required: ["Name"] + properties: + Name: + description: "The network's name." + type: "string" + CheckDuplicate: + description: | + Check for networks with duplicate names. Since Network is + primarily keyed based on a random ID and not on the name, and + network name is strictly a user-friendly alias to the network + which is uniquely identified using ID, there is no guaranteed + way to check for duplicates. CheckDuplicate is there to provide + a best effort checking of any networks which has the same name + but it is not guaranteed to catch all name collisions. + type: "boolean" + Driver: + description: "Name of the network driver plugin to use." + type: "string" + default: "bridge" + Internal: + description: "Restrict external access to the network." + type: "boolean" + Attachable: + description: | + Globally scoped network is manually attachable by regular + containers from workers in swarm mode. + type: "boolean" + Ingress: + description: | + Ingress network is the network which provides the routing-mesh + in swarm mode. + type: "boolean" + IPAM: + description: "Optional custom IP scheme for the network." + $ref: "#/definitions/IPAM" + EnableIPv6: + description: "Enable IPv6 on the network." + type: "boolean" + Options: + description: "Network specific options to be used by the drivers." + type: "object" + additionalProperties: + type: "string" + Labels: + description: "User-defined key/value metadata." + type: "object" + additionalProperties: + type: "string" + example: + Name: "isolated_nw" + CheckDuplicate: false + Driver: "bridge" + EnableIPv6: true + IPAM: + Driver: "default" + Config: + - Subnet: "172.20.0.0/16" + IPRange: "172.20.10.0/24" + Gateway: "172.20.10.11" + - Subnet: "2001:db8:abcd::/64" + Gateway: "2001:db8:abcd::1011" + Options: + foo: "bar" + Internal: true + Attachable: false + Ingress: false + Options: + com.docker.network.bridge.default_bridge: "true" + com.docker.network.bridge.enable_icc: "true" + com.docker.network.bridge.enable_ip_masquerade: "true" + com.docker.network.bridge.host_binding_ipv4: "0.0.0.0" + com.docker.network.bridge.name: "docker0" + com.docker.network.driver.mtu: "1500" + Labels: + com.example.some-label: "some-value" + com.example.some-other-label: "some-other-value" + tags: ["Network"] + + /networks/{id}/connect: + post: + summary: "Connect a container to a network" + operationId: "NetworkConnect" + consumes: + - "application/json" + responses: + 200: + description: "No error" + 403: + description: "Operation not supported for swarm scoped networks" + schema: + $ref: "#/definitions/ErrorResponse" + 404: + description: "Network or container not found" + schema: + $ref: "#/definitions/ErrorResponse" + 500: + description: "Server error" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "id" + in: "path" + description: "Network ID or name" + required: true + type: "string" + - name: "container" + in: "body" + required: true + schema: + type: "object" + title: "NetworkConnectRequest" + properties: + Container: + type: "string" + description: "The ID or name of the container to connect to the network." + EndpointConfig: + $ref: "#/definitions/EndpointSettings" + example: + Container: "3613f73ba0e4" + EndpointConfig: + IPAMConfig: + IPv4Address: "172.24.56.89" + IPv6Address: "2001:db8::5689" + tags: ["Network"] + + /networks/{id}/disconnect: + post: + summary: "Disconnect a container from a network" + operationId: "NetworkDisconnect" + consumes: + - "application/json" + responses: + 200: + description: "No error" + 403: + description: "Operation not supported for swarm scoped networks" + schema: + $ref: "#/definitions/ErrorResponse" + 404: + description: "Network or container not found" + schema: + $ref: "#/definitions/ErrorResponse" + 500: + description: "Server error" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "id" + in: "path" + description: "Network ID or name" + required: true + type: "string" + - name: "container" + in: "body" + required: true + schema: + type: "object" + title: "NetworkDisconnectRequest" + properties: + Container: + type: "string" + description: | + The ID or name of the container to disconnect from the network. + Force: + type: "boolean" + description: | + Force the container to disconnect from the network. + tags: ["Network"] + /networks/prune: + post: + summary: "Delete unused networks" + produces: + - "application/json" + operationId: "NetworkPrune" + parameters: + - name: "filters" + in: "query" + description: | + Filters to process on the prune list, encoded as JSON (a `map[string][]string`). + + Available filters: + - `until=` Prune networks created before this timestamp. The `` can be Unix timestamps, date formatted timestamps, or Go duration strings (e.g. `10m`, `1h30m`) computed relative to the daemon machine’s time. + - `label` (`label=`, `label==`, `label!=`, or `label!==`) Prune networks with (or without, in case `label!=...` is used) the specified labels. + type: "string" + responses: + 200: + description: "No error" + schema: + type: "object" + title: "NetworkPruneResponse" + properties: + NetworksDeleted: + description: "Networks that were deleted" + type: "array" + items: + type: "string" + 500: + description: "Server error" + schema: + $ref: "#/definitions/ErrorResponse" + tags: ["Network"] + /plugins: + get: + summary: "List plugins" + operationId: "PluginList" + description: "Returns information about installed plugins." + produces: ["application/json"] + responses: + 200: + description: "No error" + schema: + type: "array" + items: + $ref: "#/definitions/Plugin" + 500: + description: "Server error" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "filters" + in: "query" + type: "string" + description: | + A JSON encoded value of the filters (a `map[string][]string`) to + process on the plugin list. + + Available filters: + + - `capability=` + - `enable=|` + tags: ["Plugin"] + + /plugins/privileges: + get: + summary: "Get plugin privileges" + operationId: "GetPluginPrivileges" + responses: + 200: + description: "no error" + schema: + type: "array" + items: + $ref: "#/definitions/PluginPrivilege" + example: + - Name: "network" + Description: "" + Value: + - "host" + - Name: "mount" + Description: "" + Value: + - "/data" + - Name: "device" + Description: "" + Value: + - "/dev/cpu_dma_latency" + 500: + description: "server error" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "remote" + in: "query" + description: | + The name of the plugin. The `:latest` tag is optional, and is the + default if omitted. + required: true + type: "string" + tags: + - "Plugin" + + /plugins/pull: + post: + summary: "Install a plugin" + operationId: "PluginPull" + description: | + Pulls and installs a plugin. After the plugin is installed, it can be + enabled using the [`POST /plugins/{name}/enable` endpoint](#operation/PostPluginsEnable). + produces: + - "application/json" + responses: + 204: + description: "no error" + 500: + description: "server error" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "remote" + in: "query" + description: | + Remote reference for plugin to install. + + The `:latest` tag is optional, and is used as the default if omitted. + required: true + type: "string" + - name: "name" + in: "query" + description: | + Local name for the pulled plugin. + + The `:latest` tag is optional, and is used as the default if omitted. + required: false + type: "string" + - name: "X-Registry-Auth" + in: "header" + description: | + A base64url-encoded auth configuration to use when pulling a plugin + from a registry. + + Refer to the [authentication section](#section/Authentication) for + details. + type: "string" + - name: "body" + in: "body" + schema: + type: "array" + items: + $ref: "#/definitions/PluginPrivilege" + example: + - Name: "network" + Description: "" + Value: + - "host" + - Name: "mount" + Description: "" + Value: + - "/data" + - Name: "device" + Description: "" + Value: + - "/dev/cpu_dma_latency" + tags: ["Plugin"] + /plugins/{name}/json: + get: + summary: "Inspect a plugin" + operationId: "PluginInspect" + responses: + 200: + description: "no error" + schema: + $ref: "#/definitions/Plugin" + 404: + description: "plugin is not installed" + schema: + $ref: "#/definitions/ErrorResponse" + 500: + description: "server error" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "name" + in: "path" + description: | + The name of the plugin. The `:latest` tag is optional, and is the + default if omitted. + required: true + type: "string" + tags: ["Plugin"] + /plugins/{name}: + delete: + summary: "Remove a plugin" + operationId: "PluginDelete" + responses: + 200: + description: "no error" + schema: + $ref: "#/definitions/Plugin" + 404: + description: "plugin is not installed" + schema: + $ref: "#/definitions/ErrorResponse" + 500: + description: "server error" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "name" + in: "path" + description: | + The name of the plugin. The `:latest` tag is optional, and is the + default if omitted. + required: true + type: "string" + - name: "force" + in: "query" + description: | + Disable the plugin before removing. This may result in issues if the + plugin is in use by a container. + type: "boolean" + default: false + tags: ["Plugin"] + /plugins/{name}/enable: + post: + summary: "Enable a plugin" + operationId: "PluginEnable" + responses: + 200: + description: "no error" + 404: + description: "plugin is not installed" + schema: + $ref: "#/definitions/ErrorResponse" + 500: + description: "server error" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "name" + in: "path" + description: | + The name of the plugin. The `:latest` tag is optional, and is the + default if omitted. + required: true + type: "string" + - name: "timeout" + in: "query" + description: "Set the HTTP client timeout (in seconds)" + type: "integer" + default: 0 + tags: ["Plugin"] + /plugins/{name}/disable: + post: + summary: "Disable a plugin" + operationId: "PluginDisable" + responses: + 200: + description: "no error" + 404: + description: "plugin is not installed" + schema: + $ref: "#/definitions/ErrorResponse" + 500: + description: "server error" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "name" + in: "path" + description: | + The name of the plugin. The `:latest` tag is optional, and is the + default if omitted. + required: true + type: "string" + tags: ["Plugin"] + /plugins/{name}/upgrade: + post: + summary: "Upgrade a plugin" + operationId: "PluginUpgrade" + responses: + 204: + description: "no error" + 404: + description: "plugin not installed" + schema: + $ref: "#/definitions/ErrorResponse" + 500: + description: "server error" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "name" + in: "path" + description: | + The name of the plugin. The `:latest` tag is optional, and is the + default if omitted. + required: true + type: "string" + - name: "remote" + in: "query" + description: | + Remote reference to upgrade to. + + The `:latest` tag is optional, and is used as the default if omitted. + required: true + type: "string" + - name: "X-Registry-Auth" + in: "header" + description: | + A base64url-encoded auth configuration to use when pulling a plugin + from a registry. + + Refer to the [authentication section](#section/Authentication) for + details. + type: "string" + - name: "body" + in: "body" + schema: + type: "array" + items: + $ref: "#/definitions/PluginPrivilege" + example: + - Name: "network" + Description: "" + Value: + - "host" + - Name: "mount" + Description: "" + Value: + - "/data" + - Name: "device" + Description: "" + Value: + - "/dev/cpu_dma_latency" + tags: ["Plugin"] + /plugins/create: + post: + summary: "Create a plugin" + operationId: "PluginCreate" + consumes: + - "application/x-tar" + responses: + 204: + description: "no error" + 500: + description: "server error" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "name" + in: "query" + description: | + The name of the plugin. The `:latest` tag is optional, and is the + default if omitted. + required: true + type: "string" + - name: "tarContext" + in: "body" + description: "Path to tar containing plugin rootfs and manifest" + schema: + type: "string" + format: "binary" + tags: ["Plugin"] + /plugins/{name}/push: + post: + summary: "Push a plugin" + operationId: "PluginPush" + description: | + Push a plugin to the registry. + parameters: + - name: "name" + in: "path" + description: | + The name of the plugin. The `:latest` tag is optional, and is the + default if omitted. + required: true + type: "string" + responses: + 200: + description: "no error" + 404: + description: "plugin not installed" + schema: + $ref: "#/definitions/ErrorResponse" + 500: + description: "server error" + schema: + $ref: "#/definitions/ErrorResponse" + tags: ["Plugin"] + /plugins/{name}/set: + post: + summary: "Configure a plugin" + operationId: "PluginSet" + consumes: + - "application/json" + parameters: + - name: "name" + in: "path" + description: | + The name of the plugin. The `:latest` tag is optional, and is the + default if omitted. + required: true + type: "string" + - name: "body" + in: "body" + schema: + type: "array" + items: + type: "string" + example: ["DEBUG=1"] + responses: + 204: + description: "No error" + 404: + description: "Plugin not installed" + schema: + $ref: "#/definitions/ErrorResponse" + 500: + description: "Server error" + schema: + $ref: "#/definitions/ErrorResponse" + tags: ["Plugin"] + /nodes: + get: + summary: "List nodes" + operationId: "NodeList" + responses: + 200: + description: "no error" + schema: + type: "array" + items: + $ref: "#/definitions/Node" + 500: + description: "server error" + schema: + $ref: "#/definitions/ErrorResponse" + 503: + description: "node is not part of a swarm" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "filters" + in: "query" + description: | + Filters to process on the nodes list, encoded as JSON (a `map[string][]string`). + + Available filters: + - `id=` + - `label=` + - `membership=`(`accepted`|`pending`)` + - `name=` + - `node.label=` + - `role=`(`manager`|`worker`)` + type: "string" + tags: ["Node"] + /nodes/{id}: + get: + summary: "Inspect a node" + operationId: "NodeInspect" + responses: + 200: + description: "no error" + schema: + $ref: "#/definitions/Node" + 404: + description: "no such node" + schema: + $ref: "#/definitions/ErrorResponse" + 500: + description: "server error" + schema: + $ref: "#/definitions/ErrorResponse" + 503: + description: "node is not part of a swarm" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "id" + in: "path" + description: "The ID or name of the node" + type: "string" + required: true + tags: ["Node"] + delete: + summary: "Delete a node" + operationId: "NodeDelete" + responses: + 200: + description: "no error" + 404: + description: "no such node" + schema: + $ref: "#/definitions/ErrorResponse" + 500: + description: "server error" + schema: + $ref: "#/definitions/ErrorResponse" + 503: + description: "node is not part of a swarm" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "id" + in: "path" + description: "The ID or name of the node" + type: "string" + required: true + - name: "force" + in: "query" + description: "Force remove a node from the swarm" + default: false + type: "boolean" + tags: ["Node"] + /nodes/{id}/update: + post: + summary: "Update a node" + operationId: "NodeUpdate" + responses: + 200: + description: "no error" + 400: + description: "bad parameter" + schema: + $ref: "#/definitions/ErrorResponse" + 404: + description: "no such node" + schema: + $ref: "#/definitions/ErrorResponse" + 500: + description: "server error" + schema: + $ref: "#/definitions/ErrorResponse" + 503: + description: "node is not part of a swarm" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "id" + in: "path" + description: "The ID of the node" + type: "string" + required: true + - name: "body" + in: "body" + schema: + $ref: "#/definitions/NodeSpec" + - name: "version" + in: "query" + description: | + The version number of the node object being updated. This is required + to avoid conflicting writes. + type: "integer" + format: "int64" + required: true + tags: ["Node"] + /swarm: + get: + summary: "Inspect swarm" + operationId: "SwarmInspect" + responses: + 200: + description: "no error" + schema: + $ref: "#/definitions/Swarm" + 404: + description: "no such swarm" + schema: + $ref: "#/definitions/ErrorResponse" + 500: + description: "server error" + schema: + $ref: "#/definitions/ErrorResponse" + 503: + description: "node is not part of a swarm" + schema: + $ref: "#/definitions/ErrorResponse" + tags: ["Swarm"] + /swarm/init: + post: + summary: "Initialize a new swarm" + operationId: "SwarmInit" + produces: + - "application/json" + - "text/plain" + responses: + 200: + description: "no error" + schema: + description: "The node ID" + type: "string" + example: "7v2t30z9blmxuhnyo6s4cpenp" + 400: + description: "bad parameter" + schema: + $ref: "#/definitions/ErrorResponse" + 500: + description: "server error" + schema: + $ref: "#/definitions/ErrorResponse" + 503: + description: "node is already part of a swarm" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "body" + in: "body" + required: true + schema: + type: "object" + title: "SwarmInitRequest" + properties: + ListenAddr: + description: | + Listen address used for inter-manager communication, as well + as determining the networking interface used for the VXLAN + Tunnel Endpoint (VTEP). This can either be an address/port + combination in the form `192.168.1.1:4567`, or an interface + followed by a port number, like `eth0:4567`. If the port number + is omitted, the default swarm listening port is used. + type: "string" + AdvertiseAddr: + description: | + Externally reachable address advertised to other nodes. This + can either be an address/port combination in the form + `192.168.1.1:4567`, or an interface followed by a port number, + like `eth0:4567`. If the port number is omitted, the port + number from the listen address is used. If `AdvertiseAddr` is + not specified, it will be automatically detected when possible. + type: "string" + DataPathAddr: + description: | + Address or interface to use for data path traffic (format: + ``), for example, `192.168.1.1`, or an interface, + like `eth0`. If `DataPathAddr` is unspecified, the same address + as `AdvertiseAddr` is used. + + The `DataPathAddr` specifies the address that global scope + network drivers will publish towards other nodes in order to + reach the containers running on this node. Using this parameter + it is possible to separate the container data traffic from the + management traffic of the cluster. + type: "string" + DataPathPort: + description: | + DataPathPort specifies the data path port number for data traffic. + Acceptable port range is 1024 to 49151. + if no port is set or is set to 0, default port 4789 will be used. + type: "integer" + format: "uint32" + DefaultAddrPool: + description: | + Default Address Pool specifies default subnet pools for global + scope networks. + type: "array" + items: + type: "string" + example: ["10.10.0.0/16", "20.20.0.0/16"] + ForceNewCluster: + description: "Force creation of a new swarm." + type: "boolean" + SubnetSize: + description: | + SubnetSize specifies the subnet size of the networks created + from the default subnet pool. + type: "integer" + format: "uint32" + Spec: + $ref: "#/definitions/SwarmSpec" + example: + ListenAddr: "0.0.0.0:2377" + AdvertiseAddr: "192.168.1.1:2377" + DataPathPort: 4789 + DefaultAddrPool: ["10.10.0.0/8", "20.20.0.0/8"] + SubnetSize: 24 + ForceNewCluster: false + Spec: + Orchestration: {} + Raft: {} + Dispatcher: {} + CAConfig: {} + EncryptionConfig: + AutoLockManagers: false + tags: ["Swarm"] + /swarm/join: + post: + summary: "Join an existing swarm" + operationId: "SwarmJoin" + responses: + 200: + description: "no error" + 400: + description: "bad parameter" + schema: + $ref: "#/definitions/ErrorResponse" + 500: + description: "server error" + schema: + $ref: "#/definitions/ErrorResponse" + 503: + description: "node is already part of a swarm" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "body" + in: "body" + required: true + schema: + type: "object" + title: "SwarmJoinRequest" + properties: + ListenAddr: + description: | + Listen address used for inter-manager communication if the node + gets promoted to manager, as well as determining the networking + interface used for the VXLAN Tunnel Endpoint (VTEP). + type: "string" + AdvertiseAddr: + description: | + Externally reachable address advertised to other nodes. This + can either be an address/port combination in the form + `192.168.1.1:4567`, or an interface followed by a port number, + like `eth0:4567`. If the port number is omitted, the port + number from the listen address is used. If `AdvertiseAddr` is + not specified, it will be automatically detected when possible. + type: "string" + DataPathAddr: + description: | + Address or interface to use for data path traffic (format: + ``), for example, `192.168.1.1`, or an interface, + like `eth0`. If `DataPathAddr` is unspecified, the same address + as `AdvertiseAddr` is used. + + The `DataPathAddr` specifies the address that global scope + network drivers will publish towards other nodes in order to + reach the containers running on this node. Using this parameter + it is possible to separate the container data traffic from the + management traffic of the cluster. + + type: "string" + RemoteAddrs: + description: | + Addresses of manager nodes already participating in the swarm. + type: "array" + items: + type: "string" + JoinToken: + description: "Secret token for joining this swarm." + type: "string" + example: + ListenAddr: "0.0.0.0:2377" + AdvertiseAddr: "192.168.1.1:2377" + RemoteAddrs: + - "node1:2377" + JoinToken: "SWMTKN-1-3pu6hszjas19xyp7ghgosyx9k8atbfcr8p2is99znpy26u2lkl-7p73s1dx5in4tatdymyhg9hu2" + tags: ["Swarm"] + /swarm/leave: + post: + summary: "Leave a swarm" + operationId: "SwarmLeave" + responses: + 200: + description: "no error" + 500: + description: "server error" + schema: + $ref: "#/definitions/ErrorResponse" + 503: + description: "node is not part of a swarm" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "force" + description: | + Force leave swarm, even if this is the last manager or that it will + break the cluster. + in: "query" + type: "boolean" + default: false + tags: ["Swarm"] + /swarm/update: + post: + summary: "Update a swarm" + operationId: "SwarmUpdate" + responses: + 200: + description: "no error" + 400: + description: "bad parameter" + schema: + $ref: "#/definitions/ErrorResponse" + 500: + description: "server error" + schema: + $ref: "#/definitions/ErrorResponse" + 503: + description: "node is not part of a swarm" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "body" + in: "body" + required: true + schema: + $ref: "#/definitions/SwarmSpec" + - name: "version" + in: "query" + description: | + The version number of the swarm object being updated. This is + required to avoid conflicting writes. + type: "integer" + format: "int64" + required: true + - name: "rotateWorkerToken" + in: "query" + description: "Rotate the worker join token." + type: "boolean" + default: false + - name: "rotateManagerToken" + in: "query" + description: "Rotate the manager join token." + type: "boolean" + default: false + - name: "rotateManagerUnlockKey" + in: "query" + description: "Rotate the manager unlock key." + type: "boolean" + default: false + tags: ["Swarm"] + /swarm/unlockkey: + get: + summary: "Get the unlock key" + operationId: "SwarmUnlockkey" + consumes: + - "application/json" + responses: + 200: + description: "no error" + schema: + type: "object" + title: "UnlockKeyResponse" + properties: + UnlockKey: + description: "The swarm's unlock key." + type: "string" + example: + UnlockKey: "SWMKEY-1-7c37Cc8654o6p38HnroywCi19pllOnGtbdZEgtKxZu8" + 500: + description: "server error" + schema: + $ref: "#/definitions/ErrorResponse" + 503: + description: "node is not part of a swarm" + schema: + $ref: "#/definitions/ErrorResponse" + tags: ["Swarm"] + /swarm/unlock: + post: + summary: "Unlock a locked manager" + operationId: "SwarmUnlock" + consumes: + - "application/json" + produces: + - "application/json" + parameters: + - name: "body" + in: "body" + required: true + schema: + type: "object" + title: "SwarmUnlockRequest" + properties: + UnlockKey: + description: "The swarm's unlock key." + type: "string" + example: + UnlockKey: "SWMKEY-1-7c37Cc8654o6p38HnroywCi19pllOnGtbdZEgtKxZu8" + responses: + 200: + description: "no error" + 500: + description: "server error" + schema: + $ref: "#/definitions/ErrorResponse" + 503: + description: "node is not part of a swarm" + schema: + $ref: "#/definitions/ErrorResponse" + tags: ["Swarm"] + /services: + get: + summary: "List services" + operationId: "ServiceList" + responses: + 200: + description: "no error" + schema: + type: "array" + items: + $ref: "#/definitions/Service" + 500: + description: "server error" + schema: + $ref: "#/definitions/ErrorResponse" + 503: + description: "node is not part of a swarm" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "filters" + in: "query" + type: "string" + description: | + A JSON encoded value of the filters (a `map[string][]string`) to + process on the services list. + + Available filters: + + - `id=` + - `label=` + - `mode=["replicated"|"global"]` + - `name=` + - name: "status" + in: "query" + type: "boolean" + description: | + Include service status, with count of running and desired tasks. + tags: ["Service"] + /services/create: + post: + summary: "Create a service" + operationId: "ServiceCreate" + consumes: + - "application/json" + produces: + - "application/json" + responses: + 201: + description: "no error" + schema: + type: "object" + title: "ServiceCreateResponse" + properties: + ID: + description: "The ID of the created service." + type: "string" + Warning: + description: "Optional warning message" + type: "string" + example: + ID: "ak7w3gjqoa3kuz8xcpnyy0pvl" + Warning: "unable to pin image doesnotexist:latest to digest: image library/doesnotexist:latest not found" + 400: + description: "bad parameter" + schema: + $ref: "#/definitions/ErrorResponse" + 403: + description: "network is not eligible for services" + schema: + $ref: "#/definitions/ErrorResponse" + 409: + description: "name conflicts with an existing service" + schema: + $ref: "#/definitions/ErrorResponse" + 500: + description: "server error" + schema: + $ref: "#/definitions/ErrorResponse" + 503: + description: "node is not part of a swarm" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "body" + in: "body" + required: true + schema: + allOf: + - $ref: "#/definitions/ServiceSpec" + - type: "object" + example: + Name: "web" + TaskTemplate: + ContainerSpec: + Image: "nginx:alpine" + Mounts: + - + ReadOnly: true + Source: "web-data" + Target: "/usr/share/nginx/html" + Type: "volume" + VolumeOptions: + DriverConfig: {} + Labels: + com.example.something: "something-value" + Hosts: ["10.10.10.10 host1", "ABCD:EF01:2345:6789:ABCD:EF01:2345:6789 host2"] + User: "33" + DNSConfig: + Nameservers: ["8.8.8.8"] + Search: ["example.org"] + Options: ["timeout:3"] + Secrets: + - + File: + Name: "www.example.org.key" + UID: "33" + GID: "33" + Mode: 384 + SecretID: "fpjqlhnwb19zds35k8wn80lq9" + SecretName: "example_org_domain_key" + LogDriver: + Name: "json-file" + Options: + max-file: "3" + max-size: "10M" + Placement: {} + Resources: + Limits: + MemoryBytes: 104857600 + Reservations: {} + RestartPolicy: + Condition: "on-failure" + Delay: 10000000000 + MaxAttempts: 10 + Mode: + Replicated: + Replicas: 4 + UpdateConfig: + Parallelism: 2 + Delay: 1000000000 + FailureAction: "pause" + Monitor: 15000000000 + MaxFailureRatio: 0.15 + RollbackConfig: + Parallelism: 1 + Delay: 1000000000 + FailureAction: "pause" + Monitor: 15000000000 + MaxFailureRatio: 0.15 + EndpointSpec: + Ports: + - + Protocol: "tcp" + PublishedPort: 8080 + TargetPort: 80 + Labels: + foo: "bar" + - name: "X-Registry-Auth" + in: "header" + description: | + A base64url-encoded auth configuration for pulling from private + registries. + + Refer to the [authentication section](#section/Authentication) for + details. + type: "string" + tags: ["Service"] + /services/{id}: + get: + summary: "Inspect a service" + operationId: "ServiceInspect" + responses: + 200: + description: "no error" + schema: + $ref: "#/definitions/Service" + 404: + description: "no such service" + schema: + $ref: "#/definitions/ErrorResponse" + 500: + description: "server error" + schema: + $ref: "#/definitions/ErrorResponse" + 503: + description: "node is not part of a swarm" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "id" + in: "path" + description: "ID or name of service." + required: true + type: "string" + - name: "insertDefaults" + in: "query" + description: "Fill empty fields with default values." + type: "boolean" + default: false + tags: ["Service"] + delete: + summary: "Delete a service" + operationId: "ServiceDelete" + responses: + 200: + description: "no error" + 404: + description: "no such service" + schema: + $ref: "#/definitions/ErrorResponse" + 500: + description: "server error" + schema: + $ref: "#/definitions/ErrorResponse" + 503: + description: "node is not part of a swarm" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "id" + in: "path" + description: "ID or name of service." + required: true + type: "string" + tags: ["Service"] + /services/{id}/update: + post: + summary: "Update a service" + operationId: "ServiceUpdate" + consumes: ["application/json"] + produces: ["application/json"] + responses: + 200: + description: "no error" + schema: + $ref: "#/definitions/ServiceUpdateResponse" + 400: + description: "bad parameter" + schema: + $ref: "#/definitions/ErrorResponse" + 404: + description: "no such service" + schema: + $ref: "#/definitions/ErrorResponse" + 500: + description: "server error" + schema: + $ref: "#/definitions/ErrorResponse" + 503: + description: "node is not part of a swarm" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "id" + in: "path" + description: "ID or name of service." + required: true + type: "string" + - name: "body" + in: "body" + required: true + schema: + allOf: + - $ref: "#/definitions/ServiceSpec" + - type: "object" + example: + Name: "top" + TaskTemplate: + ContainerSpec: + Image: "busybox" + Args: + - "top" + Resources: + Limits: {} + Reservations: {} + RestartPolicy: + Condition: "any" + MaxAttempts: 0 + Placement: {} + ForceUpdate: 0 + Mode: + Replicated: + Replicas: 1 + UpdateConfig: + Parallelism: 2 + Delay: 1000000000 + FailureAction: "pause" + Monitor: 15000000000 + MaxFailureRatio: 0.15 + RollbackConfig: + Parallelism: 1 + Delay: 1000000000 + FailureAction: "pause" + Monitor: 15000000000 + MaxFailureRatio: 0.15 + EndpointSpec: + Mode: "vip" + + - name: "version" + in: "query" + description: | + The version number of the service object being updated. This is + required to avoid conflicting writes. + This version number should be the value as currently set on the + service *before* the update. You can find the current version by + calling `GET /services/{id}` + required: true + type: "integer" + - name: "registryAuthFrom" + in: "query" + description: | + If the `X-Registry-Auth` header is not specified, this parameter + indicates where to find registry authorization credentials. + type: "string" + enum: ["spec", "previous-spec"] + default: "spec" + - name: "rollback" + in: "query" + description: | + Set to this parameter to `previous` to cause a server-side rollback + to the previous service spec. The supplied spec will be ignored in + this case. + type: "string" + - name: "X-Registry-Auth" + in: "header" + description: | + A base64url-encoded auth configuration for pulling from private + registries. + + Refer to the [authentication section](#section/Authentication) for + details. + type: "string" + + tags: ["Service"] + /services/{id}/logs: + get: + summary: "Get service logs" + description: | + Get `stdout` and `stderr` logs from a service. See also + [`/containers/{id}/logs`](#operation/ContainerLogs). + + **Note**: This endpoint works only for services with the `local`, + `json-file` or `journald` logging drivers. + produces: + - "application/vnd.docker.raw-stream" + - "application/vnd.docker.multiplexed-stream" + operationId: "ServiceLogs" + responses: + 200: + description: "logs returned as a stream in response body" + schema: + type: "string" + format: "binary" + 404: + description: "no such service" + schema: + $ref: "#/definitions/ErrorResponse" + examples: + application/json: + message: "No such service: c2ada9df5af8" + 500: + description: "server error" + schema: + $ref: "#/definitions/ErrorResponse" + 503: + description: "node is not part of a swarm" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "id" + in: "path" + required: true + description: "ID or name of the service" + type: "string" + - name: "details" + in: "query" + description: "Show service context and extra details provided to logs." + type: "boolean" + default: false + - name: "follow" + in: "query" + description: "Keep connection after returning logs." + type: "boolean" + default: false + - name: "stdout" + in: "query" + description: "Return logs from `stdout`" + type: "boolean" + default: false + - name: "stderr" + in: "query" + description: "Return logs from `stderr`" + type: "boolean" + default: false + - name: "since" + in: "query" + description: "Only return logs since this time, as a UNIX timestamp" + type: "integer" + default: 0 + - name: "timestamps" + in: "query" + description: "Add timestamps to every log line" + type: "boolean" + default: false + - name: "tail" + in: "query" + description: | + Only return this number of log lines from the end of the logs. + Specify as an integer or `all` to output all log lines. + type: "string" + default: "all" + tags: ["Service"] + /tasks: + get: + summary: "List tasks" + operationId: "TaskList" + produces: + - "application/json" + responses: + 200: + description: "no error" + schema: + type: "array" + items: + $ref: "#/definitions/Task" + example: + - ID: "0kzzo1i0y4jz6027t0k7aezc7" + Version: + Index: 71 + CreatedAt: "2016-06-07T21:07:31.171892745Z" + UpdatedAt: "2016-06-07T21:07:31.376370513Z" + Spec: + ContainerSpec: + Image: "redis" + Resources: + Limits: {} + Reservations: {} + RestartPolicy: + Condition: "any" + MaxAttempts: 0 + Placement: {} + ServiceID: "9mnpnzenvg8p8tdbtq4wvbkcz" + Slot: 1 + NodeID: "60gvrl6tm78dmak4yl7srz94v" + Status: + Timestamp: "2016-06-07T21:07:31.290032978Z" + State: "running" + Message: "started" + ContainerStatus: + ContainerID: "e5d62702a1b48d01c3e02ca1e0212a250801fa8d67caca0b6f35919ebc12f035" + PID: 677 + DesiredState: "running" + NetworksAttachments: + - Network: + ID: "4qvuz4ko70xaltuqbt8956gd1" + Version: + Index: 18 + CreatedAt: "2016-06-07T20:31:11.912919752Z" + UpdatedAt: "2016-06-07T21:07:29.955277358Z" + Spec: + Name: "ingress" + Labels: + com.docker.swarm.internal: "true" + DriverConfiguration: {} + IPAMOptions: + Driver: {} + Configs: + - Subnet: "10.255.0.0/16" + Gateway: "10.255.0.1" + DriverState: + Name: "overlay" + Options: + com.docker.network.driver.overlay.vxlanid_list: "256" + IPAMOptions: + Driver: + Name: "default" + Configs: + - Subnet: "10.255.0.0/16" + Gateway: "10.255.0.1" + Addresses: + - "10.255.0.10/16" + - ID: "1yljwbmlr8er2waf8orvqpwms" + Version: + Index: 30 + CreatedAt: "2016-06-07T21:07:30.019104782Z" + UpdatedAt: "2016-06-07T21:07:30.231958098Z" + Name: "hopeful_cori" + Spec: + ContainerSpec: + Image: "redis" + Resources: + Limits: {} + Reservations: {} + RestartPolicy: + Condition: "any" + MaxAttempts: 0 + Placement: {} + ServiceID: "9mnpnzenvg8p8tdbtq4wvbkcz" + Slot: 1 + NodeID: "60gvrl6tm78dmak4yl7srz94v" + Status: + Timestamp: "2016-06-07T21:07:30.202183143Z" + State: "shutdown" + Message: "shutdown" + ContainerStatus: + ContainerID: "1cf8d63d18e79668b0004a4be4c6ee58cddfad2dae29506d8781581d0688a213" + DesiredState: "shutdown" + NetworksAttachments: + - Network: + ID: "4qvuz4ko70xaltuqbt8956gd1" + Version: + Index: 18 + CreatedAt: "2016-06-07T20:31:11.912919752Z" + UpdatedAt: "2016-06-07T21:07:29.955277358Z" + Spec: + Name: "ingress" + Labels: + com.docker.swarm.internal: "true" + DriverConfiguration: {} + IPAMOptions: + Driver: {} + Configs: + - Subnet: "10.255.0.0/16" + Gateway: "10.255.0.1" + DriverState: + Name: "overlay" + Options: + com.docker.network.driver.overlay.vxlanid_list: "256" + IPAMOptions: + Driver: + Name: "default" + Configs: + - Subnet: "10.255.0.0/16" + Gateway: "10.255.0.1" + Addresses: + - "10.255.0.5/16" + 500: + description: "server error" + schema: + $ref: "#/definitions/ErrorResponse" + 503: + description: "node is not part of a swarm" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "filters" + in: "query" + type: "string" + description: | + A JSON encoded value of the filters (a `map[string][]string`) to + process on the tasks list. + + Available filters: + + - `desired-state=(running | shutdown | accepted)` + - `id=` + - `label=key` or `label="key=value"` + - `name=` + - `node=` + - `service=` + tags: ["Task"] + /tasks/{id}: + get: + summary: "Inspect a task" + operationId: "TaskInspect" + produces: + - "application/json" + responses: + 200: + description: "no error" + schema: + $ref: "#/definitions/Task" + 404: + description: "no such task" + schema: + $ref: "#/definitions/ErrorResponse" + 500: + description: "server error" + schema: + $ref: "#/definitions/ErrorResponse" + 503: + description: "node is not part of a swarm" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "id" + in: "path" + description: "ID of the task" + required: true + type: "string" + tags: ["Task"] + /tasks/{id}/logs: + get: + summary: "Get task logs" + description: | + Get `stdout` and `stderr` logs from a task. + See also [`/containers/{id}/logs`](#operation/ContainerLogs). + + **Note**: This endpoint works only for services with the `local`, + `json-file` or `journald` logging drivers. + operationId: "TaskLogs" + produces: + - "application/vnd.docker.raw-stream" + - "application/vnd.docker.multiplexed-stream" + responses: + 200: + description: "logs returned as a stream in response body" + schema: + type: "string" + format: "binary" + 404: + description: "no such task" + schema: + $ref: "#/definitions/ErrorResponse" + examples: + application/json: + message: "No such task: c2ada9df5af8" + 500: + description: "server error" + schema: + $ref: "#/definitions/ErrorResponse" + 503: + description: "node is not part of a swarm" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "id" + in: "path" + required: true + description: "ID of the task" + type: "string" + - name: "details" + in: "query" + description: "Show task context and extra details provided to logs." + type: "boolean" + default: false + - name: "follow" + in: "query" + description: "Keep connection after returning logs." + type: "boolean" + default: false + - name: "stdout" + in: "query" + description: "Return logs from `stdout`" + type: "boolean" + default: false + - name: "stderr" + in: "query" + description: "Return logs from `stderr`" + type: "boolean" + default: false + - name: "since" + in: "query" + description: "Only return logs since this time, as a UNIX timestamp" + type: "integer" + default: 0 + - name: "timestamps" + in: "query" + description: "Add timestamps to every log line" + type: "boolean" + default: false + - name: "tail" + in: "query" + description: | + Only return this number of log lines from the end of the logs. + Specify as an integer or `all` to output all log lines. + type: "string" + default: "all" + tags: ["Task"] + /secrets: + get: + summary: "List secrets" + operationId: "SecretList" + produces: + - "application/json" + responses: + 200: + description: "no error" + schema: + type: "array" + items: + $ref: "#/definitions/Secret" + example: + - ID: "blt1owaxmitz71s9v5zh81zun" + Version: + Index: 85 + CreatedAt: "2017-07-20T13:55:28.678958722Z" + UpdatedAt: "2017-07-20T13:55:28.678958722Z" + Spec: + Name: "mysql-passwd" + Labels: + some.label: "some.value" + Driver: + Name: "secret-bucket" + Options: + OptionA: "value for driver option A" + OptionB: "value for driver option B" + - ID: "ktnbjxoalbkvbvedmg1urrz8h" + Version: + Index: 11 + CreatedAt: "2016-11-05T01:20:17.327670065Z" + UpdatedAt: "2016-11-05T01:20:17.327670065Z" + Spec: + Name: "app-dev.crt" + Labels: + foo: "bar" + 500: + description: "server error" + schema: + $ref: "#/definitions/ErrorResponse" + 503: + description: "node is not part of a swarm" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "filters" + in: "query" + type: "string" + description: | + A JSON encoded value of the filters (a `map[string][]string`) to + process on the secrets list. + + Available filters: + + - `id=` + - `label= or label==value` + - `name=` + - `names=` + tags: ["Secret"] + /secrets/create: + post: + summary: "Create a secret" + operationId: "SecretCreate" + consumes: + - "application/json" + produces: + - "application/json" + responses: + 201: + description: "no error" + schema: + $ref: "#/definitions/IdResponse" + 409: + description: "name conflicts with an existing object" + schema: + $ref: "#/definitions/ErrorResponse" + 500: + description: "server error" + schema: + $ref: "#/definitions/ErrorResponse" + 503: + description: "node is not part of a swarm" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "body" + in: "body" + schema: + allOf: + - $ref: "#/definitions/SecretSpec" + - type: "object" + example: + Name: "app-key.crt" + Labels: + foo: "bar" + Data: "VEhJUyBJUyBOT1QgQSBSRUFMIENFUlRJRklDQVRFCg==" + Driver: + Name: "secret-bucket" + Options: + OptionA: "value for driver option A" + OptionB: "value for driver option B" + tags: ["Secret"] + /secrets/{id}: + get: + summary: "Inspect a secret" + operationId: "SecretInspect" + produces: + - "application/json" + responses: + 200: + description: "no error" + schema: + $ref: "#/definitions/Secret" + examples: + application/json: + ID: "ktnbjxoalbkvbvedmg1urrz8h" + Version: + Index: 11 + CreatedAt: "2016-11-05T01:20:17.327670065Z" + UpdatedAt: "2016-11-05T01:20:17.327670065Z" + Spec: + Name: "app-dev.crt" + Labels: + foo: "bar" + Driver: + Name: "secret-bucket" + Options: + OptionA: "value for driver option A" + OptionB: "value for driver option B" + + 404: + description: "secret not found" + schema: + $ref: "#/definitions/ErrorResponse" + 500: + description: "server error" + schema: + $ref: "#/definitions/ErrorResponse" + 503: + description: "node is not part of a swarm" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "id" + in: "path" + required: true + type: "string" + description: "ID of the secret" + tags: ["Secret"] + delete: + summary: "Delete a secret" + operationId: "SecretDelete" + produces: + - "application/json" + responses: + 204: + description: "no error" + 404: + description: "secret not found" + schema: + $ref: "#/definitions/ErrorResponse" + 500: + description: "server error" + schema: + $ref: "#/definitions/ErrorResponse" + 503: + description: "node is not part of a swarm" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "id" + in: "path" + required: true + type: "string" + description: "ID of the secret" + tags: ["Secret"] + /secrets/{id}/update: + post: + summary: "Update a Secret" + operationId: "SecretUpdate" + responses: + 200: + description: "no error" + 400: + description: "bad parameter" + schema: + $ref: "#/definitions/ErrorResponse" + 404: + description: "no such secret" + schema: + $ref: "#/definitions/ErrorResponse" + 500: + description: "server error" + schema: + $ref: "#/definitions/ErrorResponse" + 503: + description: "node is not part of a swarm" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "id" + in: "path" + description: "The ID or name of the secret" + type: "string" + required: true + - name: "body" + in: "body" + schema: + $ref: "#/definitions/SecretSpec" + description: | + The spec of the secret to update. Currently, only the Labels field + can be updated. All other fields must remain unchanged from the + [SecretInspect endpoint](#operation/SecretInspect) response values. + - name: "version" + in: "query" + description: | + The version number of the secret object being updated. This is + required to avoid conflicting writes. + type: "integer" + format: "int64" + required: true + tags: ["Secret"] + /configs: + get: + summary: "List configs" + operationId: "ConfigList" + produces: + - "application/json" + responses: + 200: + description: "no error" + schema: + type: "array" + items: + $ref: "#/definitions/Config" + example: + - ID: "ktnbjxoalbkvbvedmg1urrz8h" + Version: + Index: 11 + CreatedAt: "2016-11-05T01:20:17.327670065Z" + UpdatedAt: "2016-11-05T01:20:17.327670065Z" + Spec: + Name: "server.conf" + 500: + description: "server error" + schema: + $ref: "#/definitions/ErrorResponse" + 503: + description: "node is not part of a swarm" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "filters" + in: "query" + type: "string" + description: | + A JSON encoded value of the filters (a `map[string][]string`) to + process on the configs list. + + Available filters: + + - `id=` + - `label= or label==value` + - `name=` + - `names=` + tags: ["Config"] + /configs/create: + post: + summary: "Create a config" + operationId: "ConfigCreate" + consumes: + - "application/json" + produces: + - "application/json" + responses: + 201: + description: "no error" + schema: + $ref: "#/definitions/IdResponse" + 409: + description: "name conflicts with an existing object" + schema: + $ref: "#/definitions/ErrorResponse" + 500: + description: "server error" + schema: + $ref: "#/definitions/ErrorResponse" + 503: + description: "node is not part of a swarm" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "body" + in: "body" + schema: + allOf: + - $ref: "#/definitions/ConfigSpec" + - type: "object" + example: + Name: "server.conf" + Labels: + foo: "bar" + Data: "VEhJUyBJUyBOT1QgQSBSRUFMIENFUlRJRklDQVRFCg==" + tags: ["Config"] + /configs/{id}: + get: + summary: "Inspect a config" + operationId: "ConfigInspect" + produces: + - "application/json" + responses: + 200: + description: "no error" + schema: + $ref: "#/definitions/Config" + examples: + application/json: + ID: "ktnbjxoalbkvbvedmg1urrz8h" + Version: + Index: 11 + CreatedAt: "2016-11-05T01:20:17.327670065Z" + UpdatedAt: "2016-11-05T01:20:17.327670065Z" + Spec: + Name: "app-dev.crt" + 404: + description: "config not found" + schema: + $ref: "#/definitions/ErrorResponse" + 500: + description: "server error" + schema: + $ref: "#/definitions/ErrorResponse" + 503: + description: "node is not part of a swarm" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "id" + in: "path" + required: true + type: "string" + description: "ID of the config" + tags: ["Config"] + delete: + summary: "Delete a config" + operationId: "ConfigDelete" + produces: + - "application/json" + responses: + 204: + description: "no error" + 404: + description: "config not found" + schema: + $ref: "#/definitions/ErrorResponse" + 500: + description: "server error" + schema: + $ref: "#/definitions/ErrorResponse" + 503: + description: "node is not part of a swarm" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "id" + in: "path" + required: true + type: "string" + description: "ID of the config" + tags: ["Config"] + /configs/{id}/update: + post: + summary: "Update a Config" + operationId: "ConfigUpdate" + responses: + 200: + description: "no error" + 400: + description: "bad parameter" + schema: + $ref: "#/definitions/ErrorResponse" + 404: + description: "no such config" + schema: + $ref: "#/definitions/ErrorResponse" + 500: + description: "server error" + schema: + $ref: "#/definitions/ErrorResponse" + 503: + description: "node is not part of a swarm" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "id" + in: "path" + description: "The ID or name of the config" + type: "string" + required: true + - name: "body" + in: "body" + schema: + $ref: "#/definitions/ConfigSpec" + description: | + The spec of the config to update. Currently, only the Labels field + can be updated. All other fields must remain unchanged from the + [ConfigInspect endpoint](#operation/ConfigInspect) response values. + - name: "version" + in: "query" + description: | + The version number of the config object being updated. This is + required to avoid conflicting writes. + type: "integer" + format: "int64" + required: true + tags: ["Config"] + /distribution/{name}/json: + get: + summary: "Get image information from the registry" + description: | + Return image digest and platform information by contacting the registry. + operationId: "DistributionInspect" + produces: + - "application/json" + responses: + 200: + description: "descriptor and platform information" + schema: + $ref: "#/definitions/DistributionInspect" + 401: + description: "Failed authentication or no image found" + schema: + $ref: "#/definitions/ErrorResponse" + examples: + application/json: + message: "No such image: someimage (tag: latest)" + 500: + description: "Server error" + schema: + $ref: "#/definitions/ErrorResponse" + parameters: + - name: "name" + in: "path" + description: "Image name or id" + type: "string" + required: true + tags: ["Distribution"] + /session: + post: + summary: "Initialize interactive session" + description: | + Start a new interactive session with a server. Session allows server to + call back to the client for advanced capabilities. + + ### Hijacking + + This endpoint hijacks the HTTP connection to HTTP2 transport that allows + the client to expose gPRC services on that connection. + + For example, the client sends this request to upgrade the connection: + + ``` + POST /session HTTP/1.1 + Upgrade: h2c + Connection: Upgrade + ``` + + The Docker daemon responds with a `101 UPGRADED` response follow with + the raw stream: + + ``` + HTTP/1.1 101 UPGRADED + Connection: Upgrade + Upgrade: h2c + ``` + operationId: "Session" + produces: + - "application/vnd.docker.raw-stream" + responses: + 101: + description: "no error, hijacking successful" + 400: + description: "bad parameter" + schema: + $ref: "#/definitions/ErrorResponse" + 500: + description: "server error" + schema: + $ref: "#/definitions/ErrorResponse" + tags: ["Session"] diff --git a/vendor/github.com/docker/docker/api/types/auth.go b/vendor/github.com/docker/docker/api/types/auth.go new file mode 100644 index 0000000000..ddf15bb182 --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/auth.go @@ -0,0 +1,22 @@ +package types // import "github.com/docker/docker/api/types" + +// AuthConfig contains authorization information for connecting to a Registry +type AuthConfig struct { + Username string `json:"username,omitempty"` + Password string `json:"password,omitempty"` + Auth string `json:"auth,omitempty"` + + // Email is an optional value associated with the username. + // This field is deprecated and will be removed in a later + // version of docker. + Email string `json:"email,omitempty"` + + ServerAddress string `json:"serveraddress,omitempty"` + + // IdentityToken is used to authenticate the user and get + // an access token for the registry. + IdentityToken string `json:"identitytoken,omitempty"` + + // RegistryToken is a bearer token to be sent to a registry + RegistryToken string `json:"registrytoken,omitempty"` +} diff --git a/vendor/github.com/docker/docker/api/types/blkiodev/blkio.go b/vendor/github.com/docker/docker/api/types/blkiodev/blkio.go new file mode 100644 index 0000000000..bf3463b90e --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/blkiodev/blkio.go @@ -0,0 +1,23 @@ +package blkiodev // import "github.com/docker/docker/api/types/blkiodev" + +import "fmt" + +// WeightDevice is a structure that holds device:weight pair +type WeightDevice struct { + Path string + Weight uint16 +} + +func (w *WeightDevice) String() string { + return fmt.Sprintf("%s:%d", w.Path, w.Weight) +} + +// ThrottleDevice is a structure that holds device:rate_per_second pair +type ThrottleDevice struct { + Path string + Rate uint64 +} + +func (t *ThrottleDevice) String() string { + return fmt.Sprintf("%s:%d", t.Path, t.Rate) +} diff --git a/vendor/github.com/docker/docker/api/types/client.go b/vendor/github.com/docker/docker/api/types/client.go new file mode 100644 index 0000000000..97aca02306 --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/client.go @@ -0,0 +1,443 @@ +package types // import "github.com/docker/docker/api/types" + +import ( + "bufio" + "io" + "net" + + "github.com/docker/docker/api/types/container" + "github.com/docker/docker/api/types/filters" + units "github.com/docker/go-units" +) + +// CheckpointCreateOptions holds parameters to create a checkpoint from a container +type CheckpointCreateOptions struct { + CheckpointID string + CheckpointDir string + Exit bool +} + +// CheckpointListOptions holds parameters to list checkpoints for a container +type CheckpointListOptions struct { + CheckpointDir string +} + +// CheckpointDeleteOptions holds parameters to delete a checkpoint from a container +type CheckpointDeleteOptions struct { + CheckpointID string + CheckpointDir string +} + +// ContainerAttachOptions holds parameters to attach to a container. +type ContainerAttachOptions struct { + Stream bool + Stdin bool + Stdout bool + Stderr bool + DetachKeys string + Logs bool +} + +// ContainerCommitOptions holds parameters to commit changes into a container. +type ContainerCommitOptions struct { + Reference string + Comment string + Author string + Changes []string + Pause bool + Config *container.Config +} + +// ContainerExecInspect holds information returned by exec inspect. +type ContainerExecInspect struct { + ExecID string `json:"ID"` + ContainerID string + Running bool + ExitCode int + Pid int +} + +// ContainerListOptions holds parameters to list containers with. +type ContainerListOptions struct { + Size bool + All bool + Latest bool + Since string + Before string + Limit int + Filters filters.Args +} + +// ContainerLogsOptions holds parameters to filter logs with. +type ContainerLogsOptions struct { + ShowStdout bool + ShowStderr bool + Since string + Until string + Timestamps bool + Follow bool + Tail string + Details bool +} + +// ContainerRemoveOptions holds parameters to remove containers. +type ContainerRemoveOptions struct { + RemoveVolumes bool + RemoveLinks bool + Force bool +} + +// ContainerStartOptions holds parameters to start containers. +type ContainerStartOptions struct { + CheckpointID string + CheckpointDir string +} + +// CopyToContainerOptions holds information +// about files to copy into a container +type CopyToContainerOptions struct { + AllowOverwriteDirWithFile bool + CopyUIDGID bool +} + +// EventsOptions holds parameters to filter events with. +type EventsOptions struct { + Since string + Until string + Filters filters.Args +} + +// NetworkListOptions holds parameters to filter the list of networks with. +type NetworkListOptions struct { + Filters filters.Args +} + +// NewHijackedResponse intializes a HijackedResponse type +func NewHijackedResponse(conn net.Conn, mediaType string) HijackedResponse { + return HijackedResponse{Conn: conn, Reader: bufio.NewReader(conn), mediaType: mediaType} +} + +// HijackedResponse holds connection information for a hijacked request. +type HijackedResponse struct { + mediaType string + Conn net.Conn + Reader *bufio.Reader +} + +// Close closes the hijacked connection and reader. +func (h *HijackedResponse) Close() { + h.Conn.Close() +} + +// MediaType let client know if HijackedResponse hold a raw or multiplexed stream. +// returns false if HTTP Content-Type is not relevant, and container must be inspected +func (h *HijackedResponse) MediaType() (string, bool) { + if h.mediaType == "" { + return "", false + } + return h.mediaType, true +} + +// CloseWriter is an interface that implements structs +// that close input streams to prevent from writing. +type CloseWriter interface { + CloseWrite() error +} + +// CloseWrite closes a readWriter for writing. +func (h *HijackedResponse) CloseWrite() error { + if conn, ok := h.Conn.(CloseWriter); ok { + return conn.CloseWrite() + } + return nil +} + +// ImageBuildOptions holds the information +// necessary to build images. +type ImageBuildOptions struct { + Tags []string + SuppressOutput bool + RemoteContext string + NoCache bool + Remove bool + ForceRemove bool + PullParent bool + Isolation container.Isolation + CPUSetCPUs string + CPUSetMems string + CPUShares int64 + CPUQuota int64 + CPUPeriod int64 + Memory int64 + MemorySwap int64 + CgroupParent string + NetworkMode string + ShmSize int64 + Dockerfile string + Ulimits []*units.Ulimit + // BuildArgs needs to be a *string instead of just a string so that + // we can tell the difference between "" (empty string) and no value + // at all (nil). See the parsing of buildArgs in + // api/server/router/build/build_routes.go for even more info. + BuildArgs map[string]*string + AuthConfigs map[string]AuthConfig + Context io.Reader + Labels map[string]string + // squash the resulting image's layers to the parent + // preserves the original image and creates a new one from the parent with all + // the changes applied to a single layer + Squash bool + // CacheFrom specifies images that are used for matching cache. Images + // specified here do not need to have a valid parent chain to match cache. + CacheFrom []string + SecurityOpt []string + ExtraHosts []string // List of extra hosts + Target string + SessionID string + Platform string + // Version specifies the version of the unerlying builder to use + Version BuilderVersion + // BuildID is an optional identifier that can be passed together with the + // build request. The same identifier can be used to gracefully cancel the + // build with the cancel request. + BuildID string + // Outputs defines configurations for exporting build results. Only supported + // in BuildKit mode + Outputs []ImageBuildOutput +} + +// ImageBuildOutput defines configuration for exporting a build result +type ImageBuildOutput struct { + Type string + Attrs map[string]string +} + +// BuilderVersion sets the version of underlying builder to use +type BuilderVersion string + +const ( + // BuilderV1 is the first generation builder in docker daemon + BuilderV1 BuilderVersion = "1" + // BuilderBuildKit is builder based on moby/buildkit project + BuilderBuildKit BuilderVersion = "2" +) + +// ImageBuildResponse holds information +// returned by a server after building +// an image. +type ImageBuildResponse struct { + Body io.ReadCloser + OSType string +} + +// ImageCreateOptions holds information to create images. +type ImageCreateOptions struct { + RegistryAuth string // RegistryAuth is the base64 encoded credentials for the registry. + Platform string // Platform is the target platform of the image if it needs to be pulled from the registry. +} + +// ImageImportSource holds source information for ImageImport +type ImageImportSource struct { + Source io.Reader // Source is the data to send to the server to create this image from. You must set SourceName to "-" to leverage this. + SourceName string // SourceName is the name of the image to pull. Set to "-" to leverage the Source attribute. +} + +// ImageImportOptions holds information to import images from the client host. +type ImageImportOptions struct { + Tag string // Tag is the name to tag this image with. This attribute is deprecated. + Message string // Message is the message to tag the image with + Changes []string // Changes are the raw changes to apply to this image + Platform string // Platform is the target platform of the image +} + +// ImageListOptions holds parameters to list images with. +type ImageListOptions struct { + // All controls whether all images in the graph are filtered, or just + // the heads. + All bool + + // Filters is a JSON-encoded set of filter arguments. + Filters filters.Args + + // SharedSize indicates whether the shared size of images should be computed. + SharedSize bool + + // ContainerCount indicates whether container count should be computed. + ContainerCount bool +} + +// ImageLoadResponse returns information to the client about a load process. +type ImageLoadResponse struct { + // Body must be closed to avoid a resource leak + Body io.ReadCloser + JSON bool +} + +// ImagePullOptions holds information to pull images. +type ImagePullOptions struct { + All bool + RegistryAuth string // RegistryAuth is the base64 encoded credentials for the registry + PrivilegeFunc RequestPrivilegeFunc + Platform string +} + +// RequestPrivilegeFunc is a function interface that +// clients can supply to retry operations after +// getting an authorization error. +// This function returns the registry authentication +// header value in base 64 format, or an error +// if the privilege request fails. +type RequestPrivilegeFunc func() (string, error) + +// ImagePushOptions holds information to push images. +type ImagePushOptions ImagePullOptions + +// ImageRemoveOptions holds parameters to remove images. +type ImageRemoveOptions struct { + Force bool + PruneChildren bool +} + +// ImageSearchOptions holds parameters to search images with. +type ImageSearchOptions struct { + RegistryAuth string + PrivilegeFunc RequestPrivilegeFunc + Filters filters.Args + Limit int +} + +// ResizeOptions holds parameters to resize a tty. +// It can be used to resize container ttys and +// exec process ttys too. +type ResizeOptions struct { + Height uint + Width uint +} + +// NodeListOptions holds parameters to list nodes with. +type NodeListOptions struct { + Filters filters.Args +} + +// NodeRemoveOptions holds parameters to remove nodes with. +type NodeRemoveOptions struct { + Force bool +} + +// ServiceCreateOptions contains the options to use when creating a service. +type ServiceCreateOptions struct { + // EncodedRegistryAuth is the encoded registry authorization credentials to + // use when updating the service. + // + // This field follows the format of the X-Registry-Auth header. + EncodedRegistryAuth string + + // QueryRegistry indicates whether the service update requires + // contacting a registry. A registry may be contacted to retrieve + // the image digest and manifest, which in turn can be used to update + // platform or other information about the service. + QueryRegistry bool +} + +// ServiceCreateResponse contains the information returned to a client +// on the creation of a new service. +type ServiceCreateResponse struct { + // ID is the ID of the created service. + ID string + // Warnings is a set of non-fatal warning messages to pass on to the user. + Warnings []string `json:",omitempty"` +} + +// Values for RegistryAuthFrom in ServiceUpdateOptions +const ( + RegistryAuthFromSpec = "spec" + RegistryAuthFromPreviousSpec = "previous-spec" +) + +// ServiceUpdateOptions contains the options to be used for updating services. +type ServiceUpdateOptions struct { + // EncodedRegistryAuth is the encoded registry authorization credentials to + // use when updating the service. + // + // This field follows the format of the X-Registry-Auth header. + EncodedRegistryAuth string + + // TODO(stevvooe): Consider moving the version parameter of ServiceUpdate + // into this field. While it does open API users up to racy writes, most + // users may not need that level of consistency in practice. + + // RegistryAuthFrom specifies where to find the registry authorization + // credentials if they are not given in EncodedRegistryAuth. Valid + // values are "spec" and "previous-spec". + RegistryAuthFrom string + + // Rollback indicates whether a server-side rollback should be + // performed. When this is set, the provided spec will be ignored. + // The valid values are "previous" and "none". An empty value is the + // same as "none". + Rollback string + + // QueryRegistry indicates whether the service update requires + // contacting a registry. A registry may be contacted to retrieve + // the image digest and manifest, which in turn can be used to update + // platform or other information about the service. + QueryRegistry bool +} + +// ServiceListOptions holds parameters to list services with. +type ServiceListOptions struct { + Filters filters.Args + + // Status indicates whether the server should include the service task + // count of running and desired tasks. + Status bool +} + +// ServiceInspectOptions holds parameters related to the "service inspect" +// operation. +type ServiceInspectOptions struct { + InsertDefaults bool +} + +// TaskListOptions holds parameters to list tasks with. +type TaskListOptions struct { + Filters filters.Args +} + +// PluginRemoveOptions holds parameters to remove plugins. +type PluginRemoveOptions struct { + Force bool +} + +// PluginEnableOptions holds parameters to enable plugins. +type PluginEnableOptions struct { + Timeout int +} + +// PluginDisableOptions holds parameters to disable plugins. +type PluginDisableOptions struct { + Force bool +} + +// PluginInstallOptions holds parameters to install a plugin. +type PluginInstallOptions struct { + Disabled bool + AcceptAllPermissions bool + RegistryAuth string // RegistryAuth is the base64 encoded credentials for the registry + RemoteRef string // RemoteRef is the plugin name on the registry + PrivilegeFunc RequestPrivilegeFunc + AcceptPermissionsFunc func(PluginPrivileges) (bool, error) + Args []string +} + +// SwarmUnlockKeyResponse contains the response for Engine API: +// GET /swarm/unlockkey +type SwarmUnlockKeyResponse struct { + // UnlockKey is the unlock key in ASCII-armored format. + UnlockKey string +} + +// PluginCreateOptions hold all options to plugin create. +type PluginCreateOptions struct { + RepoName string +} diff --git a/vendor/github.com/docker/docker/api/types/configs.go b/vendor/github.com/docker/docker/api/types/configs.go new file mode 100644 index 0000000000..7689f38b33 --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/configs.go @@ -0,0 +1,67 @@ +package types // import "github.com/docker/docker/api/types" + +import ( + "github.com/docker/docker/api/types/container" + "github.com/docker/docker/api/types/network" + specs "github.com/opencontainers/image-spec/specs-go/v1" +) + +// configs holds structs used for internal communication between the +// frontend (such as an http server) and the backend (such as the +// docker daemon). + +// ContainerCreateConfig is the parameter set to ContainerCreate() +type ContainerCreateConfig struct { + Name string + Config *container.Config + HostConfig *container.HostConfig + NetworkingConfig *network.NetworkingConfig + Platform *specs.Platform + AdjustCPUShares bool +} + +// ContainerRmConfig holds arguments for the container remove +// operation. This struct is used to tell the backend what operations +// to perform. +type ContainerRmConfig struct { + ForceRemove, RemoveVolume, RemoveLink bool +} + +// ExecConfig is a small subset of the Config struct that holds the configuration +// for the exec feature of docker. +type ExecConfig struct { + User string // User that will run the command + Privileged bool // Is the container in privileged mode + Tty bool // Attach standard streams to a tty. + ConsoleSize *[2]uint `json:",omitempty"` // Initial console size [height, width] + AttachStdin bool // Attach the standard input, makes possible user interaction + AttachStderr bool // Attach the standard error + AttachStdout bool // Attach the standard output + Detach bool // Execute in detach mode + DetachKeys string // Escape keys for detach + Env []string // Environment variables + WorkingDir string // Working directory + Cmd []string // Execution commands and args +} + +// PluginRmConfig holds arguments for plugin remove. +type PluginRmConfig struct { + ForceRemove bool +} + +// PluginEnableConfig holds arguments for plugin enable +type PluginEnableConfig struct { + Timeout int +} + +// PluginDisableConfig holds arguments for plugin disable. +type PluginDisableConfig struct { + ForceDisable bool +} + +// NetworkListConfig stores the options available for listing networks +type NetworkListConfig struct { + // TODO(@cpuguy83): naming is hard, this is pulled from what was being used in the router before moving here + Detailed bool + Verbose bool +} diff --git a/vendor/github.com/docker/docker/api/types/container/config.go b/vendor/github.com/docker/docker/api/types/container/config.go new file mode 100644 index 0000000000..077583e66c --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/container/config.go @@ -0,0 +1,96 @@ +package container // import "github.com/docker/docker/api/types/container" + +import ( + "io" + "time" + + "github.com/docker/docker/api/types/strslice" + "github.com/docker/go-connections/nat" +) + +// MinimumDuration puts a minimum on user configured duration. +// This is to prevent API error on time unit. For example, API may +// set 3 as healthcheck interval with intention of 3 seconds, but +// Docker interprets it as 3 nanoseconds. +const MinimumDuration = 1 * time.Millisecond + +// StopOptions holds the options to stop or restart a container. +type StopOptions struct { + // Signal (optional) is the signal to send to the container to (gracefully) + // stop it before forcibly terminating the container with SIGKILL after the + // timeout expires. If not value is set, the default (SIGTERM) is used. + Signal string `json:",omitempty"` + + // Timeout (optional) is the timeout (in seconds) to wait for the container + // to stop gracefully before forcibly terminating it with SIGKILL. + // + // - Use nil to use the default timeout (10 seconds). + // - Use '-1' to wait indefinitely. + // - Use '0' to not wait for the container to exit gracefully, and + // immediately proceeds to forcibly terminating the container. + // - Other positive values are used as timeout (in seconds). + Timeout *int `json:",omitempty"` +} + +// HealthConfig holds configuration settings for the HEALTHCHECK feature. +type HealthConfig struct { + // Test is the test to perform to check that the container is healthy. + // An empty slice means to inherit the default. + // The options are: + // {} : inherit healthcheck + // {"NONE"} : disable healthcheck + // {"CMD", args...} : exec arguments directly + // {"CMD-SHELL", command} : run command with system's default shell + Test []string `json:",omitempty"` + + // Zero means to inherit. Durations are expressed as integer nanoseconds. + Interval time.Duration `json:",omitempty"` // Interval is the time to wait between checks. + Timeout time.Duration `json:",omitempty"` // Timeout is the time to wait before considering the check to have hung. + StartPeriod time.Duration `json:",omitempty"` // The start period for the container to initialize before the retries starts to count down. + + // Retries is the number of consecutive failures needed to consider a container as unhealthy. + // Zero means inherit. + Retries int `json:",omitempty"` +} + +// ExecStartOptions holds the options to start container's exec. +type ExecStartOptions struct { + Stdin io.Reader + Stdout io.Writer + Stderr io.Writer + ConsoleSize *[2]uint `json:",omitempty"` +} + +// Config contains the configuration data about a container. +// It should hold only portable information about the container. +// Here, "portable" means "independent from the host we are running on". +// Non-portable information *should* appear in HostConfig. +// All fields added to this struct must be marked `omitempty` to keep getting +// predictable hashes from the old `v1Compatibility` configuration. +type Config struct { + Hostname string // Hostname + Domainname string // Domainname + User string // User that will run the command(s) inside the container, also support user:group + AttachStdin bool // Attach the standard input, makes possible user interaction + AttachStdout bool // Attach the standard output + AttachStderr bool // Attach the standard error + ExposedPorts nat.PortSet `json:",omitempty"` // List of exposed ports + Tty bool // Attach standard streams to a tty, including stdin if it is not closed. + OpenStdin bool // Open stdin + StdinOnce bool // If true, close stdin after the 1 attached client disconnects. + Env []string // List of environment variable to set in the container + Cmd strslice.StrSlice // Command to run when starting the container + Healthcheck *HealthConfig `json:",omitempty"` // Healthcheck describes how to check the container is healthy + ArgsEscaped bool `json:",omitempty"` // True if command is already escaped (meaning treat as a command line) (Windows specific). + Image string // Name of the image as it was passed by the operator (e.g. could be symbolic) + Volumes map[string]struct{} // List of volumes (mounts) used for the container + WorkingDir string // Current directory (PWD) in the command will be launched + Entrypoint strslice.StrSlice // Entrypoint to run when starting the container + NetworkDisabled bool `json:",omitempty"` // Is network disabled + MacAddress string `json:",omitempty"` // Mac Address of the container + OnBuild []string // ONBUILD metadata that were defined on the image Dockerfile + Labels map[string]string // List of labels set to this container + StopSignal string `json:",omitempty"` // Signal to stop a container + StopTimeout *int `json:",omitempty"` // Timeout (in seconds) to stop a container + Shell strslice.StrSlice `json:",omitempty"` // Shell for shell-form of RUN, CMD, ENTRYPOINT +} diff --git a/vendor/github.com/docker/docker/api/types/container/container_changes.go b/vendor/github.com/docker/docker/api/types/container/container_changes.go new file mode 100644 index 0000000000..16dd5019ee --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/container/container_changes.go @@ -0,0 +1,20 @@ +package container // import "github.com/docker/docker/api/types/container" + +// ---------------------------------------------------------------------------- +// Code generated by `swagger generate operation`. DO NOT EDIT. +// +// See hack/generate-swagger-api.sh +// ---------------------------------------------------------------------------- + +// ContainerChangeResponseItem change item in response to ContainerChanges operation +// swagger:model ContainerChangeResponseItem +type ContainerChangeResponseItem struct { + + // Kind of change + // Required: true + Kind uint8 `json:"Kind"` + + // Path to file that has changed + // Required: true + Path string `json:"Path"` +} diff --git a/vendor/github.com/docker/docker/api/types/container/container_top.go b/vendor/github.com/docker/docker/api/types/container/container_top.go new file mode 100644 index 0000000000..63381da367 --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/container/container_top.go @@ -0,0 +1,22 @@ +package container // import "github.com/docker/docker/api/types/container" + +// ---------------------------------------------------------------------------- +// Code generated by `swagger generate operation`. DO NOT EDIT. +// +// See hack/generate-swagger-api.sh +// ---------------------------------------------------------------------------- + +// ContainerTopOKBody OK response to ContainerTop operation +// swagger:model ContainerTopOKBody +type ContainerTopOKBody struct { + + // Each process running in the container, where each is process + // is an array of values corresponding to the titles. + // + // Required: true + Processes [][]string `json:"Processes"` + + // The ps column titles + // Required: true + Titles []string `json:"Titles"` +} diff --git a/vendor/github.com/docker/docker/api/types/container/container_update.go b/vendor/github.com/docker/docker/api/types/container/container_update.go new file mode 100644 index 0000000000..c10f175ea8 --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/container/container_update.go @@ -0,0 +1,16 @@ +package container // import "github.com/docker/docker/api/types/container" + +// ---------------------------------------------------------------------------- +// Code generated by `swagger generate operation`. DO NOT EDIT. +// +// See hack/generate-swagger-api.sh +// ---------------------------------------------------------------------------- + +// ContainerUpdateOKBody OK response to ContainerUpdate operation +// swagger:model ContainerUpdateOKBody +type ContainerUpdateOKBody struct { + + // warnings + // Required: true + Warnings []string `json:"Warnings"` +} diff --git a/vendor/github.com/docker/docker/api/types/container/create_response.go b/vendor/github.com/docker/docker/api/types/container/create_response.go new file mode 100644 index 0000000000..aa0e7f7d07 --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/container/create_response.go @@ -0,0 +1,19 @@ +package container + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +// CreateResponse ContainerCreateResponse +// +// OK response to ContainerCreate operation +// swagger:model CreateResponse +type CreateResponse struct { + + // The ID of the created container + // Required: true + ID string `json:"Id"` + + // Warnings encountered when creating the container + // Required: true + Warnings []string `json:"Warnings"` +} diff --git a/vendor/github.com/docker/docker/api/types/container/deprecated.go b/vendor/github.com/docker/docker/api/types/container/deprecated.go new file mode 100644 index 0000000000..0cb70e3638 --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/container/deprecated.go @@ -0,0 +1,16 @@ +package container // import "github.com/docker/docker/api/types/container" + +// ContainerCreateCreatedBody OK response to ContainerCreate operation +// +// Deprecated: use CreateResponse +type ContainerCreateCreatedBody = CreateResponse + +// ContainerWaitOKBody OK response to ContainerWait operation +// +// Deprecated: use WaitResponse +type ContainerWaitOKBody = WaitResponse + +// ContainerWaitOKBodyError container waiting error, if any +// +// Deprecated: use WaitExitError +type ContainerWaitOKBodyError = WaitExitError diff --git a/vendor/github.com/docker/docker/api/types/container/host_config.go b/vendor/github.com/docker/docker/api/types/container/host_config.go new file mode 100644 index 0000000000..100f434ce7 --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/container/host_config.go @@ -0,0 +1,465 @@ +package container // import "github.com/docker/docker/api/types/container" + +import ( + "strings" + + "github.com/docker/docker/api/types/blkiodev" + "github.com/docker/docker/api/types/mount" + "github.com/docker/docker/api/types/strslice" + "github.com/docker/go-connections/nat" + units "github.com/docker/go-units" +) + +// CgroupnsMode represents the cgroup namespace mode of the container +type CgroupnsMode string + +// cgroup namespace modes for containers +const ( + CgroupnsModeEmpty CgroupnsMode = "" + CgroupnsModePrivate CgroupnsMode = "private" + CgroupnsModeHost CgroupnsMode = "host" +) + +// IsPrivate indicates whether the container uses its own private cgroup namespace +func (c CgroupnsMode) IsPrivate() bool { + return c == CgroupnsModePrivate +} + +// IsHost indicates whether the container shares the host's cgroup namespace +func (c CgroupnsMode) IsHost() bool { + return c == CgroupnsModeHost +} + +// IsEmpty indicates whether the container cgroup namespace mode is unset +func (c CgroupnsMode) IsEmpty() bool { + return c == CgroupnsModeEmpty +} + +// Valid indicates whether the cgroup namespace mode is valid +func (c CgroupnsMode) Valid() bool { + return c.IsEmpty() || c.IsPrivate() || c.IsHost() +} + +// Isolation represents the isolation technology of a container. The supported +// values are platform specific +type Isolation string + +// Isolation modes for containers +const ( + IsolationEmpty Isolation = "" // IsolationEmpty is unspecified (same behavior as default) + IsolationDefault Isolation = "default" // IsolationDefault is the default isolation mode on current daemon + IsolationProcess Isolation = "process" // IsolationProcess is process isolation mode + IsolationHyperV Isolation = "hyperv" // IsolationHyperV is HyperV isolation mode +) + +// IsDefault indicates the default isolation technology of a container. On Linux this +// is the native driver. On Windows, this is a Windows Server Container. +func (i Isolation) IsDefault() bool { + // TODO consider making isolation-mode strict (case-sensitive) + v := Isolation(strings.ToLower(string(i))) + return v == IsolationDefault || v == IsolationEmpty +} + +// IsHyperV indicates the use of a Hyper-V partition for isolation +func (i Isolation) IsHyperV() bool { + // TODO consider making isolation-mode strict (case-sensitive) + return Isolation(strings.ToLower(string(i))) == IsolationHyperV +} + +// IsProcess indicates the use of process isolation +func (i Isolation) IsProcess() bool { + // TODO consider making isolation-mode strict (case-sensitive) + return Isolation(strings.ToLower(string(i))) == IsolationProcess +} + +// IpcMode represents the container ipc stack. +type IpcMode string + +// IpcMode constants +const ( + IPCModeNone IpcMode = "none" + IPCModeHost IpcMode = "host" + IPCModeContainer IpcMode = "container" + IPCModePrivate IpcMode = "private" + IPCModeShareable IpcMode = "shareable" +) + +// IsPrivate indicates whether the container uses its own private ipc namespace which can not be shared. +func (n IpcMode) IsPrivate() bool { + return n == IPCModePrivate +} + +// IsHost indicates whether the container shares the host's ipc namespace. +func (n IpcMode) IsHost() bool { + return n == IPCModeHost +} + +// IsShareable indicates whether the container's ipc namespace can be shared with another container. +func (n IpcMode) IsShareable() bool { + return n == IPCModeShareable +} + +// IsContainer indicates whether the container uses another container's ipc namespace. +func (n IpcMode) IsContainer() bool { + return strings.HasPrefix(string(n), string(IPCModeContainer)+":") +} + +// IsNone indicates whether container IpcMode is set to "none". +func (n IpcMode) IsNone() bool { + return n == IPCModeNone +} + +// IsEmpty indicates whether container IpcMode is empty +func (n IpcMode) IsEmpty() bool { + return n == "" +} + +// Valid indicates whether the ipc mode is valid. +func (n IpcMode) Valid() bool { + return n.IsEmpty() || n.IsNone() || n.IsPrivate() || n.IsHost() || n.IsShareable() || n.IsContainer() +} + +// Container returns the name of the container ipc stack is going to be used. +func (n IpcMode) Container() string { + if n.IsContainer() { + return strings.TrimPrefix(string(n), string(IPCModeContainer)+":") + } + return "" +} + +// NetworkMode represents the container network stack. +type NetworkMode string + +// IsNone indicates whether container isn't using a network stack. +func (n NetworkMode) IsNone() bool { + return n == "none" +} + +// IsDefault indicates whether container uses the default network stack. +func (n NetworkMode) IsDefault() bool { + return n == "default" +} + +// IsPrivate indicates whether container uses its private network stack. +func (n NetworkMode) IsPrivate() bool { + return !(n.IsHost() || n.IsContainer()) +} + +// IsContainer indicates whether container uses a container network stack. +func (n NetworkMode) IsContainer() bool { + parts := strings.SplitN(string(n), ":", 2) + return len(parts) > 1 && parts[0] == "container" +} + +// ConnectedContainer is the id of the container which network this container is connected to. +func (n NetworkMode) ConnectedContainer() string { + parts := strings.SplitN(string(n), ":", 2) + if len(parts) > 1 { + return parts[1] + } + return "" +} + +// UserDefined indicates user-created network +func (n NetworkMode) UserDefined() string { + if n.IsUserDefined() { + return string(n) + } + return "" +} + +// UsernsMode represents userns mode in the container. +type UsernsMode string + +// IsHost indicates whether the container uses the host's userns. +func (n UsernsMode) IsHost() bool { + return n == "host" +} + +// IsPrivate indicates whether the container uses the a private userns. +func (n UsernsMode) IsPrivate() bool { + return !(n.IsHost()) +} + +// Valid indicates whether the userns is valid. +func (n UsernsMode) Valid() bool { + parts := strings.Split(string(n), ":") + switch mode := parts[0]; mode { + case "", "host": + default: + return false + } + return true +} + +// CgroupSpec represents the cgroup to use for the container. +type CgroupSpec string + +// IsContainer indicates whether the container is using another container cgroup +func (c CgroupSpec) IsContainer() bool { + parts := strings.SplitN(string(c), ":", 2) + return len(parts) > 1 && parts[0] == "container" +} + +// Valid indicates whether the cgroup spec is valid. +func (c CgroupSpec) Valid() bool { + return c.IsContainer() || c == "" +} + +// Container returns the name of the container whose cgroup will be used. +func (c CgroupSpec) Container() string { + parts := strings.SplitN(string(c), ":", 2) + if len(parts) > 1 { + return parts[1] + } + return "" +} + +// UTSMode represents the UTS namespace of the container. +type UTSMode string + +// IsPrivate indicates whether the container uses its private UTS namespace. +func (n UTSMode) IsPrivate() bool { + return !(n.IsHost()) +} + +// IsHost indicates whether the container uses the host's UTS namespace. +func (n UTSMode) IsHost() bool { + return n == "host" +} + +// Valid indicates whether the UTS namespace is valid. +func (n UTSMode) Valid() bool { + parts := strings.Split(string(n), ":") + switch mode := parts[0]; mode { + case "", "host": + default: + return false + } + return true +} + +// PidMode represents the pid namespace of the container. +type PidMode string + +// IsPrivate indicates whether the container uses its own new pid namespace. +func (n PidMode) IsPrivate() bool { + return !(n.IsHost() || n.IsContainer()) +} + +// IsHost indicates whether the container uses the host's pid namespace. +func (n PidMode) IsHost() bool { + return n == "host" +} + +// IsContainer indicates whether the container uses a container's pid namespace. +func (n PidMode) IsContainer() bool { + parts := strings.SplitN(string(n), ":", 2) + return len(parts) > 1 && parts[0] == "container" +} + +// Valid indicates whether the pid namespace is valid. +func (n PidMode) Valid() bool { + parts := strings.Split(string(n), ":") + switch mode := parts[0]; mode { + case "", "host": + case "container": + if len(parts) != 2 || parts[1] == "" { + return false + } + default: + return false + } + return true +} + +// Container returns the name of the container whose pid namespace is going to be used. +func (n PidMode) Container() string { + parts := strings.SplitN(string(n), ":", 2) + if len(parts) > 1 { + return parts[1] + } + return "" +} + +// DeviceRequest represents a request for devices from a device driver. +// Used by GPU device drivers. +type DeviceRequest struct { + Driver string // Name of device driver + Count int // Number of devices to request (-1 = All) + DeviceIDs []string // List of device IDs as recognizable by the device driver + Capabilities [][]string // An OR list of AND lists of device capabilities (e.g. "gpu") + Options map[string]string // Options to pass onto the device driver +} + +// DeviceMapping represents the device mapping between the host and the container. +type DeviceMapping struct { + PathOnHost string + PathInContainer string + CgroupPermissions string +} + +// RestartPolicy represents the restart policies of the container. +type RestartPolicy struct { + Name string + MaximumRetryCount int +} + +// IsNone indicates whether the container has the "no" restart policy. +// This means the container will not automatically restart when exiting. +func (rp *RestartPolicy) IsNone() bool { + return rp.Name == "no" || rp.Name == "" +} + +// IsAlways indicates whether the container has the "always" restart policy. +// This means the container will automatically restart regardless of the exit status. +func (rp *RestartPolicy) IsAlways() bool { + return rp.Name == "always" +} + +// IsOnFailure indicates whether the container has the "on-failure" restart policy. +// This means the container will automatically restart of exiting with a non-zero exit status. +func (rp *RestartPolicy) IsOnFailure() bool { + return rp.Name == "on-failure" +} + +// IsUnlessStopped indicates whether the container has the +// "unless-stopped" restart policy. This means the container will +// automatically restart unless user has put it to stopped state. +func (rp *RestartPolicy) IsUnlessStopped() bool { + return rp.Name == "unless-stopped" +} + +// IsSame compares two RestartPolicy to see if they are the same +func (rp *RestartPolicy) IsSame(tp *RestartPolicy) bool { + return rp.Name == tp.Name && rp.MaximumRetryCount == tp.MaximumRetryCount +} + +// LogMode is a type to define the available modes for logging +// These modes affect how logs are handled when log messages start piling up. +type LogMode string + +// Available logging modes +const ( + LogModeUnset LogMode = "" + LogModeBlocking LogMode = "blocking" + LogModeNonBlock LogMode = "non-blocking" +) + +// LogConfig represents the logging configuration of the container. +type LogConfig struct { + Type string + Config map[string]string +} + +// Resources contains container's resources (cgroups config, ulimits...) +type Resources struct { + // Applicable to all platforms + CPUShares int64 `json:"CpuShares"` // CPU shares (relative weight vs. other containers) + Memory int64 // Memory limit (in bytes) + NanoCPUs int64 `json:"NanoCpus"` // CPU quota in units of 10-9 CPUs. + + // Applicable to UNIX platforms + CgroupParent string // Parent cgroup. + BlkioWeight uint16 // Block IO weight (relative weight vs. other containers) + BlkioWeightDevice []*blkiodev.WeightDevice + BlkioDeviceReadBps []*blkiodev.ThrottleDevice + BlkioDeviceWriteBps []*blkiodev.ThrottleDevice + BlkioDeviceReadIOps []*blkiodev.ThrottleDevice + BlkioDeviceWriteIOps []*blkiodev.ThrottleDevice + CPUPeriod int64 `json:"CpuPeriod"` // CPU CFS (Completely Fair Scheduler) period + CPUQuota int64 `json:"CpuQuota"` // CPU CFS (Completely Fair Scheduler) quota + CPURealtimePeriod int64 `json:"CpuRealtimePeriod"` // CPU real-time period + CPURealtimeRuntime int64 `json:"CpuRealtimeRuntime"` // CPU real-time runtime + CpusetCpus string // CpusetCpus 0-2, 0,1 + CpusetMems string // CpusetMems 0-2, 0,1 + Devices []DeviceMapping // List of devices to map inside the container + DeviceCgroupRules []string // List of rule to be added to the device cgroup + DeviceRequests []DeviceRequest // List of device requests for device drivers + + // KernelMemory specifies the kernel memory limit (in bytes) for the container. + // Deprecated: kernel 5.4 deprecated kmem.limit_in_bytes. + KernelMemory int64 `json:",omitempty"` + KernelMemoryTCP int64 `json:",omitempty"` // Hard limit for kernel TCP buffer memory (in bytes) + MemoryReservation int64 // Memory soft limit (in bytes) + MemorySwap int64 // Total memory usage (memory + swap); set `-1` to enable unlimited swap + MemorySwappiness *int64 // Tuning container memory swappiness behaviour + OomKillDisable *bool // Whether to disable OOM Killer or not + PidsLimit *int64 // Setting PIDs limit for a container; Set `0` or `-1` for unlimited, or `null` to not change. + Ulimits []*units.Ulimit // List of ulimits to be set in the container + + // Applicable to Windows + CPUCount int64 `json:"CpuCount"` // CPU count + CPUPercent int64 `json:"CpuPercent"` // CPU percent + IOMaximumIOps uint64 // Maximum IOps for the container system drive + IOMaximumBandwidth uint64 // Maximum IO in bytes per second for the container system drive +} + +// UpdateConfig holds the mutable attributes of a Container. +// Those attributes can be updated at runtime. +type UpdateConfig struct { + // Contains container's resources (cgroups, ulimits) + Resources + RestartPolicy RestartPolicy +} + +// HostConfig the non-portable Config structure of a container. +// Here, "non-portable" means "dependent of the host we are running on". +// Portable information *should* appear in Config. +type HostConfig struct { + // Applicable to all platforms + Binds []string // List of volume bindings for this container + ContainerIDFile string // File (path) where the containerId is written + LogConfig LogConfig // Configuration of the logs for this container + NetworkMode NetworkMode // Network mode to use for the container + PortBindings nat.PortMap // Port mapping between the exposed port (container) and the host + RestartPolicy RestartPolicy // Restart policy to be used for the container + AutoRemove bool // Automatically remove container when it exits + VolumeDriver string // Name of the volume driver used to mount volumes + VolumesFrom []string // List of volumes to take from other container + ConsoleSize [2]uint // Initial console size (height,width) + + // Applicable to UNIX platforms + CapAdd strslice.StrSlice // List of kernel capabilities to add to the container + CapDrop strslice.StrSlice // List of kernel capabilities to remove from the container + CgroupnsMode CgroupnsMode // Cgroup namespace mode to use for the container + DNS []string `json:"Dns"` // List of DNS server to lookup + DNSOptions []string `json:"DnsOptions"` // List of DNSOption to look for + DNSSearch []string `json:"DnsSearch"` // List of DNSSearch to look for + ExtraHosts []string // List of extra hosts + GroupAdd []string // List of additional groups that the container process will run as + IpcMode IpcMode // IPC namespace to use for the container + Cgroup CgroupSpec // Cgroup to use for the container + Links []string // List of links (in the name:alias form) + OomScoreAdj int // Container preference for OOM-killing + PidMode PidMode // PID namespace to use for the container + Privileged bool // Is the container in privileged mode + PublishAllPorts bool // Should docker publish all exposed port for the container + ReadonlyRootfs bool // Is the container root filesystem in read-only + SecurityOpt []string // List of string values to customize labels for MLS systems, such as SELinux. + StorageOpt map[string]string `json:",omitempty"` // Storage driver options per container. + Tmpfs map[string]string `json:",omitempty"` // List of tmpfs (mounts) used for the container + UTSMode UTSMode // UTS namespace to use for the container + UsernsMode UsernsMode // The user namespace to use for the container + ShmSize int64 // Total shm memory usage + Sysctls map[string]string `json:",omitempty"` // List of Namespaced sysctls used for the container + Runtime string `json:",omitempty"` // Runtime to use with this container + + // Applicable to Windows + Isolation Isolation // Isolation technology of the container (e.g. default, hyperv) + + // Contains container's resources (cgroups, ulimits) + Resources + + // Mounts specs used by the container + Mounts []mount.Mount `json:",omitempty"` + + // MaskedPaths is the list of paths to be masked inside the container (this overrides the default set of paths) + MaskedPaths []string + + // ReadonlyPaths is the list of paths to be set as read-only inside the container (this overrides the default set of paths) + ReadonlyPaths []string + + // Run a custom init inside the container, if null, use the daemon's configured settings + Init *bool `json:",omitempty"` +} diff --git a/vendor/github.com/docker/docker/api/types/container/hostconfig_unix.go b/vendor/github.com/docker/docker/api/types/container/hostconfig_unix.go new file mode 100644 index 0000000000..24c4fa8d90 --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/container/hostconfig_unix.go @@ -0,0 +1,42 @@ +//go:build !windows +// +build !windows + +package container // import "github.com/docker/docker/api/types/container" + +// IsValid indicates if an isolation technology is valid +func (i Isolation) IsValid() bool { + return i.IsDefault() +} + +// NetworkName returns the name of the network stack. +func (n NetworkMode) NetworkName() string { + if n.IsBridge() { + return "bridge" + } else if n.IsHost() { + return "host" + } else if n.IsContainer() { + return "container" + } else if n.IsNone() { + return "none" + } else if n.IsDefault() { + return "default" + } else if n.IsUserDefined() { + return n.UserDefined() + } + return "" +} + +// IsBridge indicates whether container uses the bridge network stack +func (n NetworkMode) IsBridge() bool { + return n == "bridge" +} + +// IsHost indicates whether container uses the host network stack. +func (n NetworkMode) IsHost() bool { + return n == "host" +} + +// IsUserDefined indicates user-created network +func (n NetworkMode) IsUserDefined() bool { + return !n.IsDefault() && !n.IsBridge() && !n.IsHost() && !n.IsNone() && !n.IsContainer() +} diff --git a/vendor/github.com/docker/docker/api/types/container/hostconfig_windows.go b/vendor/github.com/docker/docker/api/types/container/hostconfig_windows.go new file mode 100644 index 0000000000..99f803a5bb --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/container/hostconfig_windows.go @@ -0,0 +1,40 @@ +package container // import "github.com/docker/docker/api/types/container" + +// IsBridge indicates whether container uses the bridge network stack +// in windows it is given the name NAT +func (n NetworkMode) IsBridge() bool { + return n == "nat" +} + +// IsHost indicates whether container uses the host network stack. +// returns false as this is not supported by windows +func (n NetworkMode) IsHost() bool { + return false +} + +// IsUserDefined indicates user-created network +func (n NetworkMode) IsUserDefined() bool { + return !n.IsDefault() && !n.IsNone() && !n.IsBridge() && !n.IsContainer() +} + +// IsValid indicates if an isolation technology is valid +func (i Isolation) IsValid() bool { + return i.IsDefault() || i.IsHyperV() || i.IsProcess() +} + +// NetworkName returns the name of the network stack. +func (n NetworkMode) NetworkName() string { + if n.IsDefault() { + return "default" + } else if n.IsBridge() { + return "nat" + } else if n.IsNone() { + return "none" + } else if n.IsContainer() { + return "container" + } else if n.IsUserDefined() { + return n.UserDefined() + } + + return "" +} diff --git a/vendor/github.com/docker/docker/api/types/container/wait_exit_error.go b/vendor/github.com/docker/docker/api/types/container/wait_exit_error.go new file mode 100644 index 0000000000..ab56d4eed8 --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/container/wait_exit_error.go @@ -0,0 +1,12 @@ +package container + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +// WaitExitError container waiting error, if any +// swagger:model WaitExitError +type WaitExitError struct { + + // Details of an error + Message string `json:"Message,omitempty"` +} diff --git a/vendor/github.com/docker/docker/api/types/container/wait_response.go b/vendor/github.com/docker/docker/api/types/container/wait_response.go new file mode 100644 index 0000000000..84fc6afddc --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/container/wait_response.go @@ -0,0 +1,18 @@ +package container + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +// WaitResponse ContainerWaitResponse +// +// OK response to ContainerWait operation +// swagger:model WaitResponse +type WaitResponse struct { + + // error + Error *WaitExitError `json:"Error,omitempty"` + + // Exit code of the container + // Required: true + StatusCode int64 `json:"StatusCode"` +} diff --git a/vendor/github.com/docker/docker/api/types/container/waitcondition.go b/vendor/github.com/docker/docker/api/types/container/waitcondition.go new file mode 100644 index 0000000000..cd8311f99c --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/container/waitcondition.go @@ -0,0 +1,22 @@ +package container // import "github.com/docker/docker/api/types/container" + +// WaitCondition is a type used to specify a container state for which +// to wait. +type WaitCondition string + +// Possible WaitCondition Values. +// +// WaitConditionNotRunning (default) is used to wait for any of the non-running +// states: "created", "exited", "dead", "removing", or "removed". +// +// WaitConditionNextExit is used to wait for the next time the state changes +// to a non-running state. If the state is currently "created" or "exited", +// this would cause Wait() to block until either the container runs and exits +// or is removed. +// +// WaitConditionRemoved is used to wait for the container to be removed. +const ( + WaitConditionNotRunning WaitCondition = "not-running" + WaitConditionNextExit WaitCondition = "next-exit" + WaitConditionRemoved WaitCondition = "removed" +) diff --git a/vendor/github.com/docker/docker/api/types/deprecated.go b/vendor/github.com/docker/docker/api/types/deprecated.go new file mode 100644 index 0000000000..216d1df0ff --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/deprecated.go @@ -0,0 +1,14 @@ +package types // import "github.com/docker/docker/api/types" + +import "github.com/docker/docker/api/types/volume" + +// Volume volume +// +// Deprecated: use github.com/docker/docker/api/types/volume.Volume +type Volume = volume.Volume + +// VolumeUsageData Usage details about the volume. This information is used by the +// `GET /system/df` endpoint, and omitted in other endpoints. +// +// Deprecated: use github.com/docker/docker/api/types/volume.UsageData +type VolumeUsageData = volume.UsageData diff --git a/vendor/github.com/docker/docker/api/types/error_response.go b/vendor/github.com/docker/docker/api/types/error_response.go new file mode 100644 index 0000000000..dc942d9d9e --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/error_response.go @@ -0,0 +1,13 @@ +package types + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +// ErrorResponse Represents an error. +// swagger:model ErrorResponse +type ErrorResponse struct { + + // The error message. + // Required: true + Message string `json:"message"` +} diff --git a/vendor/github.com/docker/docker/api/types/error_response_ext.go b/vendor/github.com/docker/docker/api/types/error_response_ext.go new file mode 100644 index 0000000000..f84f034cd5 --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/error_response_ext.go @@ -0,0 +1,6 @@ +package types + +// Error returns the error message +func (e ErrorResponse) Error() string { + return e.Message +} diff --git a/vendor/github.com/docker/docker/api/types/events/events.go b/vendor/github.com/docker/docker/api/types/events/events.go new file mode 100644 index 0000000000..9fe07e26fd --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/events/events.go @@ -0,0 +1,47 @@ +package events // import "github.com/docker/docker/api/types/events" + +// Type is used for event-types. +type Type = string + +// List of known event types. +const ( + BuilderEventType Type = "builder" // BuilderEventType is the event type that the builder generates. + ConfigEventType Type = "config" // ConfigEventType is the event type that configs generate. + ContainerEventType Type = "container" // ContainerEventType is the event type that containers generate. + DaemonEventType Type = "daemon" // DaemonEventType is the event type that daemon generate. + ImageEventType Type = "image" // ImageEventType is the event type that images generate. + NetworkEventType Type = "network" // NetworkEventType is the event type that networks generate. + NodeEventType Type = "node" // NodeEventType is the event type that nodes generate. + PluginEventType Type = "plugin" // PluginEventType is the event type that plugins generate. + SecretEventType Type = "secret" // SecretEventType is the event type that secrets generate. + ServiceEventType Type = "service" // ServiceEventType is the event type that services generate. + VolumeEventType Type = "volume" // VolumeEventType is the event type that volumes generate. +) + +// Actor describes something that generates events, +// like a container, or a network, or a volume. +// It has a defined name and a set of attributes. +// The container attributes are its labels, other actors +// can generate these attributes from other properties. +type Actor struct { + ID string + Attributes map[string]string +} + +// Message represents the information an event contains +type Message struct { + // Deprecated information from JSONMessage. + // With data only in container events. + Status string `json:"status,omitempty"` // Deprecated: use Action instead. + ID string `json:"id,omitempty"` // Deprecated: use Actor.ID instead. + From string `json:"from,omitempty"` // Deprecated: use Actor.Attributes["image"] instead. + + Type Type + Action string + Actor Actor + // Engine events are local scope. Cluster events are swarm scope. + Scope string `json:"scope,omitempty"` + + Time int64 `json:"time,omitempty"` + TimeNano int64 `json:"timeNano,omitempty"` +} diff --git a/vendor/github.com/docker/docker/api/types/filters/parse.go b/vendor/github.com/docker/docker/api/types/filters/parse.go new file mode 100644 index 0000000000..f8fe794074 --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/filters/parse.go @@ -0,0 +1,323 @@ +/* +Package filters provides tools for encoding a mapping of keys to a set of +multiple values. +*/ +package filters // import "github.com/docker/docker/api/types/filters" + +import ( + "encoding/json" + "regexp" + "strings" + + "github.com/docker/docker/api/types/versions" + "github.com/pkg/errors" +) + +// Args stores a mapping of keys to a set of multiple values. +type Args struct { + fields map[string]map[string]bool +} + +// KeyValuePair are used to initialize a new Args +type KeyValuePair struct { + Key string + Value string +} + +// Arg creates a new KeyValuePair for initializing Args +func Arg(key, value string) KeyValuePair { + return KeyValuePair{Key: key, Value: value} +} + +// NewArgs returns a new Args populated with the initial args +func NewArgs(initialArgs ...KeyValuePair) Args { + args := Args{fields: map[string]map[string]bool{}} + for _, arg := range initialArgs { + args.Add(arg.Key, arg.Value) + } + return args +} + +// Keys returns all the keys in list of Args +func (args Args) Keys() []string { + keys := make([]string, 0, len(args.fields)) + for k := range args.fields { + keys = append(keys, k) + } + return keys +} + +// MarshalJSON returns a JSON byte representation of the Args +func (args Args) MarshalJSON() ([]byte, error) { + if len(args.fields) == 0 { + return []byte("{}"), nil + } + return json.Marshal(args.fields) +} + +// ToJSON returns the Args as a JSON encoded string +func ToJSON(a Args) (string, error) { + if a.Len() == 0 { + return "", nil + } + buf, err := json.Marshal(a) + return string(buf), err +} + +// ToParamWithVersion encodes Args as a JSON string. If version is less than 1.22 +// then the encoded format will use an older legacy format where the values are a +// list of strings, instead of a set. +// +// Deprecated: do not use in any new code; use ToJSON instead +func ToParamWithVersion(version string, a Args) (string, error) { + if a.Len() == 0 { + return "", nil + } + + if version != "" && versions.LessThan(version, "1.22") { + buf, err := json.Marshal(convertArgsToSlice(a.fields)) + return string(buf), err + } + + return ToJSON(a) +} + +// FromJSON decodes a JSON encoded string into Args +func FromJSON(p string) (Args, error) { + args := NewArgs() + + if p == "" { + return args, nil + } + + raw := []byte(p) + err := json.Unmarshal(raw, &args) + if err == nil { + return args, nil + } + + // Fallback to parsing arguments in the legacy slice format + deprecated := map[string][]string{} + if legacyErr := json.Unmarshal(raw, &deprecated); legacyErr != nil { + return args, invalidFilter{errors.Wrap(err, "invalid filter")} + } + + args.fields = deprecatedArgs(deprecated) + return args, nil +} + +// UnmarshalJSON populates the Args from JSON encode bytes +func (args Args) UnmarshalJSON(raw []byte) error { + return json.Unmarshal(raw, &args.fields) +} + +// Get returns the list of values associated with the key +func (args Args) Get(key string) []string { + values := args.fields[key] + if values == nil { + return make([]string, 0) + } + slice := make([]string, 0, len(values)) + for key := range values { + slice = append(slice, key) + } + return slice +} + +// Add a new value to the set of values +func (args Args) Add(key, value string) { + if _, ok := args.fields[key]; ok { + args.fields[key][value] = true + } else { + args.fields[key] = map[string]bool{value: true} + } +} + +// Del removes a value from the set +func (args Args) Del(key, value string) { + if _, ok := args.fields[key]; ok { + delete(args.fields[key], value) + if len(args.fields[key]) == 0 { + delete(args.fields, key) + } + } +} + +// Len returns the number of keys in the mapping +func (args Args) Len() int { + return len(args.fields) +} + +// MatchKVList returns true if all the pairs in sources exist as key=value +// pairs in the mapping at key, or if there are no values at key. +func (args Args) MatchKVList(key string, sources map[string]string) bool { + fieldValues := args.fields[key] + + // do not filter if there is no filter set or cannot determine filter + if len(fieldValues) == 0 { + return true + } + + if len(sources) == 0 { + return false + } + + for value := range fieldValues { + testKV := strings.SplitN(value, "=", 2) + + v, ok := sources[testKV[0]] + if !ok { + return false + } + if len(testKV) == 2 && testKV[1] != v { + return false + } + } + + return true +} + +// Match returns true if any of the values at key match the source string +func (args Args) Match(field, source string) bool { + if args.ExactMatch(field, source) { + return true + } + + fieldValues := args.fields[field] + for name2match := range fieldValues { + match, err := regexp.MatchString(name2match, source) + if err != nil { + continue + } + if match { + return true + } + } + return false +} + +// ExactMatch returns true if the source matches exactly one of the values. +func (args Args) ExactMatch(key, source string) bool { + fieldValues, ok := args.fields[key] + // do not filter if there is no filter set or cannot determine filter + if !ok || len(fieldValues) == 0 { + return true + } + + // try to match full name value to avoid O(N) regular expression matching + return fieldValues[source] +} + +// UniqueExactMatch returns true if there is only one value and the source +// matches exactly the value. +func (args Args) UniqueExactMatch(key, source string) bool { + fieldValues := args.fields[key] + // do not filter if there is no filter set or cannot determine filter + if len(fieldValues) == 0 { + return true + } + if len(args.fields[key]) != 1 { + return false + } + + // try to match full name value to avoid O(N) regular expression matching + return fieldValues[source] +} + +// FuzzyMatch returns true if the source matches exactly one value, or the +// source has one of the values as a prefix. +func (args Args) FuzzyMatch(key, source string) bool { + if args.ExactMatch(key, source) { + return true + } + + fieldValues := args.fields[key] + for prefix := range fieldValues { + if strings.HasPrefix(source, prefix) { + return true + } + } + return false +} + +// Contains returns true if the key exists in the mapping +func (args Args) Contains(field string) bool { + _, ok := args.fields[field] + return ok +} + +type invalidFilter struct{ error } + +func (e invalidFilter) Error() string { + return e.error.Error() +} + +func (invalidFilter) InvalidParameter() {} + +// Validate compared the set of accepted keys against the keys in the mapping. +// An error is returned if any mapping keys are not in the accepted set. +func (args Args) Validate(accepted map[string]bool) error { + for name := range args.fields { + if !accepted[name] { + return invalidFilter{errors.New("invalid filter '" + name + "'")} + } + } + return nil +} + +// WalkValues iterates over the list of values for a key in the mapping and calls +// op() for each value. If op returns an error the iteration stops and the +// error is returned. +func (args Args) WalkValues(field string, op func(value string) error) error { + if _, ok := args.fields[field]; !ok { + return nil + } + for v := range args.fields[field] { + if err := op(v); err != nil { + return err + } + } + return nil +} + +// Clone returns a copy of args. +func (args Args) Clone() (newArgs Args) { + newArgs.fields = make(map[string]map[string]bool, len(args.fields)) + for k, m := range args.fields { + var mm map[string]bool + if m != nil { + mm = make(map[string]bool, len(m)) + for kk, v := range m { + mm[kk] = v + } + } + newArgs.fields[k] = mm + } + return newArgs +} + +func deprecatedArgs(d map[string][]string) map[string]map[string]bool { + m := map[string]map[string]bool{} + for k, v := range d { + values := map[string]bool{} + for _, vv := range v { + values[vv] = true + } + m[k] = values + } + return m +} + +func convertArgsToSlice(f map[string]map[string]bool) map[string][]string { + m := map[string][]string{} + for k, v := range f { + values := []string{} + for kk := range v { + if v[kk] { + values = append(values, kk) + } + } + m[k] = values + } + return m +} diff --git a/vendor/github.com/docker/docker/api/types/graph_driver_data.go b/vendor/github.com/docker/docker/api/types/graph_driver_data.go new file mode 100644 index 0000000000..ce3deb331c --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/graph_driver_data.go @@ -0,0 +1,23 @@ +package types + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +// GraphDriverData Information about the storage driver used to store the container's and +// image's filesystem. +// +// swagger:model GraphDriverData +type GraphDriverData struct { + + // Low-level storage metadata, provided as key/value pairs. + // + // This information is driver-specific, and depends on the storage-driver + // in use, and should be used for informational purposes only. + // + // Required: true + Data map[string]string `json:"Data"` + + // Name of the storage driver. + // Required: true + Name string `json:"Name"` +} diff --git a/vendor/github.com/docker/docker/api/types/id_response.go b/vendor/github.com/docker/docker/api/types/id_response.go new file mode 100644 index 0000000000..7592d2f8b1 --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/id_response.go @@ -0,0 +1,13 @@ +package types + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +// IDResponse Response to an API call that returns just an Id +// swagger:model IdResponse +type IDResponse struct { + + // The id of the newly created object. + // Required: true + ID string `json:"Id"` +} diff --git a/vendor/github.com/docker/docker/api/types/image/image_history.go b/vendor/github.com/docker/docker/api/types/image/image_history.go new file mode 100644 index 0000000000..e302bb0aeb --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/image/image_history.go @@ -0,0 +1,36 @@ +package image // import "github.com/docker/docker/api/types/image" + +// ---------------------------------------------------------------------------- +// Code generated by `swagger generate operation`. DO NOT EDIT. +// +// See hack/generate-swagger-api.sh +// ---------------------------------------------------------------------------- + +// HistoryResponseItem individual image layer information in response to ImageHistory operation +// swagger:model HistoryResponseItem +type HistoryResponseItem struct { + + // comment + // Required: true + Comment string `json:"Comment"` + + // created + // Required: true + Created int64 `json:"Created"` + + // created by + // Required: true + CreatedBy string `json:"CreatedBy"` + + // Id + // Required: true + ID string `json:"Id"` + + // size + // Required: true + Size int64 `json:"Size"` + + // tags + // Required: true + Tags []string `json:"Tags"` +} diff --git a/vendor/github.com/docker/docker/api/types/image_delete_response_item.go b/vendor/github.com/docker/docker/api/types/image_delete_response_item.go new file mode 100644 index 0000000000..b9a65a0d8e --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/image_delete_response_item.go @@ -0,0 +1,15 @@ +package types + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +// ImageDeleteResponseItem image delete response item +// swagger:model ImageDeleteResponseItem +type ImageDeleteResponseItem struct { + + // The image ID of an image that was deleted + Deleted string `json:"Deleted,omitempty"` + + // The image ID of an image that was untagged + Untagged string `json:"Untagged,omitempty"` +} diff --git a/vendor/github.com/docker/docker/api/types/image_summary.go b/vendor/github.com/docker/docker/api/types/image_summary.go new file mode 100644 index 0000000000..90b983a25c --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/image_summary.go @@ -0,0 +1,97 @@ +package types + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +// ImageSummary image summary +// swagger:model ImageSummary +type ImageSummary struct { + + // Number of containers using this image. Includes both stopped and running + // containers. + // + // This size is not calculated by default, and depends on which API endpoint + // is used. `-1` indicates that the value has not been set / calculated. + // + // Required: true + Containers int64 `json:"Containers"` + + // Date and time at which the image was created as a Unix timestamp + // (number of seconds sinds EPOCH). + // + // Required: true + Created int64 `json:"Created"` + + // ID is the content-addressable ID of an image. + // + // This identifier is a content-addressable digest calculated from the + // image's configuration (which includes the digests of layers used by + // the image). + // + // Note that this digest differs from the `RepoDigests` below, which + // holds digests of image manifests that reference the image. + // + // Required: true + ID string `json:"Id"` + + // User-defined key/value metadata. + // Required: true + Labels map[string]string `json:"Labels"` + + // ID of the parent image. + // + // Depending on how the image was created, this field may be empty and + // is only set for images that were built/created locally. This field + // is empty if the image was pulled from an image registry. + // + // Required: true + ParentID string `json:"ParentId"` + + // List of content-addressable digests of locally available image manifests + // that the image is referenced from. Multiple manifests can refer to the + // same image. + // + // These digests are usually only available if the image was either pulled + // from a registry, or if the image was pushed to a registry, which is when + // the manifest is generated and its digest calculated. + // + // Required: true + RepoDigests []string `json:"RepoDigests"` + + // List of image names/tags in the local image cache that reference this + // image. + // + // Multiple image tags can refer to the same image, and this list may be + // empty if no tags reference the image, in which case the image is + // "untagged", in which case it can still be referenced by its ID. + // + // Required: true + RepoTags []string `json:"RepoTags"` + + // Total size of image layers that are shared between this image and other + // images. + // + // This size is not calculated by default. `-1` indicates that the value + // has not been set / calculated. + // + // Required: true + SharedSize int64 `json:"SharedSize"` + + // Total size of the image including all layers it is composed of. + // + // Required: true + Size int64 `json:"Size"` + + // Total size of the image including all layers it is composed of. + // + // In versions of Docker before v1.10, this field was calculated from + // the image itself and all of its parent images. Docker v1.10 and up + // store images self-contained, and no longer use a parent-chain, making + // this field an equivalent of the Size field. + // + // This field is kept for backward compatibility, but may be removed in + // a future version of the API. + // + // Required: true + VirtualSize int64 `json:"VirtualSize"` +} diff --git a/vendor/github.com/docker/docker/api/types/mount/mount.go b/vendor/github.com/docker/docker/api/types/mount/mount.go new file mode 100644 index 0000000000..ac4ce62231 --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/mount/mount.go @@ -0,0 +1,140 @@ +package mount // import "github.com/docker/docker/api/types/mount" + +import ( + "os" +) + +// Type represents the type of a mount. +type Type string + +// Type constants +const ( + // TypeBind is the type for mounting host dir + TypeBind Type = "bind" + // TypeVolume is the type for remote storage volumes + TypeVolume Type = "volume" + // TypeTmpfs is the type for mounting tmpfs + TypeTmpfs Type = "tmpfs" + // TypeNamedPipe is the type for mounting Windows named pipes + TypeNamedPipe Type = "npipe" + // TypeCluster is the type for Swarm Cluster Volumes. + TypeCluster Type = "cluster" +) + +// Mount represents a mount (volume). +type Mount struct { + Type Type `json:",omitempty"` + // Source specifies the name of the mount. Depending on mount type, this + // may be a volume name or a host path, or even ignored. + // Source is not supported for tmpfs (must be an empty value) + Source string `json:",omitempty"` + Target string `json:",omitempty"` + ReadOnly bool `json:",omitempty"` + Consistency Consistency `json:",omitempty"` + + BindOptions *BindOptions `json:",omitempty"` + VolumeOptions *VolumeOptions `json:",omitempty"` + TmpfsOptions *TmpfsOptions `json:",omitempty"` + ClusterOptions *ClusterOptions `json:",omitempty"` +} + +// Propagation represents the propagation of a mount. +type Propagation string + +const ( + // PropagationRPrivate RPRIVATE + PropagationRPrivate Propagation = "rprivate" + // PropagationPrivate PRIVATE + PropagationPrivate Propagation = "private" + // PropagationRShared RSHARED + PropagationRShared Propagation = "rshared" + // PropagationShared SHARED + PropagationShared Propagation = "shared" + // PropagationRSlave RSLAVE + PropagationRSlave Propagation = "rslave" + // PropagationSlave SLAVE + PropagationSlave Propagation = "slave" +) + +// Propagations is the list of all valid mount propagations +var Propagations = []Propagation{ + PropagationRPrivate, + PropagationPrivate, + PropagationRShared, + PropagationShared, + PropagationRSlave, + PropagationSlave, +} + +// Consistency represents the consistency requirements of a mount. +type Consistency string + +const ( + // ConsistencyFull guarantees bind mount-like consistency + ConsistencyFull Consistency = "consistent" + // ConsistencyCached mounts can cache read data and FS structure + ConsistencyCached Consistency = "cached" + // ConsistencyDelegated mounts can cache read and written data and structure + ConsistencyDelegated Consistency = "delegated" + // ConsistencyDefault provides "consistent" behavior unless overridden + ConsistencyDefault Consistency = "default" +) + +// BindOptions defines options specific to mounts of type "bind". +type BindOptions struct { + Propagation Propagation `json:",omitempty"` + NonRecursive bool `json:",omitempty"` + CreateMountpoint bool `json:",omitempty"` +} + +// VolumeOptions represents the options for a mount of type volume. +type VolumeOptions struct { + NoCopy bool `json:",omitempty"` + Labels map[string]string `json:",omitempty"` + DriverConfig *Driver `json:",omitempty"` +} + +// Driver represents a volume driver. +type Driver struct { + Name string `json:",omitempty"` + Options map[string]string `json:",omitempty"` +} + +// TmpfsOptions defines options specific to mounts of type "tmpfs". +type TmpfsOptions struct { + // Size sets the size of the tmpfs, in bytes. + // + // This will be converted to an operating system specific value + // depending on the host. For example, on linux, it will be converted to + // use a 'k', 'm' or 'g' syntax. BSD, though not widely supported with + // docker, uses a straight byte value. + // + // Percentages are not supported. + SizeBytes int64 `json:",omitempty"` + // Mode of the tmpfs upon creation + Mode os.FileMode `json:",omitempty"` + + // TODO(stevvooe): There are several more tmpfs flags, specified in the + // daemon, that are accepted. Only the most basic are added for now. + // + // From https://github.com/moby/sys/blob/mount/v0.1.1/mount/flags.go#L47-L56 + // + // var validFlags = map[string]bool{ + // "": true, + // "size": true, X + // "mode": true, X + // "uid": true, + // "gid": true, + // "nr_inodes": true, + // "nr_blocks": true, + // "mpol": true, + // } + // + // Some of these may be straightforward to add, but others, such as + // uid/gid have implications in a clustered system. +} + +// ClusterOptions specifies options for a Cluster volume. +type ClusterOptions struct { + // intentionally empty +} diff --git a/vendor/github.com/docker/docker/api/types/network/network.go b/vendor/github.com/docker/docker/api/types/network/network.go new file mode 100644 index 0000000000..437b184c67 --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/network/network.go @@ -0,0 +1,126 @@ +package network // import "github.com/docker/docker/api/types/network" +import ( + "github.com/docker/docker/api/types/filters" +) + +// Address represents an IP address +type Address struct { + Addr string + PrefixLen int +} + +// IPAM represents IP Address Management +type IPAM struct { + Driver string + Options map[string]string // Per network IPAM driver options + Config []IPAMConfig +} + +// IPAMConfig represents IPAM configurations +type IPAMConfig struct { + Subnet string `json:",omitempty"` + IPRange string `json:",omitempty"` + Gateway string `json:",omitempty"` + AuxAddress map[string]string `json:"AuxiliaryAddresses,omitempty"` +} + +// EndpointIPAMConfig represents IPAM configurations for the endpoint +type EndpointIPAMConfig struct { + IPv4Address string `json:",omitempty"` + IPv6Address string `json:",omitempty"` + LinkLocalIPs []string `json:",omitempty"` +} + +// Copy makes a copy of the endpoint ipam config +func (cfg *EndpointIPAMConfig) Copy() *EndpointIPAMConfig { + cfgCopy := *cfg + cfgCopy.LinkLocalIPs = make([]string, 0, len(cfg.LinkLocalIPs)) + cfgCopy.LinkLocalIPs = append(cfgCopy.LinkLocalIPs, cfg.LinkLocalIPs...) + return &cfgCopy +} + +// PeerInfo represents one peer of an overlay network +type PeerInfo struct { + Name string + IP string +} + +// EndpointSettings stores the network endpoint details +type EndpointSettings struct { + // Configurations + IPAMConfig *EndpointIPAMConfig + Links []string + Aliases []string + // Operational data + NetworkID string + EndpointID string + Gateway string + IPAddress string + IPPrefixLen int + IPv6Gateway string + GlobalIPv6Address string + GlobalIPv6PrefixLen int + MacAddress string + DriverOpts map[string]string +} + +// Task carries the information about one backend task +type Task struct { + Name string + EndpointID string + EndpointIP string + Info map[string]string +} + +// ServiceInfo represents service parameters with the list of service's tasks +type ServiceInfo struct { + VIP string + Ports []string + LocalLBIndex int + Tasks []Task +} + +// Copy makes a deep copy of `EndpointSettings` +func (es *EndpointSettings) Copy() *EndpointSettings { + epCopy := *es + if es.IPAMConfig != nil { + epCopy.IPAMConfig = es.IPAMConfig.Copy() + } + + if es.Links != nil { + links := make([]string, 0, len(es.Links)) + epCopy.Links = append(links, es.Links...) + } + + if es.Aliases != nil { + aliases := make([]string, 0, len(es.Aliases)) + epCopy.Aliases = append(aliases, es.Aliases...) + } + return &epCopy +} + +// NetworkingConfig represents the container's networking configuration for each of its interfaces +// Carries the networking configs specified in the `docker run` and `docker network connect` commands +type NetworkingConfig struct { + EndpointsConfig map[string]*EndpointSettings // Endpoint configs for each connecting network +} + +// ConfigReference specifies the source which provides a network's configuration +type ConfigReference struct { + Network string +} + +var acceptedFilters = map[string]bool{ + "dangling": true, + "driver": true, + "id": true, + "label": true, + "name": true, + "scope": true, + "type": true, +} + +// ValidateFilters validates the list of filter args with the available filters. +func ValidateFilters(filter filters.Args) error { + return filter.Validate(acceptedFilters) +} diff --git a/vendor/github.com/docker/docker/api/types/plugin.go b/vendor/github.com/docker/docker/api/types/plugin.go new file mode 100644 index 0000000000..abae48b9ab --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/plugin.go @@ -0,0 +1,203 @@ +package types + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +// Plugin A plugin for the Engine API +// swagger:model Plugin +type Plugin struct { + + // config + // Required: true + Config PluginConfig `json:"Config"` + + // True if the plugin is running. False if the plugin is not running, only installed. + // Required: true + Enabled bool `json:"Enabled"` + + // Id + ID string `json:"Id,omitempty"` + + // name + // Required: true + Name string `json:"Name"` + + // plugin remote reference used to push/pull the plugin + PluginReference string `json:"PluginReference,omitempty"` + + // settings + // Required: true + Settings PluginSettings `json:"Settings"` +} + +// PluginConfig The config of a plugin. +// swagger:model PluginConfig +type PluginConfig struct { + + // args + // Required: true + Args PluginConfigArgs `json:"Args"` + + // description + // Required: true + Description string `json:"Description"` + + // Docker Version used to create the plugin + DockerVersion string `json:"DockerVersion,omitempty"` + + // documentation + // Required: true + Documentation string `json:"Documentation"` + + // entrypoint + // Required: true + Entrypoint []string `json:"Entrypoint"` + + // env + // Required: true + Env []PluginEnv `json:"Env"` + + // interface + // Required: true + Interface PluginConfigInterface `json:"Interface"` + + // ipc host + // Required: true + IpcHost bool `json:"IpcHost"` + + // linux + // Required: true + Linux PluginConfigLinux `json:"Linux"` + + // mounts + // Required: true + Mounts []PluginMount `json:"Mounts"` + + // network + // Required: true + Network PluginConfigNetwork `json:"Network"` + + // pid host + // Required: true + PidHost bool `json:"PidHost"` + + // propagated mount + // Required: true + PropagatedMount string `json:"PropagatedMount"` + + // user + User PluginConfigUser `json:"User,omitempty"` + + // work dir + // Required: true + WorkDir string `json:"WorkDir"` + + // rootfs + Rootfs *PluginConfigRootfs `json:"rootfs,omitempty"` +} + +// PluginConfigArgs plugin config args +// swagger:model PluginConfigArgs +type PluginConfigArgs struct { + + // description + // Required: true + Description string `json:"Description"` + + // name + // Required: true + Name string `json:"Name"` + + // settable + // Required: true + Settable []string `json:"Settable"` + + // value + // Required: true + Value []string `json:"Value"` +} + +// PluginConfigInterface The interface between Docker and the plugin +// swagger:model PluginConfigInterface +type PluginConfigInterface struct { + + // Protocol to use for clients connecting to the plugin. + ProtocolScheme string `json:"ProtocolScheme,omitempty"` + + // socket + // Required: true + Socket string `json:"Socket"` + + // types + // Required: true + Types []PluginInterfaceType `json:"Types"` +} + +// PluginConfigLinux plugin config linux +// swagger:model PluginConfigLinux +type PluginConfigLinux struct { + + // allow all devices + // Required: true + AllowAllDevices bool `json:"AllowAllDevices"` + + // capabilities + // Required: true + Capabilities []string `json:"Capabilities"` + + // devices + // Required: true + Devices []PluginDevice `json:"Devices"` +} + +// PluginConfigNetwork plugin config network +// swagger:model PluginConfigNetwork +type PluginConfigNetwork struct { + + // type + // Required: true + Type string `json:"Type"` +} + +// PluginConfigRootfs plugin config rootfs +// swagger:model PluginConfigRootfs +type PluginConfigRootfs struct { + + // diff ids + DiffIds []string `json:"diff_ids"` + + // type + Type string `json:"type,omitempty"` +} + +// PluginConfigUser plugin config user +// swagger:model PluginConfigUser +type PluginConfigUser struct { + + // g ID + GID uint32 `json:"GID,omitempty"` + + // UID + UID uint32 `json:"UID,omitempty"` +} + +// PluginSettings Settings that can be modified by users. +// swagger:model PluginSettings +type PluginSettings struct { + + // args + // Required: true + Args []string `json:"Args"` + + // devices + // Required: true + Devices []PluginDevice `json:"Devices"` + + // env + // Required: true + Env []string `json:"Env"` + + // mounts + // Required: true + Mounts []PluginMount `json:"Mounts"` +} diff --git a/vendor/github.com/docker/docker/api/types/plugin_device.go b/vendor/github.com/docker/docker/api/types/plugin_device.go new file mode 100644 index 0000000000..5699010675 --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/plugin_device.go @@ -0,0 +1,25 @@ +package types + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +// PluginDevice plugin device +// swagger:model PluginDevice +type PluginDevice struct { + + // description + // Required: true + Description string `json:"Description"` + + // name + // Required: true + Name string `json:"Name"` + + // path + // Required: true + Path *string `json:"Path"` + + // settable + // Required: true + Settable []string `json:"Settable"` +} diff --git a/vendor/github.com/docker/docker/api/types/plugin_env.go b/vendor/github.com/docker/docker/api/types/plugin_env.go new file mode 100644 index 0000000000..32962dc2eb --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/plugin_env.go @@ -0,0 +1,25 @@ +package types + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +// PluginEnv plugin env +// swagger:model PluginEnv +type PluginEnv struct { + + // description + // Required: true + Description string `json:"Description"` + + // name + // Required: true + Name string `json:"Name"` + + // settable + // Required: true + Settable []string `json:"Settable"` + + // value + // Required: true + Value *string `json:"Value"` +} diff --git a/vendor/github.com/docker/docker/api/types/plugin_interface_type.go b/vendor/github.com/docker/docker/api/types/plugin_interface_type.go new file mode 100644 index 0000000000..c82f204e87 --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/plugin_interface_type.go @@ -0,0 +1,21 @@ +package types + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +// PluginInterfaceType plugin interface type +// swagger:model PluginInterfaceType +type PluginInterfaceType struct { + + // capability + // Required: true + Capability string `json:"Capability"` + + // prefix + // Required: true + Prefix string `json:"Prefix"` + + // version + // Required: true + Version string `json:"Version"` +} diff --git a/vendor/github.com/docker/docker/api/types/plugin_mount.go b/vendor/github.com/docker/docker/api/types/plugin_mount.go new file mode 100644 index 0000000000..5c031cf8b5 --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/plugin_mount.go @@ -0,0 +1,37 @@ +package types + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +// PluginMount plugin mount +// swagger:model PluginMount +type PluginMount struct { + + // description + // Required: true + Description string `json:"Description"` + + // destination + // Required: true + Destination string `json:"Destination"` + + // name + // Required: true + Name string `json:"Name"` + + // options + // Required: true + Options []string `json:"Options"` + + // settable + // Required: true + Settable []string `json:"Settable"` + + // source + // Required: true + Source *string `json:"Source"` + + // type + // Required: true + Type string `json:"Type"` +} diff --git a/vendor/github.com/docker/docker/api/types/plugin_responses.go b/vendor/github.com/docker/docker/api/types/plugin_responses.go new file mode 100644 index 0000000000..60d1fb5ad8 --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/plugin_responses.go @@ -0,0 +1,71 @@ +package types // import "github.com/docker/docker/api/types" + +import ( + "encoding/json" + "fmt" + "sort" +) + +// PluginsListResponse contains the response for the Engine API +type PluginsListResponse []*Plugin + +// UnmarshalJSON implements json.Unmarshaler for PluginInterfaceType +func (t *PluginInterfaceType) UnmarshalJSON(p []byte) error { + versionIndex := len(p) + prefixIndex := 0 + if len(p) < 2 || p[0] != '"' || p[len(p)-1] != '"' { + return fmt.Errorf("%q is not a plugin interface type", p) + } + p = p[1 : len(p)-1] +loop: + for i, b := range p { + switch b { + case '.': + prefixIndex = i + case '/': + versionIndex = i + break loop + } + } + t.Prefix = string(p[:prefixIndex]) + t.Capability = string(p[prefixIndex+1 : versionIndex]) + if versionIndex < len(p) { + t.Version = string(p[versionIndex+1:]) + } + return nil +} + +// MarshalJSON implements json.Marshaler for PluginInterfaceType +func (t *PluginInterfaceType) MarshalJSON() ([]byte, error) { + return json.Marshal(t.String()) +} + +// String implements fmt.Stringer for PluginInterfaceType +func (t PluginInterfaceType) String() string { + return fmt.Sprintf("%s.%s/%s", t.Prefix, t.Capability, t.Version) +} + +// PluginPrivilege describes a permission the user has to accept +// upon installing a plugin. +type PluginPrivilege struct { + Name string + Description string + Value []string +} + +// PluginPrivileges is a list of PluginPrivilege +type PluginPrivileges []PluginPrivilege + +func (s PluginPrivileges) Len() int { + return len(s) +} + +func (s PluginPrivileges) Less(i, j int) bool { + return s[i].Name < s[j].Name +} + +func (s PluginPrivileges) Swap(i, j int) { + sort.Strings(s[i].Value) + sort.Strings(s[j].Value) + s[i], s[j] = s[j], s[i] +} diff --git a/vendor/github.com/docker/docker/api/types/port.go b/vendor/github.com/docker/docker/api/types/port.go new file mode 100644 index 0000000000..d91234744c --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/port.go @@ -0,0 +1,23 @@ +package types + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +// Port An open port on a container +// swagger:model Port +type Port struct { + + // Host IP address that the container's port is mapped to + IP string `json:"IP,omitempty"` + + // Port on the container + // Required: true + PrivatePort uint16 `json:"PrivatePort"` + + // Port exposed on the host + PublicPort uint16 `json:"PublicPort,omitempty"` + + // type + // Required: true + Type string `json:"Type"` +} diff --git a/vendor/github.com/docker/docker/api/types/registry/authenticate.go b/vendor/github.com/docker/docker/api/types/registry/authenticate.go new file mode 100644 index 0000000000..f0a2113e40 --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/registry/authenticate.go @@ -0,0 +1,21 @@ +package registry // import "github.com/docker/docker/api/types/registry" + +// ---------------------------------------------------------------------------- +// DO NOT EDIT THIS FILE +// This file was generated by `swagger generate operation` +// +// See hack/generate-swagger-api.sh +// ---------------------------------------------------------------------------- + +// AuthenticateOKBody authenticate o k body +// swagger:model AuthenticateOKBody +type AuthenticateOKBody struct { + + // An opaque token used to authenticate a user after a successful login + // Required: true + IdentityToken string `json:"IdentityToken"` + + // The status of the authentication + // Required: true + Status string `json:"Status"` +} diff --git a/vendor/github.com/docker/docker/api/types/registry/registry.go b/vendor/github.com/docker/docker/api/types/registry/registry.go new file mode 100644 index 0000000000..62a88f5be8 --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/registry/registry.go @@ -0,0 +1,120 @@ +package registry // import "github.com/docker/docker/api/types/registry" + +import ( + "encoding/json" + "net" + + v1 "github.com/opencontainers/image-spec/specs-go/v1" +) + +// ServiceConfig stores daemon registry services configuration. +type ServiceConfig struct { + AllowNondistributableArtifactsCIDRs []*NetIPNet + AllowNondistributableArtifactsHostnames []string + InsecureRegistryCIDRs []*NetIPNet `json:"InsecureRegistryCIDRs"` + IndexConfigs map[string]*IndexInfo `json:"IndexConfigs"` + Mirrors []string +} + +// NetIPNet is the net.IPNet type, which can be marshalled and +// unmarshalled to JSON +type NetIPNet net.IPNet + +// String returns the CIDR notation of ipnet +func (ipnet *NetIPNet) String() string { + return (*net.IPNet)(ipnet).String() +} + +// MarshalJSON returns the JSON representation of the IPNet +func (ipnet *NetIPNet) MarshalJSON() ([]byte, error) { + return json.Marshal((*net.IPNet)(ipnet).String()) +} + +// UnmarshalJSON sets the IPNet from a byte array of JSON +func (ipnet *NetIPNet) UnmarshalJSON(b []byte) (err error) { + var ipnetStr string + if err = json.Unmarshal(b, &ipnetStr); err == nil { + var cidr *net.IPNet + if _, cidr, err = net.ParseCIDR(ipnetStr); err == nil { + *ipnet = NetIPNet(*cidr) + } + } + return +} + +// IndexInfo contains information about a registry +// +// RepositoryInfo Examples: +// +// { +// "Index" : { +// "Name" : "docker.io", +// "Mirrors" : ["https://registry-2.docker.io/v1/", "https://registry-3.docker.io/v1/"], +// "Secure" : true, +// "Official" : true, +// }, +// "RemoteName" : "library/debian", +// "LocalName" : "debian", +// "CanonicalName" : "docker.io/debian" +// "Official" : true, +// } +// +// { +// "Index" : { +// "Name" : "127.0.0.1:5000", +// "Mirrors" : [], +// "Secure" : false, +// "Official" : false, +// }, +// "RemoteName" : "user/repo", +// "LocalName" : "127.0.0.1:5000/user/repo", +// "CanonicalName" : "127.0.0.1:5000/user/repo", +// "Official" : false, +// } +type IndexInfo struct { + // Name is the name of the registry, such as "docker.io" + Name string + // Mirrors is a list of mirrors, expressed as URIs + Mirrors []string + // Secure is set to false if the registry is part of the list of + // insecure registries. Insecure registries accept HTTP and/or accept + // HTTPS with certificates from unknown CAs. + Secure bool + // Official indicates whether this is an official registry + Official bool +} + +// SearchResult describes a search result returned from a registry +type SearchResult struct { + // StarCount indicates the number of stars this repository has + StarCount int `json:"star_count"` + // IsOfficial is true if the result is from an official repository. + IsOfficial bool `json:"is_official"` + // Name is the name of the repository + Name string `json:"name"` + // IsAutomated indicates whether the result is automated + IsAutomated bool `json:"is_automated"` + // Description is a textual description of the repository + Description string `json:"description"` +} + +// SearchResults lists a collection search results returned from a registry +type SearchResults struct { + // Query contains the query string that generated the search results + Query string `json:"query"` + // NumResults indicates the number of results the query returned + NumResults int `json:"num_results"` + // Results is a slice containing the actual results for the search + Results []SearchResult `json:"results"` +} + +// DistributionInspect describes the result obtained from contacting the +// registry to retrieve image metadata +type DistributionInspect struct { + // Descriptor contains information about the manifest, including + // the content addressable digest + Descriptor v1.Descriptor + // Platforms contains the list of platforms supported by the image, + // obtained by parsing the manifest + Platforms []v1.Platform +} diff --git a/vendor/github.com/docker/docker/api/types/service_update_response.go b/vendor/github.com/docker/docker/api/types/service_update_response.go new file mode 100644 index 0000000000..74ea64b1bb --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/service_update_response.go @@ -0,0 +1,12 @@ +package types + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +// ServiceUpdateResponse service update response +// swagger:model ServiceUpdateResponse +type ServiceUpdateResponse struct { + + // Optional warning messages + Warnings []string `json:"Warnings"` +} diff --git a/vendor/github.com/docker/docker/api/types/stats.go b/vendor/github.com/docker/docker/api/types/stats.go new file mode 100644 index 0000000000..20daebed14 --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/stats.go @@ -0,0 +1,181 @@ +// Package types is used for API stability in the types and response to the +// consumers of the API stats endpoint. +package types // import "github.com/docker/docker/api/types" + +import "time" + +// ThrottlingData stores CPU throttling stats of one running container. +// Not used on Windows. +type ThrottlingData struct { + // Number of periods with throttling active + Periods uint64 `json:"periods"` + // Number of periods when the container hits its throttling limit. + ThrottledPeriods uint64 `json:"throttled_periods"` + // Aggregate time the container was throttled for in nanoseconds. + ThrottledTime uint64 `json:"throttled_time"` +} + +// CPUUsage stores All CPU stats aggregated since container inception. +type CPUUsage struct { + // Total CPU time consumed. + // Units: nanoseconds (Linux) + // Units: 100's of nanoseconds (Windows) + TotalUsage uint64 `json:"total_usage"` + + // Total CPU time consumed per core (Linux). Not used on Windows. + // Units: nanoseconds. + PercpuUsage []uint64 `json:"percpu_usage,omitempty"` + + // Time spent by tasks of the cgroup in kernel mode (Linux). + // Time spent by all container processes in kernel mode (Windows). + // Units: nanoseconds (Linux). + // Units: 100's of nanoseconds (Windows). Not populated for Hyper-V Containers. + UsageInKernelmode uint64 `json:"usage_in_kernelmode"` + + // Time spent by tasks of the cgroup in user mode (Linux). + // Time spent by all container processes in user mode (Windows). + // Units: nanoseconds (Linux). + // Units: 100's of nanoseconds (Windows). Not populated for Hyper-V Containers + UsageInUsermode uint64 `json:"usage_in_usermode"` +} + +// CPUStats aggregates and wraps all CPU related info of container +type CPUStats struct { + // CPU Usage. Linux and Windows. + CPUUsage CPUUsage `json:"cpu_usage"` + + // System Usage. Linux only. + SystemUsage uint64 `json:"system_cpu_usage,omitempty"` + + // Online CPUs. Linux only. + OnlineCPUs uint32 `json:"online_cpus,omitempty"` + + // Throttling Data. Linux only. + ThrottlingData ThrottlingData `json:"throttling_data,omitempty"` +} + +// MemoryStats aggregates all memory stats since container inception on Linux. +// Windows returns stats for commit and private working set only. +type MemoryStats struct { + // Linux Memory Stats + + // current res_counter usage for memory + Usage uint64 `json:"usage,omitempty"` + // maximum usage ever recorded. + MaxUsage uint64 `json:"max_usage,omitempty"` + // TODO(vishh): Export these as stronger types. + // all the stats exported via memory.stat. + Stats map[string]uint64 `json:"stats,omitempty"` + // number of times memory usage hits limits. + Failcnt uint64 `json:"failcnt,omitempty"` + Limit uint64 `json:"limit,omitempty"` + + // Windows Memory Stats + // See https://technet.microsoft.com/en-us/magazine/ff382715.aspx + + // committed bytes + Commit uint64 `json:"commitbytes,omitempty"` + // peak committed bytes + CommitPeak uint64 `json:"commitpeakbytes,omitempty"` + // private working set + PrivateWorkingSet uint64 `json:"privateworkingset,omitempty"` +} + +// BlkioStatEntry is one small entity to store a piece of Blkio stats +// Not used on Windows. +type BlkioStatEntry struct { + Major uint64 `json:"major"` + Minor uint64 `json:"minor"` + Op string `json:"op"` + Value uint64 `json:"value"` +} + +// BlkioStats stores All IO service stats for data read and write. +// This is a Linux specific structure as the differences between expressing +// block I/O on Windows and Linux are sufficiently significant to make +// little sense attempting to morph into a combined structure. +type BlkioStats struct { + // number of bytes transferred to and from the block device + IoServiceBytesRecursive []BlkioStatEntry `json:"io_service_bytes_recursive"` + IoServicedRecursive []BlkioStatEntry `json:"io_serviced_recursive"` + IoQueuedRecursive []BlkioStatEntry `json:"io_queue_recursive"` + IoServiceTimeRecursive []BlkioStatEntry `json:"io_service_time_recursive"` + IoWaitTimeRecursive []BlkioStatEntry `json:"io_wait_time_recursive"` + IoMergedRecursive []BlkioStatEntry `json:"io_merged_recursive"` + IoTimeRecursive []BlkioStatEntry `json:"io_time_recursive"` + SectorsRecursive []BlkioStatEntry `json:"sectors_recursive"` +} + +// StorageStats is the disk I/O stats for read/write on Windows. +type StorageStats struct { + ReadCountNormalized uint64 `json:"read_count_normalized,omitempty"` + ReadSizeBytes uint64 `json:"read_size_bytes,omitempty"` + WriteCountNormalized uint64 `json:"write_count_normalized,omitempty"` + WriteSizeBytes uint64 `json:"write_size_bytes,omitempty"` +} + +// NetworkStats aggregates the network stats of one container +type NetworkStats struct { + // Bytes received. Windows and Linux. + RxBytes uint64 `json:"rx_bytes"` + // Packets received. Windows and Linux. + RxPackets uint64 `json:"rx_packets"` + // Received errors. Not used on Windows. Note that we don't `omitempty` this + // field as it is expected in the >=v1.21 API stats structure. + RxErrors uint64 `json:"rx_errors"` + // Incoming packets dropped. Windows and Linux. + RxDropped uint64 `json:"rx_dropped"` + // Bytes sent. Windows and Linux. + TxBytes uint64 `json:"tx_bytes"` + // Packets sent. Windows and Linux. + TxPackets uint64 `json:"tx_packets"` + // Sent errors. Not used on Windows. Note that we don't `omitempty` this + // field as it is expected in the >=v1.21 API stats structure. + TxErrors uint64 `json:"tx_errors"` + // Outgoing packets dropped. Windows and Linux. + TxDropped uint64 `json:"tx_dropped"` + // Endpoint ID. Not used on Linux. + EndpointID string `json:"endpoint_id,omitempty"` + // Instance ID. Not used on Linux. + InstanceID string `json:"instance_id,omitempty"` +} + +// PidsStats contains the stats of a container's pids +type PidsStats struct { + // Current is the number of pids in the cgroup + Current uint64 `json:"current,omitempty"` + // Limit is the hard limit on the number of pids in the cgroup. + // A "Limit" of 0 means that there is no limit. + Limit uint64 `json:"limit,omitempty"` +} + +// Stats is Ultimate struct aggregating all types of stats of one container +type Stats struct { + // Common stats + Read time.Time `json:"read"` + PreRead time.Time `json:"preread"` + + // Linux specific stats, not populated on Windows. + PidsStats PidsStats `json:"pids_stats,omitempty"` + BlkioStats BlkioStats `json:"blkio_stats,omitempty"` + + // Windows specific stats, not populated on Linux. + NumProcs uint32 `json:"num_procs"` + StorageStats StorageStats `json:"storage_stats,omitempty"` + + // Shared stats + CPUStats CPUStats `json:"cpu_stats,omitempty"` + PreCPUStats CPUStats `json:"precpu_stats,omitempty"` // "Pre"="Previous" + MemoryStats MemoryStats `json:"memory_stats,omitempty"` +} + +// StatsJSON is newly used Networks +type StatsJSON struct { + Stats + + Name string `json:"name,omitempty"` + ID string `json:"id,omitempty"` + + // Networks request version >=1.21 + Networks map[string]NetworkStats `json:"networks,omitempty"` +} diff --git a/vendor/github.com/docker/docker/api/types/strslice/strslice.go b/vendor/github.com/docker/docker/api/types/strslice/strslice.go new file mode 100644 index 0000000000..82921cebc1 --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/strslice/strslice.go @@ -0,0 +1,30 @@ +package strslice // import "github.com/docker/docker/api/types/strslice" + +import "encoding/json" + +// StrSlice represents a string or an array of strings. +// We need to override the json decoder to accept both options. +type StrSlice []string + +// UnmarshalJSON decodes the byte slice whether it's a string or an array of +// strings. This method is needed to implement json.Unmarshaler. +func (e *StrSlice) UnmarshalJSON(b []byte) error { + if len(b) == 0 { + // With no input, we preserve the existing value by returning nil and + // leaving the target alone. This allows defining default values for + // the type. + return nil + } + + p := make([]string, 0, 1) + if err := json.Unmarshal(b, &p); err != nil { + var s string + if err := json.Unmarshal(b, &s); err != nil { + return err + } + p = append(p, s) + } + + *e = p + return nil +} diff --git a/vendor/github.com/docker/docker/api/types/swarm/common.go b/vendor/github.com/docker/docker/api/types/swarm/common.go new file mode 100644 index 0000000000..5ded7dba8a --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/swarm/common.go @@ -0,0 +1,48 @@ +package swarm // import "github.com/docker/docker/api/types/swarm" + +import ( + "strconv" + "time" +) + +// Version represents the internal object version. +type Version struct { + Index uint64 `json:",omitempty"` +} + +// String implements fmt.Stringer interface. +func (v Version) String() string { + return strconv.FormatUint(v.Index, 10) +} + +// Meta is a base object inherited by most of the other once. +type Meta struct { + Version Version `json:",omitempty"` + CreatedAt time.Time `json:",omitempty"` + UpdatedAt time.Time `json:",omitempty"` +} + +// Annotations represents how to describe an object. +type Annotations struct { + Name string `json:",omitempty"` + Labels map[string]string `json:"Labels"` +} + +// Driver represents a driver (network, logging, secrets backend). +type Driver struct { + Name string `json:",omitempty"` + Options map[string]string `json:",omitempty"` +} + +// TLSInfo represents the TLS information about what CA certificate is trusted, +// and who the issuer for a TLS certificate is +type TLSInfo struct { + // TrustRoot is the trusted CA root certificate in PEM format + TrustRoot string `json:",omitempty"` + + // CertIssuer is the raw subject bytes of the issuer + CertIssuerSubject []byte `json:",omitempty"` + + // CertIssuerPublicKey is the raw public key bytes of the issuer + CertIssuerPublicKey []byte `json:",omitempty"` +} diff --git a/vendor/github.com/docker/docker/api/types/swarm/config.go b/vendor/github.com/docker/docker/api/types/swarm/config.go new file mode 100644 index 0000000000..16202ccce6 --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/swarm/config.go @@ -0,0 +1,40 @@ +package swarm // import "github.com/docker/docker/api/types/swarm" + +import "os" + +// Config represents a config. +type Config struct { + ID string + Meta + Spec ConfigSpec +} + +// ConfigSpec represents a config specification from a config in swarm +type ConfigSpec struct { + Annotations + Data []byte `json:",omitempty"` + + // Templating controls whether and how to evaluate the config payload as + // a template. If it is not set, no templating is used. + Templating *Driver `json:",omitempty"` +} + +// ConfigReferenceFileTarget is a file target in a config reference +type ConfigReferenceFileTarget struct { + Name string + UID string + GID string + Mode os.FileMode +} + +// ConfigReferenceRuntimeTarget is a target for a config specifying that it +// isn't mounted into the container but instead has some other purpose. +type ConfigReferenceRuntimeTarget struct{} + +// ConfigReference is a reference to a config in swarm +type ConfigReference struct { + File *ConfigReferenceFileTarget `json:",omitempty"` + Runtime *ConfigReferenceRuntimeTarget `json:",omitempty"` + ConfigID string + ConfigName string +} diff --git a/vendor/github.com/docker/docker/api/types/swarm/container.go b/vendor/github.com/docker/docker/api/types/swarm/container.go new file mode 100644 index 0000000000..af5e1c0bc2 --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/swarm/container.go @@ -0,0 +1,80 @@ +package swarm // import "github.com/docker/docker/api/types/swarm" + +import ( + "time" + + "github.com/docker/docker/api/types/container" + "github.com/docker/docker/api/types/mount" + "github.com/docker/go-units" +) + +// DNSConfig specifies DNS related configurations in resolver configuration file (resolv.conf) +// Detailed documentation is available in: +// http://man7.org/linux/man-pages/man5/resolv.conf.5.html +// `nameserver`, `search`, `options` have been supported. +// TODO: `domain` is not supported yet. +type DNSConfig struct { + // Nameservers specifies the IP addresses of the name servers + Nameservers []string `json:",omitempty"` + // Search specifies the search list for host-name lookup + Search []string `json:",omitempty"` + // Options allows certain internal resolver variables to be modified + Options []string `json:",omitempty"` +} + +// SELinuxContext contains the SELinux labels of the container. +type SELinuxContext struct { + Disable bool + + User string + Role string + Type string + Level string +} + +// CredentialSpec for managed service account (Windows only) +type CredentialSpec struct { + Config string + File string + Registry string +} + +// Privileges defines the security options for the container. +type Privileges struct { + CredentialSpec *CredentialSpec + SELinuxContext *SELinuxContext +} + +// ContainerSpec represents the spec of a container. +type ContainerSpec struct { + Image string `json:",omitempty"` + Labels map[string]string `json:",omitempty"` + Command []string `json:",omitempty"` + Args []string `json:",omitempty"` + Hostname string `json:",omitempty"` + Env []string `json:",omitempty"` + Dir string `json:",omitempty"` + User string `json:",omitempty"` + Groups []string `json:",omitempty"` + Privileges *Privileges `json:",omitempty"` + Init *bool `json:",omitempty"` + StopSignal string `json:",omitempty"` + TTY bool `json:",omitempty"` + OpenStdin bool `json:",omitempty"` + ReadOnly bool `json:",omitempty"` + Mounts []mount.Mount `json:",omitempty"` + StopGracePeriod *time.Duration `json:",omitempty"` + Healthcheck *container.HealthConfig `json:",omitempty"` + // The format of extra hosts on swarmkit is specified in: + // http://man7.org/linux/man-pages/man5/hosts.5.html + // IP_address canonical_hostname [aliases...] + Hosts []string `json:",omitempty"` + DNSConfig *DNSConfig `json:",omitempty"` + Secrets []*SecretReference `json:",omitempty"` + Configs []*ConfigReference `json:",omitempty"` + Isolation container.Isolation `json:",omitempty"` + Sysctls map[string]string `json:",omitempty"` + CapabilityAdd []string `json:",omitempty"` + CapabilityDrop []string `json:",omitempty"` + Ulimits []*units.Ulimit `json:",omitempty"` +} diff --git a/vendor/github.com/docker/docker/api/types/swarm/network.go b/vendor/github.com/docker/docker/api/types/swarm/network.go new file mode 100644 index 0000000000..98ef3284d1 --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/swarm/network.go @@ -0,0 +1,121 @@ +package swarm // import "github.com/docker/docker/api/types/swarm" + +import ( + "github.com/docker/docker/api/types/network" +) + +// Endpoint represents an endpoint. +type Endpoint struct { + Spec EndpointSpec `json:",omitempty"` + Ports []PortConfig `json:",omitempty"` + VirtualIPs []EndpointVirtualIP `json:",omitempty"` +} + +// EndpointSpec represents the spec of an endpoint. +type EndpointSpec struct { + Mode ResolutionMode `json:",omitempty"` + Ports []PortConfig `json:",omitempty"` +} + +// ResolutionMode represents a resolution mode. +type ResolutionMode string + +const ( + // ResolutionModeVIP VIP + ResolutionModeVIP ResolutionMode = "vip" + // ResolutionModeDNSRR DNSRR + ResolutionModeDNSRR ResolutionMode = "dnsrr" +) + +// PortConfig represents the config of a port. +type PortConfig struct { + Name string `json:",omitempty"` + Protocol PortConfigProtocol `json:",omitempty"` + // TargetPort is the port inside the container + TargetPort uint32 `json:",omitempty"` + // PublishedPort is the port on the swarm hosts + PublishedPort uint32 `json:",omitempty"` + // PublishMode is the mode in which port is published + PublishMode PortConfigPublishMode `json:",omitempty"` +} + +// PortConfigPublishMode represents the mode in which the port is to +// be published. +type PortConfigPublishMode string + +const ( + // PortConfigPublishModeIngress is used for ports published + // for ingress load balancing using routing mesh. + PortConfigPublishModeIngress PortConfigPublishMode = "ingress" + // PortConfigPublishModeHost is used for ports published + // for direct host level access on the host where the task is running. + PortConfigPublishModeHost PortConfigPublishMode = "host" +) + +// PortConfigProtocol represents the protocol of a port. +type PortConfigProtocol string + +const ( + // TODO(stevvooe): These should be used generally, not just for PortConfig. + + // PortConfigProtocolTCP TCP + PortConfigProtocolTCP PortConfigProtocol = "tcp" + // PortConfigProtocolUDP UDP + PortConfigProtocolUDP PortConfigProtocol = "udp" + // PortConfigProtocolSCTP SCTP + PortConfigProtocolSCTP PortConfigProtocol = "sctp" +) + +// EndpointVirtualIP represents the virtual ip of a port. +type EndpointVirtualIP struct { + NetworkID string `json:",omitempty"` + Addr string `json:",omitempty"` +} + +// Network represents a network. +type Network struct { + ID string + Meta + Spec NetworkSpec `json:",omitempty"` + DriverState Driver `json:",omitempty"` + IPAMOptions *IPAMOptions `json:",omitempty"` +} + +// NetworkSpec represents the spec of a network. +type NetworkSpec struct { + Annotations + DriverConfiguration *Driver `json:",omitempty"` + IPv6Enabled bool `json:",omitempty"` + Internal bool `json:",omitempty"` + Attachable bool `json:",omitempty"` + Ingress bool `json:",omitempty"` + IPAMOptions *IPAMOptions `json:",omitempty"` + ConfigFrom *network.ConfigReference `json:",omitempty"` + Scope string `json:",omitempty"` +} + +// NetworkAttachmentConfig represents the configuration of a network attachment. +type NetworkAttachmentConfig struct { + Target string `json:",omitempty"` + Aliases []string `json:",omitempty"` + DriverOpts map[string]string `json:",omitempty"` +} + +// NetworkAttachment represents a network attachment. +type NetworkAttachment struct { + Network Network `json:",omitempty"` + Addresses []string `json:",omitempty"` +} + +// IPAMOptions represents ipam options. +type IPAMOptions struct { + Driver Driver `json:",omitempty"` + Configs []IPAMConfig `json:",omitempty"` +} + +// IPAMConfig represents ipam configuration. +type IPAMConfig struct { + Subnet string `json:",omitempty"` + Range string `json:",omitempty"` + Gateway string `json:",omitempty"` +} diff --git a/vendor/github.com/docker/docker/api/types/swarm/node.go b/vendor/github.com/docker/docker/api/types/swarm/node.go new file mode 100644 index 0000000000..bb98d5eedc --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/swarm/node.go @@ -0,0 +1,139 @@ +package swarm // import "github.com/docker/docker/api/types/swarm" + +// Node represents a node. +type Node struct { + ID string + Meta + // Spec defines the desired state of the node as specified by the user. + // The system will honor this and will *never* modify it. + Spec NodeSpec `json:",omitempty"` + // Description encapsulates the properties of the Node as reported by the + // agent. + Description NodeDescription `json:",omitempty"` + // Status provides the current status of the node, as seen by the manager. + Status NodeStatus `json:",omitempty"` + // ManagerStatus provides the current status of the node's manager + // component, if the node is a manager. + ManagerStatus *ManagerStatus `json:",omitempty"` +} + +// NodeSpec represents the spec of a node. +type NodeSpec struct { + Annotations + Role NodeRole `json:",omitempty"` + Availability NodeAvailability `json:",omitempty"` +} + +// NodeRole represents the role of a node. +type NodeRole string + +const ( + // NodeRoleWorker WORKER + NodeRoleWorker NodeRole = "worker" + // NodeRoleManager MANAGER + NodeRoleManager NodeRole = "manager" +) + +// NodeAvailability represents the availability of a node. +type NodeAvailability string + +const ( + // NodeAvailabilityActive ACTIVE + NodeAvailabilityActive NodeAvailability = "active" + // NodeAvailabilityPause PAUSE + NodeAvailabilityPause NodeAvailability = "pause" + // NodeAvailabilityDrain DRAIN + NodeAvailabilityDrain NodeAvailability = "drain" +) + +// NodeDescription represents the description of a node. +type NodeDescription struct { + Hostname string `json:",omitempty"` + Platform Platform `json:",omitempty"` + Resources Resources `json:",omitempty"` + Engine EngineDescription `json:",omitempty"` + TLSInfo TLSInfo `json:",omitempty"` + CSIInfo []NodeCSIInfo `json:",omitempty"` +} + +// Platform represents the platform (Arch/OS). +type Platform struct { + Architecture string `json:",omitempty"` + OS string `json:",omitempty"` +} + +// EngineDescription represents the description of an engine. +type EngineDescription struct { + EngineVersion string `json:",omitempty"` + Labels map[string]string `json:",omitempty"` + Plugins []PluginDescription `json:",omitempty"` +} + +// NodeCSIInfo represents information about a CSI plugin available on the node +type NodeCSIInfo struct { + // PluginName is the name of the CSI plugin. + PluginName string `json:",omitempty"` + // NodeID is the ID of the node as reported by the CSI plugin. This is + // different from the swarm node ID. + NodeID string `json:",omitempty"` + // MaxVolumesPerNode is the maximum number of volumes that may be published + // to this node + MaxVolumesPerNode int64 `json:",omitempty"` + // AccessibleTopology indicates the location of this node in the CSI + // plugin's topology + AccessibleTopology *Topology `json:",omitempty"` +} + +// PluginDescription represents the description of an engine plugin. +type PluginDescription struct { + Type string `json:",omitempty"` + Name string `json:",omitempty"` +} + +// NodeStatus represents the status of a node. +type NodeStatus struct { + State NodeState `json:",omitempty"` + Message string `json:",omitempty"` + Addr string `json:",omitempty"` +} + +// Reachability represents the reachability of a node. +type Reachability string + +const ( + // ReachabilityUnknown UNKNOWN + ReachabilityUnknown Reachability = "unknown" + // ReachabilityUnreachable UNREACHABLE + ReachabilityUnreachable Reachability = "unreachable" + // ReachabilityReachable REACHABLE + ReachabilityReachable Reachability = "reachable" +) + +// ManagerStatus represents the status of a manager. +type ManagerStatus struct { + Leader bool `json:",omitempty"` + Reachability Reachability `json:",omitempty"` + Addr string `json:",omitempty"` +} + +// NodeState represents the state of a node. +type NodeState string + +const ( + // NodeStateUnknown UNKNOWN + NodeStateUnknown NodeState = "unknown" + // NodeStateDown DOWN + NodeStateDown NodeState = "down" + // NodeStateReady READY + NodeStateReady NodeState = "ready" + // NodeStateDisconnected DISCONNECTED + NodeStateDisconnected NodeState = "disconnected" +) + +// Topology defines the CSI topology of this node. This type is a duplicate of +// github.com/docker/docker/api/types.Topology. Because the type definition +// is so simple and to avoid complicated structure or circular imports, we just +// duplicate it here. See that type for full documentation +type Topology struct { + Segments map[string]string `json:",omitempty"` +} diff --git a/vendor/github.com/docker/docker/api/types/swarm/runtime.go b/vendor/github.com/docker/docker/api/types/swarm/runtime.go new file mode 100644 index 0000000000..0c77403ccf --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/swarm/runtime.go @@ -0,0 +1,27 @@ +package swarm // import "github.com/docker/docker/api/types/swarm" + +// RuntimeType is the type of runtime used for the TaskSpec +type RuntimeType string + +// RuntimeURL is the proto type url +type RuntimeURL string + +const ( + // RuntimeContainer is the container based runtime + RuntimeContainer RuntimeType = "container" + // RuntimePlugin is the plugin based runtime + RuntimePlugin RuntimeType = "plugin" + // RuntimeNetworkAttachment is the network attachment runtime + RuntimeNetworkAttachment RuntimeType = "attachment" + + // RuntimeURLContainer is the proto url for the container type + RuntimeURLContainer RuntimeURL = "types.docker.com/RuntimeContainer" + // RuntimeURLPlugin is the proto url for the plugin type + RuntimeURLPlugin RuntimeURL = "types.docker.com/RuntimePlugin" +) + +// NetworkAttachmentSpec represents the runtime spec type for network +// attachment tasks +type NetworkAttachmentSpec struct { + ContainerID string +} diff --git a/vendor/github.com/docker/docker/api/types/swarm/runtime/gen.go b/vendor/github.com/docker/docker/api/types/swarm/runtime/gen.go new file mode 100644 index 0000000000..98c2806c31 --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/swarm/runtime/gen.go @@ -0,0 +1,3 @@ +//go:generate protoc -I . --gogofast_out=import_path=github.com/docker/docker/api/types/swarm/runtime:. plugin.proto + +package runtime // import "github.com/docker/docker/api/types/swarm/runtime" diff --git a/vendor/github.com/docker/docker/api/types/swarm/runtime/plugin.pb.go b/vendor/github.com/docker/docker/api/types/swarm/runtime/plugin.pb.go new file mode 100644 index 0000000000..e45045866a --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/swarm/runtime/plugin.pb.go @@ -0,0 +1,754 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: plugin.proto + +/* + Package runtime is a generated protocol buffer package. + + It is generated from these files: + plugin.proto + + It has these top-level messages: + PluginSpec + PluginPrivilege +*/ +package runtime + +import proto "github.com/gogo/protobuf/proto" +import fmt "fmt" +import math "math" + +import io "io" + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package + +// PluginSpec defines the base payload which clients can specify for creating +// a service with the plugin runtime. +type PluginSpec struct { + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Remote string `protobuf:"bytes,2,opt,name=remote,proto3" json:"remote,omitempty"` + Privileges []*PluginPrivilege `protobuf:"bytes,3,rep,name=privileges" json:"privileges,omitempty"` + Disabled bool `protobuf:"varint,4,opt,name=disabled,proto3" json:"disabled,omitempty"` + Env []string `protobuf:"bytes,5,rep,name=env" json:"env,omitempty"` +} + +func (m *PluginSpec) Reset() { *m = PluginSpec{} } +func (m *PluginSpec) String() string { return proto.CompactTextString(m) } +func (*PluginSpec) ProtoMessage() {} +func (*PluginSpec) Descriptor() ([]byte, []int) { return fileDescriptorPlugin, []int{0} } + +func (m *PluginSpec) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *PluginSpec) GetRemote() string { + if m != nil { + return m.Remote + } + return "" +} + +func (m *PluginSpec) GetPrivileges() []*PluginPrivilege { + if m != nil { + return m.Privileges + } + return nil +} + +func (m *PluginSpec) GetDisabled() bool { + if m != nil { + return m.Disabled + } + return false +} + +func (m *PluginSpec) GetEnv() []string { + if m != nil { + return m.Env + } + return nil +} + +// PluginPrivilege describes a permission the user has to accept +// upon installing a plugin. +type PluginPrivilege struct { + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` + Value []string `protobuf:"bytes,3,rep,name=value" json:"value,omitempty"` +} + +func (m *PluginPrivilege) Reset() { *m = PluginPrivilege{} } +func (m *PluginPrivilege) String() string { return proto.CompactTextString(m) } +func (*PluginPrivilege) ProtoMessage() {} +func (*PluginPrivilege) Descriptor() ([]byte, []int) { return fileDescriptorPlugin, []int{1} } + +func (m *PluginPrivilege) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *PluginPrivilege) GetDescription() string { + if m != nil { + return m.Description + } + return "" +} + +func (m *PluginPrivilege) GetValue() []string { + if m != nil { + return m.Value + } + return nil +} + +func init() { + proto.RegisterType((*PluginSpec)(nil), "PluginSpec") + proto.RegisterType((*PluginPrivilege)(nil), "PluginPrivilege") +} +func (m *PluginSpec) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalTo(dAtA) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *PluginSpec) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + if len(m.Name) > 0 { + dAtA[i] = 0xa + i++ + i = encodeVarintPlugin(dAtA, i, uint64(len(m.Name))) + i += copy(dAtA[i:], m.Name) + } + if len(m.Remote) > 0 { + dAtA[i] = 0x12 + i++ + i = encodeVarintPlugin(dAtA, i, uint64(len(m.Remote))) + i += copy(dAtA[i:], m.Remote) + } + if len(m.Privileges) > 0 { + for _, msg := range m.Privileges { + dAtA[i] = 0x1a + i++ + i = encodeVarintPlugin(dAtA, i, uint64(msg.Size())) + n, err := msg.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n + } + } + if m.Disabled { + dAtA[i] = 0x20 + i++ + if m.Disabled { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i++ + } + if len(m.Env) > 0 { + for _, s := range m.Env { + dAtA[i] = 0x2a + i++ + l = len(s) + for l >= 1<<7 { + dAtA[i] = uint8(uint64(l)&0x7f | 0x80) + l >>= 7 + i++ + } + dAtA[i] = uint8(l) + i++ + i += copy(dAtA[i:], s) + } + } + return i, nil +} + +func (m *PluginPrivilege) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalTo(dAtA) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *PluginPrivilege) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + if len(m.Name) > 0 { + dAtA[i] = 0xa + i++ + i = encodeVarintPlugin(dAtA, i, uint64(len(m.Name))) + i += copy(dAtA[i:], m.Name) + } + if len(m.Description) > 0 { + dAtA[i] = 0x12 + i++ + i = encodeVarintPlugin(dAtA, i, uint64(len(m.Description))) + i += copy(dAtA[i:], m.Description) + } + if len(m.Value) > 0 { + for _, s := range m.Value { + dAtA[i] = 0x1a + i++ + l = len(s) + for l >= 1<<7 { + dAtA[i] = uint8(uint64(l)&0x7f | 0x80) + l >>= 7 + i++ + } + dAtA[i] = uint8(l) + i++ + i += copy(dAtA[i:], s) + } + } + return i, nil +} + +func encodeVarintPlugin(dAtA []byte, offset int, v uint64) int { + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return offset + 1 +} +func (m *PluginSpec) Size() (n int) { + var l int + _ = l + l = len(m.Name) + if l > 0 { + n += 1 + l + sovPlugin(uint64(l)) + } + l = len(m.Remote) + if l > 0 { + n += 1 + l + sovPlugin(uint64(l)) + } + if len(m.Privileges) > 0 { + for _, e := range m.Privileges { + l = e.Size() + n += 1 + l + sovPlugin(uint64(l)) + } + } + if m.Disabled { + n += 2 + } + if len(m.Env) > 0 { + for _, s := range m.Env { + l = len(s) + n += 1 + l + sovPlugin(uint64(l)) + } + } + return n +} + +func (m *PluginPrivilege) Size() (n int) { + var l int + _ = l + l = len(m.Name) + if l > 0 { + n += 1 + l + sovPlugin(uint64(l)) + } + l = len(m.Description) + if l > 0 { + n += 1 + l + sovPlugin(uint64(l)) + } + if len(m.Value) > 0 { + for _, s := range m.Value { + l = len(s) + n += 1 + l + sovPlugin(uint64(l)) + } + } + return n +} + +func sovPlugin(x uint64) (n int) { + for { + n++ + x >>= 7 + if x == 0 { + break + } + } + return n +} +func sozPlugin(x uint64) (n int) { + return sovPlugin(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *PluginSpec) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlugin + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: PluginSpec: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: PluginSpec: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlugin + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthPlugin + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Name = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Remote", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlugin + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthPlugin + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Remote = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Privileges", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlugin + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthPlugin + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Privileges = append(m.Privileges, &PluginPrivilege{}) + if err := m.Privileges[len(m.Privileges)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Disabled", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlugin + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + m.Disabled = bool(v != 0) + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Env", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlugin + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthPlugin + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Env = append(m.Env, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipPlugin(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthPlugin + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *PluginPrivilege) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlugin + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: PluginPrivilege: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: PluginPrivilege: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlugin + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthPlugin + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Name = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Description", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlugin + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthPlugin + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Description = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Value", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlugin + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthPlugin + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Value = append(m.Value, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipPlugin(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthPlugin + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipPlugin(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowPlugin + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowPlugin + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + return iNdEx, nil + case 1: + iNdEx += 8 + return iNdEx, nil + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowPlugin + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + iNdEx += length + if length < 0 { + return 0, ErrInvalidLengthPlugin + } + return iNdEx, nil + case 3: + for { + var innerWire uint64 + var start int = iNdEx + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowPlugin + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + innerWire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + innerWireType := int(innerWire & 0x7) + if innerWireType == 4 { + break + } + next, err := skipPlugin(dAtA[start:]) + if err != nil { + return 0, err + } + iNdEx = start + next + } + return iNdEx, nil + case 4: + return iNdEx, nil + case 5: + iNdEx += 4 + return iNdEx, nil + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + } + panic("unreachable") +} + +var ( + ErrInvalidLengthPlugin = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowPlugin = fmt.Errorf("proto: integer overflow") +) + +func init() { proto.RegisterFile("plugin.proto", fileDescriptorPlugin) } + +var fileDescriptorPlugin = []byte{ + // 256 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x90, 0x4d, 0x4b, 0xc3, 0x30, + 0x18, 0xc7, 0x89, 0xdd, 0xc6, 0xfa, 0x4c, 0x70, 0x04, 0x91, 0xe2, 0xa1, 0x94, 0x9d, 0x7a, 0x6a, + 0x45, 0x2f, 0x82, 0x37, 0x0f, 0x9e, 0x47, 0xbc, 0x09, 0x1e, 0xd2, 0xf6, 0xa1, 0x06, 0x9b, 0x17, + 0x92, 0xb4, 0xe2, 0x37, 0xf1, 0x23, 0x79, 0xf4, 0x23, 0x48, 0x3f, 0x89, 0x98, 0x75, 0x32, 0x64, + 0xa7, 0xff, 0x4b, 0xc2, 0x9f, 0x1f, 0x0f, 0x9c, 0x9a, 0xae, 0x6f, 0x85, 0x2a, 0x8c, 0xd5, 0x5e, + 0x6f, 0x3e, 0x08, 0xc0, 0x36, 0x14, 0x8f, 0x06, 0x6b, 0x4a, 0x61, 0xa6, 0xb8, 0xc4, 0x84, 0x64, + 0x24, 0x8f, 0x59, 0xf0, 0xf4, 0x02, 0x16, 0x16, 0xa5, 0xf6, 0x98, 0x9c, 0x84, 0x76, 0x4a, 0xf4, + 0x0a, 0xc0, 0x58, 0x31, 0x88, 0x0e, 0x5b, 0x74, 0x49, 0x94, 0x45, 0xf9, 0xea, 0x7a, 0x5d, 0xec, + 0xc6, 0xb6, 0xfb, 0x07, 0x76, 0xf0, 0x87, 0x5e, 0xc2, 0xb2, 0x11, 0x8e, 0x57, 0x1d, 0x36, 0xc9, + 0x2c, 0x23, 0xf9, 0x92, 0xfd, 0x65, 0xba, 0x86, 0x08, 0xd5, 0x90, 0xcc, 0xb3, 0x28, 0x8f, 0xd9, + 0xaf, 0xdd, 0x3c, 0xc3, 0xd9, 0xbf, 0xb1, 0xa3, 0x78, 0x19, 0xac, 0x1a, 0x74, 0xb5, 0x15, 0xc6, + 0x0b, 0xad, 0x26, 0xc6, 0xc3, 0x8a, 0x9e, 0xc3, 0x7c, 0xe0, 0x5d, 0x8f, 0x81, 0x31, 0x66, 0xbb, + 0x70, 0xff, 0xf0, 0x39, 0xa6, 0xe4, 0x6b, 0x4c, 0xc9, 0xf7, 0x98, 0x92, 0xa7, 0xdb, 0x56, 0xf8, + 0x97, 0xbe, 0x2a, 0x6a, 0x2d, 0xcb, 0x46, 0xd7, 0xaf, 0x68, 0xf7, 0xc2, 0x8d, 0x28, 0xfd, 0xbb, + 0x41, 0x57, 0xba, 0x37, 0x6e, 0x65, 0x69, 0x7b, 0xe5, 0x85, 0xc4, 0xbb, 0x49, 0xab, 0x45, 0x38, + 0xe4, 0xcd, 0x4f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x99, 0xa8, 0xd9, 0x9b, 0x58, 0x01, 0x00, 0x00, +} diff --git a/vendor/github.com/docker/docker/api/types/swarm/runtime/plugin.proto b/vendor/github.com/docker/docker/api/types/swarm/runtime/plugin.proto new file mode 100644 index 0000000000..9ef169046b --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/swarm/runtime/plugin.proto @@ -0,0 +1,21 @@ +syntax = "proto3"; + +option go_package = "github.com/docker/docker/api/types/swarm/runtime;runtime"; + +// PluginSpec defines the base payload which clients can specify for creating +// a service with the plugin runtime. +message PluginSpec { + string name = 1; + string remote = 2; + repeated PluginPrivilege privileges = 3; + bool disabled = 4; + repeated string env = 5; +} + +// PluginPrivilege describes a permission the user has to accept +// upon installing a plugin. +message PluginPrivilege { + string name = 1; + string description = 2; + repeated string value = 3; +} diff --git a/vendor/github.com/docker/docker/api/types/swarm/secret.go b/vendor/github.com/docker/docker/api/types/swarm/secret.go new file mode 100644 index 0000000000..d5213ec981 --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/swarm/secret.go @@ -0,0 +1,36 @@ +package swarm // import "github.com/docker/docker/api/types/swarm" + +import "os" + +// Secret represents a secret. +type Secret struct { + ID string + Meta + Spec SecretSpec +} + +// SecretSpec represents a secret specification from a secret in swarm +type SecretSpec struct { + Annotations + Data []byte `json:",omitempty"` + Driver *Driver `json:",omitempty"` // name of the secrets driver used to fetch the secret's value from an external secret store + + // Templating controls whether and how to evaluate the secret payload as + // a template. If it is not set, no templating is used. + Templating *Driver `json:",omitempty"` +} + +// SecretReferenceFileTarget is a file target in a secret reference +type SecretReferenceFileTarget struct { + Name string + UID string + GID string + Mode os.FileMode +} + +// SecretReference is a reference to a secret in swarm +type SecretReference struct { + File *SecretReferenceFileTarget + SecretID string + SecretName string +} diff --git a/vendor/github.com/docker/docker/api/types/swarm/service.go b/vendor/github.com/docker/docker/api/types/swarm/service.go new file mode 100644 index 0000000000..6eb452d24d --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/swarm/service.go @@ -0,0 +1,202 @@ +package swarm // import "github.com/docker/docker/api/types/swarm" + +import "time" + +// Service represents a service. +type Service struct { + ID string + Meta + Spec ServiceSpec `json:",omitempty"` + PreviousSpec *ServiceSpec `json:",omitempty"` + Endpoint Endpoint `json:",omitempty"` + UpdateStatus *UpdateStatus `json:",omitempty"` + + // ServiceStatus is an optional, extra field indicating the number of + // desired and running tasks. It is provided primarily as a shortcut to + // calculating these values client-side, which otherwise would require + // listing all tasks for a service, an operation that could be + // computation and network expensive. + ServiceStatus *ServiceStatus `json:",omitempty"` + + // JobStatus is the status of a Service which is in one of ReplicatedJob or + // GlobalJob modes. It is absent on Replicated and Global services. + JobStatus *JobStatus `json:",omitempty"` +} + +// ServiceSpec represents the spec of a service. +type ServiceSpec struct { + Annotations + + // TaskTemplate defines how the service should construct new tasks when + // orchestrating this service. + TaskTemplate TaskSpec `json:",omitempty"` + Mode ServiceMode `json:",omitempty"` + UpdateConfig *UpdateConfig `json:",omitempty"` + RollbackConfig *UpdateConfig `json:",omitempty"` + + // Networks field in ServiceSpec is deprecated. The + // same field in TaskSpec should be used instead. + // This field will be removed in a future release. + Networks []NetworkAttachmentConfig `json:",omitempty"` + EndpointSpec *EndpointSpec `json:",omitempty"` +} + +// ServiceMode represents the mode of a service. +type ServiceMode struct { + Replicated *ReplicatedService `json:",omitempty"` + Global *GlobalService `json:",omitempty"` + ReplicatedJob *ReplicatedJob `json:",omitempty"` + GlobalJob *GlobalJob `json:",omitempty"` +} + +// UpdateState is the state of a service update. +type UpdateState string + +const ( + // UpdateStateUpdating is the updating state. + UpdateStateUpdating UpdateState = "updating" + // UpdateStatePaused is the paused state. + UpdateStatePaused UpdateState = "paused" + // UpdateStateCompleted is the completed state. + UpdateStateCompleted UpdateState = "completed" + // UpdateStateRollbackStarted is the state with a rollback in progress. + UpdateStateRollbackStarted UpdateState = "rollback_started" + // UpdateStateRollbackPaused is the state with a rollback in progress. + UpdateStateRollbackPaused UpdateState = "rollback_paused" + // UpdateStateRollbackCompleted is the state with a rollback in progress. + UpdateStateRollbackCompleted UpdateState = "rollback_completed" +) + +// UpdateStatus reports the status of a service update. +type UpdateStatus struct { + State UpdateState `json:",omitempty"` + StartedAt *time.Time `json:",omitempty"` + CompletedAt *time.Time `json:",omitempty"` + Message string `json:",omitempty"` +} + +// ReplicatedService is a kind of ServiceMode. +type ReplicatedService struct { + Replicas *uint64 `json:",omitempty"` +} + +// GlobalService is a kind of ServiceMode. +type GlobalService struct{} + +// ReplicatedJob is the a type of Service which executes a defined Tasks +// in parallel until the specified number of Tasks have succeeded. +type ReplicatedJob struct { + // MaxConcurrent indicates the maximum number of Tasks that should be + // executing simultaneously for this job at any given time. There may be + // fewer Tasks that MaxConcurrent executing simultaneously; for example, if + // there are fewer than MaxConcurrent tasks needed to reach + // TotalCompletions. + // + // If this field is empty, it will default to a max concurrency of 1. + MaxConcurrent *uint64 `json:",omitempty"` + + // TotalCompletions is the total number of Tasks desired to run to + // completion. + // + // If this field is empty, the value of MaxConcurrent will be used. + TotalCompletions *uint64 `json:",omitempty"` +} + +// GlobalJob is the type of a Service which executes a Task on every Node +// matching the Service's placement constraints. These tasks run to completion +// and then exit. +// +// This type is deliberately empty. +type GlobalJob struct{} + +const ( + // UpdateFailureActionPause PAUSE + UpdateFailureActionPause = "pause" + // UpdateFailureActionContinue CONTINUE + UpdateFailureActionContinue = "continue" + // UpdateFailureActionRollback ROLLBACK + UpdateFailureActionRollback = "rollback" + + // UpdateOrderStopFirst STOP_FIRST + UpdateOrderStopFirst = "stop-first" + // UpdateOrderStartFirst START_FIRST + UpdateOrderStartFirst = "start-first" +) + +// UpdateConfig represents the update configuration. +type UpdateConfig struct { + // Maximum number of tasks to be updated in one iteration. + // 0 means unlimited parallelism. + Parallelism uint64 + + // Amount of time between updates. + Delay time.Duration `json:",omitempty"` + + // FailureAction is the action to take when an update failures. + FailureAction string `json:",omitempty"` + + // Monitor indicates how long to monitor a task for failure after it is + // created. If the task fails by ending up in one of the states + // REJECTED, COMPLETED, or FAILED, within Monitor from its creation, + // this counts as a failure. If it fails after Monitor, it does not + // count as a failure. If Monitor is unspecified, a default value will + // be used. + Monitor time.Duration `json:",omitempty"` + + // MaxFailureRatio is the fraction of tasks that may fail during + // an update before the failure action is invoked. Any task created by + // the current update which ends up in one of the states REJECTED, + // COMPLETED or FAILED within Monitor from its creation counts as a + // failure. The number of failures is divided by the number of tasks + // being updated, and if this fraction is greater than + // MaxFailureRatio, the failure action is invoked. + // + // If the failure action is CONTINUE, there is no effect. + // If the failure action is PAUSE, no more tasks will be updated until + // another update is started. + MaxFailureRatio float32 + + // Order indicates the order of operations when rolling out an updated + // task. Either the old task is shut down before the new task is + // started, or the new task is started before the old task is shut down. + Order string +} + +// ServiceStatus represents the number of running tasks in a service and the +// number of tasks desired to be running. +type ServiceStatus struct { + // RunningTasks is the number of tasks for the service actually in the + // Running state + RunningTasks uint64 + + // DesiredTasks is the number of tasks desired to be running by the + // service. For replicated services, this is the replica count. For global + // services, this is computed by taking the number of tasks with desired + // state of not-Shutdown. + DesiredTasks uint64 + + // CompletedTasks is the number of tasks in the state Completed, if this + // service is in ReplicatedJob or GlobalJob mode. This field must be + // cross-referenced with the service type, because the default value of 0 + // may mean that a service is not in a job mode, or it may mean that the + // job has yet to complete any tasks. + CompletedTasks uint64 +} + +// JobStatus is the status of a job-type service. +type JobStatus struct { + // JobIteration is a value increased each time a Job is executed, + // successfully or otherwise. "Executed", in this case, means the job as a + // whole has been started, not that an individual Task has been launched. A + // job is "Executed" when its ServiceSpec is updated. JobIteration can be + // used to disambiguate Tasks belonging to different executions of a job. + // + // Though JobIteration will increase with each subsequent execution, it may + // not necessarily increase by 1, and so JobIteration should not be used to + // keep track of the number of times a job has been executed. + JobIteration Version + + // LastExecution is the time that the job was last executed, as observed by + // Swarm manager. + LastExecution time.Time `json:",omitempty"` +} diff --git a/vendor/github.com/docker/docker/api/types/swarm/swarm.go b/vendor/github.com/docker/docker/api/types/swarm/swarm.go new file mode 100644 index 0000000000..3eae4b9b29 --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/swarm/swarm.go @@ -0,0 +1,237 @@ +package swarm // import "github.com/docker/docker/api/types/swarm" + +import ( + "time" +) + +// ClusterInfo represents info about the cluster for outputting in "info" +// it contains the same information as "Swarm", but without the JoinTokens +type ClusterInfo struct { + ID string + Meta + Spec Spec + TLSInfo TLSInfo + RootRotationInProgress bool + DefaultAddrPool []string + SubnetSize uint32 + DataPathPort uint32 +} + +// Swarm represents a swarm. +type Swarm struct { + ClusterInfo + JoinTokens JoinTokens +} + +// JoinTokens contains the tokens workers and managers need to join the swarm. +type JoinTokens struct { + // Worker is the join token workers may use to join the swarm. + Worker string + // Manager is the join token managers may use to join the swarm. + Manager string +} + +// Spec represents the spec of a swarm. +type Spec struct { + Annotations + + Orchestration OrchestrationConfig `json:",omitempty"` + Raft RaftConfig `json:",omitempty"` + Dispatcher DispatcherConfig `json:",omitempty"` + CAConfig CAConfig `json:",omitempty"` + TaskDefaults TaskDefaults `json:",omitempty"` + EncryptionConfig EncryptionConfig `json:",omitempty"` +} + +// OrchestrationConfig represents orchestration configuration. +type OrchestrationConfig struct { + // TaskHistoryRetentionLimit is the number of historic tasks to keep per instance or + // node. If negative, never remove completed or failed tasks. + TaskHistoryRetentionLimit *int64 `json:",omitempty"` +} + +// TaskDefaults parameterizes cluster-level task creation with default values. +type TaskDefaults struct { + // LogDriver selects the log driver to use for tasks created in the + // orchestrator if unspecified by a service. + // + // Updating this value will only have an affect on new tasks. Old tasks + // will continue use their previously configured log driver until + // recreated. + LogDriver *Driver `json:",omitempty"` +} + +// EncryptionConfig controls at-rest encryption of data and keys. +type EncryptionConfig struct { + // AutoLockManagers specifies whether or not managers TLS keys and raft data + // should be encrypted at rest in such a way that they must be unlocked + // before the manager node starts up again. + AutoLockManagers bool +} + +// RaftConfig represents raft configuration. +type RaftConfig struct { + // SnapshotInterval is the number of log entries between snapshots. + SnapshotInterval uint64 `json:",omitempty"` + + // KeepOldSnapshots is the number of snapshots to keep beyond the + // current snapshot. + KeepOldSnapshots *uint64 `json:",omitempty"` + + // LogEntriesForSlowFollowers is the number of log entries to keep + // around to sync up slow followers after a snapshot is created. + LogEntriesForSlowFollowers uint64 `json:",omitempty"` + + // ElectionTick is the number of ticks that a follower will wait for a message + // from the leader before becoming a candidate and starting an election. + // ElectionTick must be greater than HeartbeatTick. + // + // A tick currently defaults to one second, so these translate directly to + // seconds currently, but this is NOT guaranteed. + ElectionTick int + + // HeartbeatTick is the number of ticks between heartbeats. Every + // HeartbeatTick ticks, the leader will send a heartbeat to the + // followers. + // + // A tick currently defaults to one second, so these translate directly to + // seconds currently, but this is NOT guaranteed. + HeartbeatTick int +} + +// DispatcherConfig represents dispatcher configuration. +type DispatcherConfig struct { + // HeartbeatPeriod defines how often agent should send heartbeats to + // dispatcher. + HeartbeatPeriod time.Duration `json:",omitempty"` +} + +// CAConfig represents CA configuration. +type CAConfig struct { + // NodeCertExpiry is the duration certificates should be issued for + NodeCertExpiry time.Duration `json:",omitempty"` + + // ExternalCAs is a list of CAs to which a manager node will make + // certificate signing requests for node certificates. + ExternalCAs []*ExternalCA `json:",omitempty"` + + // SigningCACert and SigningCAKey specify the desired signing root CA and + // root CA key for the swarm. When inspecting the cluster, the key will + // be redacted. + SigningCACert string `json:",omitempty"` + SigningCAKey string `json:",omitempty"` + + // If this value changes, and there is no specified signing cert and key, + // then the swarm is forced to generate a new root certificate ane key. + ForceRotate uint64 `json:",omitempty"` +} + +// ExternalCAProtocol represents type of external CA. +type ExternalCAProtocol string + +// ExternalCAProtocolCFSSL CFSSL +const ExternalCAProtocolCFSSL ExternalCAProtocol = "cfssl" + +// ExternalCA defines external CA to be used by the cluster. +type ExternalCA struct { + // Protocol is the protocol used by this external CA. + Protocol ExternalCAProtocol + + // URL is the URL where the external CA can be reached. + URL string + + // Options is a set of additional key/value pairs whose interpretation + // depends on the specified CA type. + Options map[string]string `json:",omitempty"` + + // CACert specifies which root CA is used by this external CA. This certificate must + // be in PEM format. + CACert string +} + +// InitRequest is the request used to init a swarm. +type InitRequest struct { + ListenAddr string + AdvertiseAddr string + DataPathAddr string + DataPathPort uint32 + ForceNewCluster bool + Spec Spec + AutoLockManagers bool + Availability NodeAvailability + DefaultAddrPool []string + SubnetSize uint32 +} + +// JoinRequest is the request used to join a swarm. +type JoinRequest struct { + ListenAddr string + AdvertiseAddr string + DataPathAddr string + RemoteAddrs []string + JoinToken string // accept by secret + Availability NodeAvailability +} + +// UnlockRequest is the request used to unlock a swarm. +type UnlockRequest struct { + // UnlockKey is the unlock key in ASCII-armored format. + UnlockKey string +} + +// LocalNodeState represents the state of the local node. +type LocalNodeState string + +const ( + // LocalNodeStateInactive INACTIVE + LocalNodeStateInactive LocalNodeState = "inactive" + // LocalNodeStatePending PENDING + LocalNodeStatePending LocalNodeState = "pending" + // LocalNodeStateActive ACTIVE + LocalNodeStateActive LocalNodeState = "active" + // LocalNodeStateError ERROR + LocalNodeStateError LocalNodeState = "error" + // LocalNodeStateLocked LOCKED + LocalNodeStateLocked LocalNodeState = "locked" +) + +// Info represents generic information about swarm. +type Info struct { + NodeID string + NodeAddr string + + LocalNodeState LocalNodeState + ControlAvailable bool + Error string + + RemoteManagers []Peer + Nodes int `json:",omitempty"` + Managers int `json:",omitempty"` + + Cluster *ClusterInfo `json:",omitempty"` + + Warnings []string `json:",omitempty"` +} + +// Status provides information about the current swarm status and role, +// obtained from the "Swarm" header in the API response. +type Status struct { + // NodeState represents the state of the node. + NodeState LocalNodeState + + // ControlAvailable indicates if the node is a swarm manager. + ControlAvailable bool +} + +// Peer represents a peer. +type Peer struct { + NodeID string + Addr string +} + +// UpdateFlags contains flags for SwarmUpdate. +type UpdateFlags struct { + RotateWorkerToken bool + RotateManagerToken bool + RotateManagerUnlockKey bool +} diff --git a/vendor/github.com/docker/docker/api/types/swarm/task.go b/vendor/github.com/docker/docker/api/types/swarm/task.go new file mode 100644 index 0000000000..ad3eeca0b7 --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/swarm/task.go @@ -0,0 +1,225 @@ +package swarm // import "github.com/docker/docker/api/types/swarm" + +import ( + "time" + + "github.com/docker/docker/api/types/swarm/runtime" +) + +// TaskState represents the state of a task. +type TaskState string + +const ( + // TaskStateNew NEW + TaskStateNew TaskState = "new" + // TaskStateAllocated ALLOCATED + TaskStateAllocated TaskState = "allocated" + // TaskStatePending PENDING + TaskStatePending TaskState = "pending" + // TaskStateAssigned ASSIGNED + TaskStateAssigned TaskState = "assigned" + // TaskStateAccepted ACCEPTED + TaskStateAccepted TaskState = "accepted" + // TaskStatePreparing PREPARING + TaskStatePreparing TaskState = "preparing" + // TaskStateReady READY + TaskStateReady TaskState = "ready" + // TaskStateStarting STARTING + TaskStateStarting TaskState = "starting" + // TaskStateRunning RUNNING + TaskStateRunning TaskState = "running" + // TaskStateComplete COMPLETE + TaskStateComplete TaskState = "complete" + // TaskStateShutdown SHUTDOWN + TaskStateShutdown TaskState = "shutdown" + // TaskStateFailed FAILED + TaskStateFailed TaskState = "failed" + // TaskStateRejected REJECTED + TaskStateRejected TaskState = "rejected" + // TaskStateRemove REMOVE + TaskStateRemove TaskState = "remove" + // TaskStateOrphaned ORPHANED + TaskStateOrphaned TaskState = "orphaned" +) + +// Task represents a task. +type Task struct { + ID string + Meta + Annotations + + Spec TaskSpec `json:",omitempty"` + ServiceID string `json:",omitempty"` + Slot int `json:",omitempty"` + NodeID string `json:",omitempty"` + Status TaskStatus `json:",omitempty"` + DesiredState TaskState `json:",omitempty"` + NetworksAttachments []NetworkAttachment `json:",omitempty"` + GenericResources []GenericResource `json:",omitempty"` + + // JobIteration is the JobIteration of the Service that this Task was + // spawned from, if the Service is a ReplicatedJob or GlobalJob. This is + // used to determine which Tasks belong to which run of the job. This field + // is absent if the Service mode is Replicated or Global. + JobIteration *Version `json:",omitempty"` + + // Volumes is the list of VolumeAttachments for this task. It specifies + // which particular volumes are to be used by this particular task, and + // fulfilling what mounts in the spec. + Volumes []VolumeAttachment +} + +// TaskSpec represents the spec of a task. +type TaskSpec struct { + // ContainerSpec, NetworkAttachmentSpec, and PluginSpec are mutually exclusive. + // PluginSpec is only used when the `Runtime` field is set to `plugin` + // NetworkAttachmentSpec is used if the `Runtime` field is set to + // `attachment`. + ContainerSpec *ContainerSpec `json:",omitempty"` + PluginSpec *runtime.PluginSpec `json:",omitempty"` + NetworkAttachmentSpec *NetworkAttachmentSpec `json:",omitempty"` + + Resources *ResourceRequirements `json:",omitempty"` + RestartPolicy *RestartPolicy `json:",omitempty"` + Placement *Placement `json:",omitempty"` + Networks []NetworkAttachmentConfig `json:",omitempty"` + + // LogDriver specifies the LogDriver to use for tasks created from this + // spec. If not present, the one on cluster default on swarm.Spec will be + // used, finally falling back to the engine default if not specified. + LogDriver *Driver `json:",omitempty"` + + // ForceUpdate is a counter that triggers an update even if no relevant + // parameters have been changed. + ForceUpdate uint64 + + Runtime RuntimeType `json:",omitempty"` +} + +// Resources represents resources (CPU/Memory) which can be advertised by a +// node and requested to be reserved for a task. +type Resources struct { + NanoCPUs int64 `json:",omitempty"` + MemoryBytes int64 `json:",omitempty"` + GenericResources []GenericResource `json:",omitempty"` +} + +// Limit describes limits on resources which can be requested by a task. +type Limit struct { + NanoCPUs int64 `json:",omitempty"` + MemoryBytes int64 `json:",omitempty"` + Pids int64 `json:",omitempty"` +} + +// GenericResource represents a "user defined" resource which can +// be either an integer (e.g: SSD=3) or a string (e.g: SSD=sda1) +type GenericResource struct { + NamedResourceSpec *NamedGenericResource `json:",omitempty"` + DiscreteResourceSpec *DiscreteGenericResource `json:",omitempty"` +} + +// NamedGenericResource represents a "user defined" resource which is defined +// as a string. +// "Kind" is used to describe the Kind of a resource (e.g: "GPU", "FPGA", "SSD", ...) +// Value is used to identify the resource (GPU="UUID-1", FPGA="/dev/sdb5", ...) +type NamedGenericResource struct { + Kind string `json:",omitempty"` + Value string `json:",omitempty"` +} + +// DiscreteGenericResource represents a "user defined" resource which is defined +// as an integer +// "Kind" is used to describe the Kind of a resource (e.g: "GPU", "FPGA", "SSD", ...) +// Value is used to count the resource (SSD=5, HDD=3, ...) +type DiscreteGenericResource struct { + Kind string `json:",omitempty"` + Value int64 `json:",omitempty"` +} + +// ResourceRequirements represents resources requirements. +type ResourceRequirements struct { + Limits *Limit `json:",omitempty"` + Reservations *Resources `json:",omitempty"` +} + +// Placement represents orchestration parameters. +type Placement struct { + Constraints []string `json:",omitempty"` + Preferences []PlacementPreference `json:",omitempty"` + MaxReplicas uint64 `json:",omitempty"` + + // Platforms stores all the platforms that the image can run on. + // This field is used in the platform filter for scheduling. If empty, + // then the platform filter is off, meaning there are no scheduling restrictions. + Platforms []Platform `json:",omitempty"` +} + +// PlacementPreference provides a way to make the scheduler aware of factors +// such as topology. +type PlacementPreference struct { + Spread *SpreadOver +} + +// SpreadOver is a scheduling preference that instructs the scheduler to spread +// tasks evenly over groups of nodes identified by labels. +type SpreadOver struct { + // label descriptor, such as engine.labels.az + SpreadDescriptor string +} + +// RestartPolicy represents the restart policy. +type RestartPolicy struct { + Condition RestartPolicyCondition `json:",omitempty"` + Delay *time.Duration `json:",omitempty"` + MaxAttempts *uint64 `json:",omitempty"` + Window *time.Duration `json:",omitempty"` +} + +// RestartPolicyCondition represents when to restart. +type RestartPolicyCondition string + +const ( + // RestartPolicyConditionNone NONE + RestartPolicyConditionNone RestartPolicyCondition = "none" + // RestartPolicyConditionOnFailure ON_FAILURE + RestartPolicyConditionOnFailure RestartPolicyCondition = "on-failure" + // RestartPolicyConditionAny ANY + RestartPolicyConditionAny RestartPolicyCondition = "any" +) + +// TaskStatus represents the status of a task. +type TaskStatus struct { + Timestamp time.Time `json:",omitempty"` + State TaskState `json:",omitempty"` + Message string `json:",omitempty"` + Err string `json:",omitempty"` + ContainerStatus *ContainerStatus `json:",omitempty"` + PortStatus PortStatus `json:",omitempty"` +} + +// ContainerStatus represents the status of a container. +type ContainerStatus struct { + ContainerID string + PID int + ExitCode int +} + +// PortStatus represents the port status of a task's host ports whose +// service has published host ports +type PortStatus struct { + Ports []PortConfig `json:",omitempty"` +} + +// VolumeAttachment contains the associating a Volume to a Task. +type VolumeAttachment struct { + // ID is the Swarmkit ID of the Volume. This is not the CSI VolumeId. + ID string `json:",omitempty"` + + // Source, together with Target, indicates the Mount, as specified in the + // ContainerSpec, that this volume fulfills. + Source string `json:",omitempty"` + + // Target, together with Source, indicates the Mount, as specified + // in the ContainerSpec, that this volume fulfills. + Target string `json:",omitempty"` +} diff --git a/vendor/github.com/docker/docker/api/types/time/timestamp.go b/vendor/github.com/docker/docker/api/types/time/timestamp.go new file mode 100644 index 0000000000..2a74b7a597 --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/time/timestamp.go @@ -0,0 +1,131 @@ +package time // import "github.com/docker/docker/api/types/time" + +import ( + "fmt" + "math" + "strconv" + "strings" + "time" +) + +// These are additional predefined layouts for use in Time.Format and Time.Parse +// with --since and --until parameters for `docker logs` and `docker events` +const ( + rFC3339Local = "2006-01-02T15:04:05" // RFC3339 with local timezone + rFC3339NanoLocal = "2006-01-02T15:04:05.999999999" // RFC3339Nano with local timezone + dateWithZone = "2006-01-02Z07:00" // RFC3339 with time at 00:00:00 + dateLocal = "2006-01-02" // RFC3339 with local timezone and time at 00:00:00 +) + +// GetTimestamp tries to parse given string as golang duration, +// then RFC3339 time and finally as a Unix timestamp. If +// any of these were successful, it returns a Unix timestamp +// as string otherwise returns the given value back. +// In case of duration input, the returned timestamp is computed +// as the given reference time minus the amount of the duration. +func GetTimestamp(value string, reference time.Time) (string, error) { + if d, err := time.ParseDuration(value); value != "0" && err == nil { + return strconv.FormatInt(reference.Add(-d).Unix(), 10), nil + } + + var format string + // if the string has a Z or a + or three dashes use parse otherwise use parseinlocation + parseInLocation := !(strings.ContainsAny(value, "zZ+") || strings.Count(value, "-") == 3) + + if strings.Contains(value, ".") { + if parseInLocation { + format = rFC3339NanoLocal + } else { + format = time.RFC3339Nano + } + } else if strings.Contains(value, "T") { + // we want the number of colons in the T portion of the timestamp + tcolons := strings.Count(value, ":") + // if parseInLocation is off and we have a +/- zone offset (not Z) then + // there will be an extra colon in the input for the tz offset subtract that + // colon from the tcolons count + if !parseInLocation && !strings.ContainsAny(value, "zZ") && tcolons > 0 { + tcolons-- + } + if parseInLocation { + switch tcolons { + case 0: + format = "2006-01-02T15" + case 1: + format = "2006-01-02T15:04" + default: + format = rFC3339Local + } + } else { + switch tcolons { + case 0: + format = "2006-01-02T15Z07:00" + case 1: + format = "2006-01-02T15:04Z07:00" + default: + format = time.RFC3339 + } + } + } else if parseInLocation { + format = dateLocal + } else { + format = dateWithZone + } + + var t time.Time + var err error + + if parseInLocation { + t, err = time.ParseInLocation(format, value, time.FixedZone(reference.Zone())) + } else { + t, err = time.Parse(format, value) + } + + if err != nil { + // if there is a `-` then it's an RFC3339 like timestamp + if strings.Contains(value, "-") { + return "", err // was probably an RFC3339 like timestamp but the parser failed with an error + } + if _, _, err := parseTimestamp(value); err != nil { + return "", fmt.Errorf("failed to parse value as time or duration: %q", value) + } + return value, nil // unix timestamp in and out case (meaning: the value passed at the command line is already in the right format for passing to the server) + } + + return fmt.Sprintf("%d.%09d", t.Unix(), int64(t.Nanosecond())), nil +} + +// ParseTimestamps returns seconds and nanoseconds from a timestamp that has the +// format "%d.%09d", time.Unix(), int64(time.Nanosecond())) +// if the incoming nanosecond portion is longer or shorter than 9 digits it is +// converted to nanoseconds. The expectation is that the seconds and +// seconds will be used to create a time variable. For example: +// +// seconds, nanoseconds, err := ParseTimestamp("1136073600.000000001",0) +// if err == nil since := time.Unix(seconds, nanoseconds) +// +// returns seconds as def(aultSeconds) if value == "" +func ParseTimestamps(value string, def int64) (int64, int64, error) { + if value == "" { + return def, 0, nil + } + return parseTimestamp(value) +} + +func parseTimestamp(value string) (int64, int64, error) { + sa := strings.SplitN(value, ".", 2) + s, err := strconv.ParseInt(sa[0], 10, 64) + if err != nil { + return s, 0, err + } + if len(sa) != 2 { + return s, 0, nil + } + n, err := strconv.ParseInt(sa[1], 10, 64) + if err != nil { + return s, n, err + } + // should already be in nanoseconds but just in case convert n to nanoseconds + n = int64(float64(n) * math.Pow(float64(10), float64(9-len(sa[1])))) + return s, n, nil +} diff --git a/vendor/github.com/docker/docker/api/types/types.go b/vendor/github.com/docker/docker/api/types/types.go new file mode 100644 index 0000000000..036405299e --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/types.go @@ -0,0 +1,809 @@ +package types // import "github.com/docker/docker/api/types" + +import ( + "errors" + "fmt" + "io" + "os" + "strings" + "time" + + "github.com/docker/docker/api/types/container" + "github.com/docker/docker/api/types/filters" + "github.com/docker/docker/api/types/mount" + "github.com/docker/docker/api/types/network" + "github.com/docker/docker/api/types/registry" + "github.com/docker/docker/api/types/swarm" + "github.com/docker/docker/api/types/volume" + "github.com/docker/go-connections/nat" +) + +const ( + // MediaTypeRawStream is vendor specific MIME-Type set for raw TTY streams + MediaTypeRawStream = "application/vnd.docker.raw-stream" + + // MediaTypeMultiplexedStream is vendor specific MIME-Type set for stdin/stdout/stderr multiplexed streams + MediaTypeMultiplexedStream = "application/vnd.docker.multiplexed-stream" +) + +// RootFS returns Image's RootFS description including the layer IDs. +type RootFS struct { + Type string `json:",omitempty"` + Layers []string `json:",omitempty"` +} + +// ImageInspect contains response of Engine API: +// GET "/images/{name:.*}/json" +type ImageInspect struct { + // ID is the content-addressable ID of an image. + // + // This identifier is a content-addressable digest calculated from the + // image's configuration (which includes the digests of layers used by + // the image). + // + // Note that this digest differs from the `RepoDigests` below, which + // holds digests of image manifests that reference the image. + ID string `json:"Id"` + + // RepoTags is a list of image names/tags in the local image cache that + // reference this image. + // + // Multiple image tags can refer to the same image, and this list may be + // empty if no tags reference the image, in which case the image is + // "untagged", in which case it can still be referenced by its ID. + RepoTags []string + + // RepoDigests is a list of content-addressable digests of locally available + // image manifests that the image is referenced from. Multiple manifests can + // refer to the same image. + // + // These digests are usually only available if the image was either pulled + // from a registry, or if the image was pushed to a registry, which is when + // the manifest is generated and its digest calculated. + RepoDigests []string + + // Parent is the ID of the parent image. + // + // Depending on how the image was created, this field may be empty and + // is only set for images that were built/created locally. This field + // is empty if the image was pulled from an image registry. + Parent string + + // Comment is an optional message that can be set when committing or + // importing the image. + Comment string + + // Created is the date and time at which the image was created, formatted in + // RFC 3339 nano-seconds (time.RFC3339Nano). + Created string + + // Container is the ID of the container that was used to create the image. + // + // Depending on how the image was created, this field may be empty. + Container string + + // ContainerConfig is an optional field containing the configuration of the + // container that was last committed when creating the image. + // + // Previous versions of Docker builder used this field to store build cache, + // and it is not in active use anymore. + ContainerConfig *container.Config + + // DockerVersion is the version of Docker that was used to build the image. + // + // Depending on how the image was created, this field may be empty. + DockerVersion string + + // Author is the name of the author that was specified when committing the + // image, or as specified through MAINTAINER (deprecated) in the Dockerfile. + Author string + Config *container.Config + + // Architecture is the hardware CPU architecture that the image runs on. + Architecture string + + // Variant is the CPU architecture variant (presently ARM-only). + Variant string `json:",omitempty"` + + // OS is the Operating System the image is built to run on. + Os string + + // OsVersion is the version of the Operating System the image is built to + // run on (especially for Windows). + OsVersion string `json:",omitempty"` + + // Size is the total size of the image including all layers it is composed of. + Size int64 + + // VirtualSize is the total size of the image including all layers it is + // composed of. + // + // In versions of Docker before v1.10, this field was calculated from + // the image itself and all of its parent images. Docker v1.10 and up + // store images self-contained, and no longer use a parent-chain, making + // this field an equivalent of the Size field. + // + // This field is kept for backward compatibility, but may be removed in + // a future version of the API. + VirtualSize int64 // TODO(thaJeztah): deprecate this field + + // GraphDriver holds information about the storage driver used to store the + // container's and image's filesystem. + GraphDriver GraphDriverData + + // RootFS contains information about the image's RootFS, including the + // layer IDs. + RootFS RootFS + + // Metadata of the image in the local cache. + // + // This information is local to the daemon, and not part of the image itself. + Metadata ImageMetadata +} + +// ImageMetadata contains engine-local data about the image +type ImageMetadata struct { + // LastTagTime is the date and time at which the image was last tagged. + LastTagTime time.Time `json:",omitempty"` +} + +// Container contains response of Engine API: +// GET "/containers/json" +type Container struct { + ID string `json:"Id"` + Names []string + Image string + ImageID string + Command string + Created int64 + Ports []Port + SizeRw int64 `json:",omitempty"` + SizeRootFs int64 `json:",omitempty"` + Labels map[string]string + State string + Status string + HostConfig struct { + NetworkMode string `json:",omitempty"` + } + NetworkSettings *SummaryNetworkSettings + Mounts []MountPoint +} + +// CopyConfig contains request body of Engine API: +// POST "/containers/"+containerID+"/copy" +type CopyConfig struct { + Resource string +} + +// ContainerPathStat is used to encode the header from +// GET "/containers/{name:.*}/archive" +// "Name" is the file or directory name. +type ContainerPathStat struct { + Name string `json:"name"` + Size int64 `json:"size"` + Mode os.FileMode `json:"mode"` + Mtime time.Time `json:"mtime"` + LinkTarget string `json:"linkTarget"` +} + +// ContainerStats contains response of Engine API: +// GET "/stats" +type ContainerStats struct { + Body io.ReadCloser `json:"body"` + OSType string `json:"ostype"` +} + +// Ping contains response of Engine API: +// GET "/_ping" +type Ping struct { + APIVersion string + OSType string + Experimental bool + BuilderVersion BuilderVersion + + // SwarmStatus provides information about the current swarm status of the + // engine, obtained from the "Swarm" header in the API response. + // + // It can be a nil struct if the API version does not provide this header + // in the ping response, or if an error occurred, in which case the client + // should use other ways to get the current swarm status, such as the /swarm + // endpoint. + SwarmStatus *swarm.Status +} + +// ComponentVersion describes the version information for a specific component. +type ComponentVersion struct { + Name string + Version string + Details map[string]string `json:",omitempty"` +} + +// Version contains response of Engine API: +// GET "/version" +type Version struct { + Platform struct{ Name string } `json:",omitempty"` + Components []ComponentVersion `json:",omitempty"` + + // The following fields are deprecated, they relate to the Engine component and are kept for backwards compatibility + + Version string + APIVersion string `json:"ApiVersion"` + MinAPIVersion string `json:"MinAPIVersion,omitempty"` + GitCommit string + GoVersion string + Os string + Arch string + KernelVersion string `json:",omitempty"` + Experimental bool `json:",omitempty"` + BuildTime string `json:",omitempty"` +} + +// Commit holds the Git-commit (SHA1) that a binary was built from, as reported +// in the version-string of external tools, such as containerd, or runC. +type Commit struct { + ID string // ID is the actual commit ID of external tool. + Expected string // Expected is the commit ID of external tool expected by dockerd as set at build time. +} + +// Info contains response of Engine API: +// GET "/info" +type Info struct { + ID string + Containers int + ContainersRunning int + ContainersPaused int + ContainersStopped int + Images int + Driver string + DriverStatus [][2]string + SystemStatus [][2]string `json:",omitempty"` // SystemStatus is only propagated by the Swarm standalone API + Plugins PluginsInfo + MemoryLimit bool + SwapLimit bool + KernelMemory bool `json:",omitempty"` // Deprecated: kernel 5.4 deprecated kmem.limit_in_bytes + KernelMemoryTCP bool `json:",omitempty"` // KernelMemoryTCP is not supported on cgroups v2. + CPUCfsPeriod bool `json:"CpuCfsPeriod"` + CPUCfsQuota bool `json:"CpuCfsQuota"` + CPUShares bool + CPUSet bool + PidsLimit bool + IPv4Forwarding bool + BridgeNfIptables bool + BridgeNfIP6tables bool `json:"BridgeNfIp6tables"` + Debug bool + NFd int + OomKillDisable bool + NGoroutines int + SystemTime string + LoggingDriver string + CgroupDriver string + CgroupVersion string `json:",omitempty"` + NEventsListener int + KernelVersion string + OperatingSystem string + OSVersion string + OSType string + Architecture string + IndexServerAddress string + RegistryConfig *registry.ServiceConfig + NCPU int + MemTotal int64 + GenericResources []swarm.GenericResource + DockerRootDir string + HTTPProxy string `json:"HttpProxy"` + HTTPSProxy string `json:"HttpsProxy"` + NoProxy string + Name string + Labels []string + ExperimentalBuild bool + ServerVersion string + ClusterStore string `json:",omitempty"` // Deprecated: host-discovery and overlay networks with external k/v stores are deprecated + ClusterAdvertise string `json:",omitempty"` // Deprecated: host-discovery and overlay networks with external k/v stores are deprecated + Runtimes map[string]Runtime + DefaultRuntime string + Swarm swarm.Info + // LiveRestoreEnabled determines whether containers should be kept + // running when the daemon is shutdown or upon daemon start if + // running containers are detected + LiveRestoreEnabled bool + Isolation container.Isolation + InitBinary string + ContainerdCommit Commit + RuncCommit Commit + InitCommit Commit + SecurityOptions []string + ProductLicense string `json:",omitempty"` + DefaultAddressPools []NetworkAddressPool `json:",omitempty"` + + // Warnings contains a slice of warnings that occurred while collecting + // system information. These warnings are intended to be informational + // messages for the user, and are not intended to be parsed / used for + // other purposes, as they do not have a fixed format. + Warnings []string +} + +// KeyValue holds a key/value pair +type KeyValue struct { + Key, Value string +} + +// NetworkAddressPool is a temp struct used by Info struct +type NetworkAddressPool struct { + Base string + Size int +} + +// SecurityOpt contains the name and options of a security option +type SecurityOpt struct { + Name string + Options []KeyValue +} + +// DecodeSecurityOptions decodes a security options string slice to a type safe +// SecurityOpt +func DecodeSecurityOptions(opts []string) ([]SecurityOpt, error) { + so := []SecurityOpt{} + for _, opt := range opts { + // support output from a < 1.13 docker daemon + if !strings.Contains(opt, "=") { + so = append(so, SecurityOpt{Name: opt}) + continue + } + secopt := SecurityOpt{} + split := strings.Split(opt, ",") + for _, s := range split { + kv := strings.SplitN(s, "=", 2) + if len(kv) != 2 { + return nil, fmt.Errorf("invalid security option %q", s) + } + if kv[0] == "" || kv[1] == "" { + return nil, errors.New("invalid empty security option") + } + if kv[0] == "name" { + secopt.Name = kv[1] + continue + } + secopt.Options = append(secopt.Options, KeyValue{Key: kv[0], Value: kv[1]}) + } + so = append(so, secopt) + } + return so, nil +} + +// PluginsInfo is a temp struct holding Plugins name +// registered with docker daemon. It is used by Info struct +type PluginsInfo struct { + // List of Volume plugins registered + Volume []string + // List of Network plugins registered + Network []string + // List of Authorization plugins registered + Authorization []string + // List of Log plugins registered + Log []string +} + +// ExecStartCheck is a temp struct used by execStart +// Config fields is part of ExecConfig in runconfig package +type ExecStartCheck struct { + // ExecStart will first check if it's detached + Detach bool + // Check if there's a tty + Tty bool + // Terminal size [height, width], unused if Tty == false + ConsoleSize *[2]uint `json:",omitempty"` +} + +// HealthcheckResult stores information about a single run of a healthcheck probe +type HealthcheckResult struct { + Start time.Time // Start is the time this check started + End time.Time // End is the time this check ended + ExitCode int // ExitCode meanings: 0=healthy, 1=unhealthy, 2=reserved (considered unhealthy), else=error running probe + Output string // Output from last check +} + +// Health states +const ( + NoHealthcheck = "none" // Indicates there is no healthcheck + Starting = "starting" // Starting indicates that the container is not yet ready + Healthy = "healthy" // Healthy indicates that the container is running correctly + Unhealthy = "unhealthy" // Unhealthy indicates that the container has a problem +) + +// Health stores information about the container's healthcheck results +type Health struct { + Status string // Status is one of Starting, Healthy or Unhealthy + FailingStreak int // FailingStreak is the number of consecutive failures + Log []*HealthcheckResult // Log contains the last few results (oldest first) +} + +// ContainerState stores container's running state +// it's part of ContainerJSONBase and will return by "inspect" command +type ContainerState struct { + Status string // String representation of the container state. Can be one of "created", "running", "paused", "restarting", "removing", "exited", or "dead" + Running bool + Paused bool + Restarting bool + OOMKilled bool + Dead bool + Pid int + ExitCode int + Error string + StartedAt string + FinishedAt string + Health *Health `json:",omitempty"` +} + +// ContainerNode stores information about the node that a container +// is running on. It's only used by the Docker Swarm standalone API +type ContainerNode struct { + ID string + IPAddress string `json:"IP"` + Addr string + Name string + Cpus int + Memory int64 + Labels map[string]string +} + +// ContainerJSONBase contains response of Engine API: +// GET "/containers/{name:.*}/json" +type ContainerJSONBase struct { + ID string `json:"Id"` + Created string + Path string + Args []string + State *ContainerState + Image string + ResolvConfPath string + HostnamePath string + HostsPath string + LogPath string + Node *ContainerNode `json:",omitempty"` // Node is only propagated by Docker Swarm standalone API + Name string + RestartCount int + Driver string + Platform string + MountLabel string + ProcessLabel string + AppArmorProfile string + ExecIDs []string + HostConfig *container.HostConfig + GraphDriver GraphDriverData + SizeRw *int64 `json:",omitempty"` + SizeRootFs *int64 `json:",omitempty"` +} + +// ContainerJSON is newly used struct along with MountPoint +type ContainerJSON struct { + *ContainerJSONBase + Mounts []MountPoint + Config *container.Config + NetworkSettings *NetworkSettings +} + +// NetworkSettings exposes the network settings in the api +type NetworkSettings struct { + NetworkSettingsBase + DefaultNetworkSettings + Networks map[string]*network.EndpointSettings +} + +// SummaryNetworkSettings provides a summary of container's networks +// in /containers/json +type SummaryNetworkSettings struct { + Networks map[string]*network.EndpointSettings +} + +// NetworkSettingsBase holds basic information about networks +type NetworkSettingsBase struct { + Bridge string // Bridge is the Bridge name the network uses(e.g. `docker0`) + SandboxID string // SandboxID uniquely represents a container's network stack + HairpinMode bool // HairpinMode specifies if hairpin NAT should be enabled on the virtual interface + LinkLocalIPv6Address string // LinkLocalIPv6Address is an IPv6 unicast address using the link-local prefix + LinkLocalIPv6PrefixLen int // LinkLocalIPv6PrefixLen is the prefix length of an IPv6 unicast address + Ports nat.PortMap // Ports is a collection of PortBinding indexed by Port + SandboxKey string // SandboxKey identifies the sandbox + SecondaryIPAddresses []network.Address + SecondaryIPv6Addresses []network.Address +} + +// DefaultNetworkSettings holds network information +// during the 2 release deprecation period. +// It will be removed in Docker 1.11. +type DefaultNetworkSettings struct { + EndpointID string // EndpointID uniquely represents a service endpoint in a Sandbox + Gateway string // Gateway holds the gateway address for the network + GlobalIPv6Address string // GlobalIPv6Address holds network's global IPv6 address + GlobalIPv6PrefixLen int // GlobalIPv6PrefixLen represents mask length of network's global IPv6 address + IPAddress string // IPAddress holds the IPv4 address for the network + IPPrefixLen int // IPPrefixLen represents mask length of network's IPv4 address + IPv6Gateway string // IPv6Gateway holds gateway address specific for IPv6 + MacAddress string // MacAddress holds the MAC address for the network +} + +// MountPoint represents a mount point configuration inside the container. +// This is used for reporting the mountpoints in use by a container. +type MountPoint struct { + // Type is the type of mount, see `Type` definitions in + // github.com/docker/docker/api/types/mount.Type + Type mount.Type `json:",omitempty"` + + // Name is the name reference to the underlying data defined by `Source` + // e.g., the volume name. + Name string `json:",omitempty"` + + // Source is the source location of the mount. + // + // For volumes, this contains the storage location of the volume (within + // `/var/lib/docker/volumes/`). For bind-mounts, and `npipe`, this contains + // the source (host) part of the bind-mount. For `tmpfs` mount points, this + // field is empty. + Source string + + // Destination is the path relative to the container root (`/`) where the + // Source is mounted inside the container. + Destination string + + // Driver is the volume driver used to create the volume (if it is a volume). + Driver string `json:",omitempty"` + + // Mode is a comma separated list of options supplied by the user when + // creating the bind/volume mount. + // + // The default is platform-specific (`"z"` on Linux, empty on Windows). + Mode string + + // RW indicates whether the mount is mounted writable (read-write). + RW bool + + // Propagation describes how mounts are propagated from the host into the + // mount point, and vice-versa. Refer to the Linux kernel documentation + // for details: + // https://www.kernel.org/doc/Documentation/filesystems/sharedsubtree.txt + // + // This field is not used on Windows. + Propagation mount.Propagation +} + +// NetworkResource is the body of the "get network" http response message +type NetworkResource struct { + Name string // Name is the requested name of the network + ID string `json:"Id"` // ID uniquely identifies a network on a single machine + Created time.Time // Created is the time the network created + Scope string // Scope describes the level at which the network exists (e.g. `swarm` for cluster-wide or `local` for machine level) + Driver string // Driver is the Driver name used to create the network (e.g. `bridge`, `overlay`) + EnableIPv6 bool // EnableIPv6 represents whether to enable IPv6 + IPAM network.IPAM // IPAM is the network's IP Address Management + Internal bool // Internal represents if the network is used internal only + Attachable bool // Attachable represents if the global scope is manually attachable by regular containers from workers in swarm mode. + Ingress bool // Ingress indicates the network is providing the routing-mesh for the swarm cluster. + ConfigFrom network.ConfigReference // ConfigFrom specifies the source which will provide the configuration for this network. + ConfigOnly bool // ConfigOnly networks are place-holder networks for network configurations to be used by other networks. ConfigOnly networks cannot be used directly to run containers or services. + Containers map[string]EndpointResource // Containers contains endpoints belonging to the network + Options map[string]string // Options holds the network specific options to use for when creating the network + Labels map[string]string // Labels holds metadata specific to the network being created + Peers []network.PeerInfo `json:",omitempty"` // List of peer nodes for an overlay network + Services map[string]network.ServiceInfo `json:",omitempty"` +} + +// EndpointResource contains network resources allocated and used for a container in a network +type EndpointResource struct { + Name string + EndpointID string + MacAddress string + IPv4Address string + IPv6Address string +} + +// NetworkCreate is the expected body of the "create network" http request message +type NetworkCreate struct { + // Check for networks with duplicate names. + // Network is primarily keyed based on a random ID and not on the name. + // Network name is strictly a user-friendly alias to the network + // which is uniquely identified using ID. + // And there is no guaranteed way to check for duplicates. + // Option CheckDuplicate is there to provide a best effort checking of any networks + // which has the same name but it is not guaranteed to catch all name collisions. + CheckDuplicate bool + Driver string + Scope string + EnableIPv6 bool + IPAM *network.IPAM + Internal bool + Attachable bool + Ingress bool + ConfigOnly bool + ConfigFrom *network.ConfigReference + Options map[string]string + Labels map[string]string +} + +// NetworkCreateRequest is the request message sent to the server for network create call. +type NetworkCreateRequest struct { + NetworkCreate + Name string +} + +// NetworkCreateResponse is the response message sent by the server for network create call +type NetworkCreateResponse struct { + ID string `json:"Id"` + Warning string +} + +// NetworkConnect represents the data to be used to connect a container to the network +type NetworkConnect struct { + Container string + EndpointConfig *network.EndpointSettings `json:",omitempty"` +} + +// NetworkDisconnect represents the data to be used to disconnect a container from the network +type NetworkDisconnect struct { + Container string + Force bool +} + +// NetworkInspectOptions holds parameters to inspect network +type NetworkInspectOptions struct { + Scope string + Verbose bool +} + +// Checkpoint represents the details of a checkpoint +type Checkpoint struct { + Name string // Name is the name of the checkpoint +} + +// Runtime describes an OCI runtime +type Runtime struct { + Path string `json:"path"` + Args []string `json:"runtimeArgs,omitempty"` + + // This is exposed here only for internal use + // It is not currently supported to specify custom shim configs + Shim *ShimConfig `json:"-"` +} + +// ShimConfig is used by runtime to configure containerd shims +type ShimConfig struct { + Binary string + Opts interface{} +} + +// DiskUsageObject represents an object type used for disk usage query filtering. +type DiskUsageObject string + +const ( + // ContainerObject represents a container DiskUsageObject. + ContainerObject DiskUsageObject = "container" + // ImageObject represents an image DiskUsageObject. + ImageObject DiskUsageObject = "image" + // VolumeObject represents a volume DiskUsageObject. + VolumeObject DiskUsageObject = "volume" + // BuildCacheObject represents a build-cache DiskUsageObject. + BuildCacheObject DiskUsageObject = "build-cache" +) + +// DiskUsageOptions holds parameters for system disk usage query. +type DiskUsageOptions struct { + // Types specifies what object types to include in the response. If empty, + // all object types are returned. + Types []DiskUsageObject +} + +// DiskUsage contains response of Engine API: +// GET "/system/df" +type DiskUsage struct { + LayersSize int64 + Images []*ImageSummary + Containers []*Container + Volumes []*volume.Volume + BuildCache []*BuildCache + BuilderSize int64 `json:",omitempty"` // Deprecated: deprecated in API 1.38, and no longer used since API 1.40. +} + +// ContainersPruneReport contains the response for Engine API: +// POST "/containers/prune" +type ContainersPruneReport struct { + ContainersDeleted []string + SpaceReclaimed uint64 +} + +// VolumesPruneReport contains the response for Engine API: +// POST "/volumes/prune" +type VolumesPruneReport struct { + VolumesDeleted []string + SpaceReclaimed uint64 +} + +// ImagesPruneReport contains the response for Engine API: +// POST "/images/prune" +type ImagesPruneReport struct { + ImagesDeleted []ImageDeleteResponseItem + SpaceReclaimed uint64 +} + +// BuildCachePruneReport contains the response for Engine API: +// POST "/build/prune" +type BuildCachePruneReport struct { + CachesDeleted []string + SpaceReclaimed uint64 +} + +// NetworksPruneReport contains the response for Engine API: +// POST "/networks/prune" +type NetworksPruneReport struct { + NetworksDeleted []string +} + +// SecretCreateResponse contains the information returned to a client +// on the creation of a new secret. +type SecretCreateResponse struct { + // ID is the id of the created secret. + ID string +} + +// SecretListOptions holds parameters to list secrets +type SecretListOptions struct { + Filters filters.Args +} + +// ConfigCreateResponse contains the information returned to a client +// on the creation of a new config. +type ConfigCreateResponse struct { + // ID is the id of the created config. + ID string +} + +// ConfigListOptions holds parameters to list configs +type ConfigListOptions struct { + Filters filters.Args +} + +// PushResult contains the tag, manifest digest, and manifest size from the +// push. It's used to signal this information to the trust code in the client +// so it can sign the manifest if necessary. +type PushResult struct { + Tag string + Digest string + Size int +} + +// BuildResult contains the image id of a successful build +type BuildResult struct { + ID string +} + +// BuildCache contains information about a build cache record. +type BuildCache struct { + // ID is the unique ID of the build cache record. + ID string + // Parent is the ID of the parent build cache record. + // + // Deprecated: deprecated in API v1.42 and up, as it was deprecated in BuildKit; use Parents instead. + Parent string `json:"Parent,omitempty"` + // Parents is the list of parent build cache record IDs. + Parents []string `json:" Parents,omitempty"` + // Type is the cache record type. + Type string + // Description is a description of the build-step that produced the build cache. + Description string + // InUse indicates if the build cache is in use. + InUse bool + // Shared indicates if the build cache is shared. + Shared bool + // Size is the amount of disk space used by the build cache (in bytes). + Size int64 + // CreatedAt is the date and time at which the build cache was created. + CreatedAt time.Time + // LastUsedAt is the date and time at which the build cache was last used. + LastUsedAt *time.Time + UsageCount int +} + +// BuildCachePruneOptions hold parameters to prune the build cache +type BuildCachePruneOptions struct { + All bool + KeepStorage int64 + Filters filters.Args +} diff --git a/vendor/github.com/docker/docker/api/types/versions/README.md b/vendor/github.com/docker/docker/api/types/versions/README.md new file mode 100644 index 0000000000..1ef911edb0 --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/versions/README.md @@ -0,0 +1,14 @@ +# Legacy API type versions + +This package includes types for legacy API versions. The stable version of the API types live in `api/types/*.go`. + +Consider moving a type here when you need to keep backwards compatibility in the API. This legacy types are organized by the latest API version they appear in. For instance, types in the `v1p19` package are valid for API versions below or equal `1.19`. Types in the `v1p20` package are valid for the API version `1.20`, since the versions below that will use the legacy types in `v1p19`. + +## Package name conventions + +The package name convention is to use `v` as a prefix for the version number and `p`(patch) as a separator. We use this nomenclature due to a few restrictions in the Go package name convention: + +1. We cannot use `.` because it's interpreted by the language, think of `v1.20.CallFunction`. +2. We cannot use `_` because golint complains about it. The code is actually valid, but it looks probably more weird: `v1_20.CallFunction`. + +For instance, if you want to modify a type that was available in the version `1.21` of the API but it will have different fields in the version `1.22`, you want to create a new package under `api/types/versions/v1p21`. diff --git a/vendor/github.com/docker/docker/api/types/versions/compare.go b/vendor/github.com/docker/docker/api/types/versions/compare.go new file mode 100644 index 0000000000..489e917ee5 --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/versions/compare.go @@ -0,0 +1,65 @@ +package versions // import "github.com/docker/docker/api/types/versions" + +import ( + "strconv" + "strings" +) + +// compare compares two version strings +// returns -1 if v1 < v2, 1 if v1 > v2, 0 otherwise. +func compare(v1, v2 string) int { + if v1 == v2 { + return 0 + } + var ( + currTab = strings.Split(v1, ".") + otherTab = strings.Split(v2, ".") + ) + + max := len(currTab) + if len(otherTab) > max { + max = len(otherTab) + } + for i := 0; i < max; i++ { + var currInt, otherInt int + + if len(currTab) > i { + currInt, _ = strconv.Atoi(currTab[i]) + } + if len(otherTab) > i { + otherInt, _ = strconv.Atoi(otherTab[i]) + } + if currInt > otherInt { + return 1 + } + if otherInt > currInt { + return -1 + } + } + return 0 +} + +// LessThan checks if a version is less than another +func LessThan(v, other string) bool { + return compare(v, other) == -1 +} + +// LessThanOrEqualTo checks if a version is less than or equal to another +func LessThanOrEqualTo(v, other string) bool { + return compare(v, other) <= 0 +} + +// GreaterThan checks if a version is greater than another +func GreaterThan(v, other string) bool { + return compare(v, other) == 1 +} + +// GreaterThanOrEqualTo checks if a version is greater than or equal to another +func GreaterThanOrEqualTo(v, other string) bool { + return compare(v, other) >= 0 +} + +// Equal checks if a version is equal to another +func Equal(v, other string) bool { + return compare(v, other) == 0 +} diff --git a/vendor/github.com/docker/docker/api/types/volume/cluster_volume.go b/vendor/github.com/docker/docker/api/types/volume/cluster_volume.go new file mode 100644 index 0000000000..55fc5d3899 --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/volume/cluster_volume.go @@ -0,0 +1,420 @@ +package volume + +import ( + "github.com/docker/docker/api/types/swarm" +) + +// ClusterVolume contains options and information specific to, and only present +// on, Swarm CSI cluster volumes. +type ClusterVolume struct { + // ID is the Swarm ID of the volume. Because cluster volumes are Swarm + // objects, they have an ID, unlike non-cluster volumes, which only have a + // Name. This ID can be used to refer to the cluster volume. + ID string + + // Meta is the swarm metadata about this volume. + swarm.Meta + + // Spec is the cluster-specific options from which this volume is derived. + Spec ClusterVolumeSpec + + // PublishStatus contains the status of the volume as it pertains to its + // publishing on Nodes. + PublishStatus []*PublishStatus `json:",omitempty"` + + // Info is information about the global status of the volume. + Info *Info `json:",omitempty"` +} + +// ClusterVolumeSpec contains the spec used to create this volume. +type ClusterVolumeSpec struct { + // Group defines the volume group of this volume. Volumes belonging to the + // same group can be referred to by group name when creating Services. + // Referring to a volume by group instructs swarm to treat volumes in that + // group interchangeably for the purpose of scheduling. Volumes with an + // empty string for a group technically all belong to the same, emptystring + // group. + Group string `json:",omitempty"` + + // AccessMode defines how the volume is used by tasks. + AccessMode *AccessMode `json:",omitempty"` + + // AccessibilityRequirements specifies where in the cluster a volume must + // be accessible from. + // + // This field must be empty if the plugin does not support + // VOLUME_ACCESSIBILITY_CONSTRAINTS capabilities. If it is present but the + // plugin does not support it, volume will not be created. + // + // If AccessibilityRequirements is empty, but the plugin does support + // VOLUME_ACCESSIBILITY_CONSTRAINTS, then Swarmkit will assume the entire + // cluster is a valid target for the volume. + AccessibilityRequirements *TopologyRequirement `json:",omitempty"` + + // CapacityRange defines the desired capacity that the volume should be + // created with. If nil, the plugin will decide the capacity. + CapacityRange *CapacityRange `json:",omitempty"` + + // Secrets defines Swarm Secrets that are passed to the CSI storage plugin + // when operating on this volume. + Secrets []Secret `json:",omitempty"` + + // Availability is the Volume's desired availability. Analogous to Node + // Availability, this allows the user to take volumes offline in order to + // update or delete them. + Availability Availability `json:",omitempty"` +} + +// Availability specifies the availability of the volume. +type Availability string + +const ( + // AvailabilityActive indicates that the volume is active and fully + // schedulable on the cluster. + AvailabilityActive Availability = "active" + + // AvailabilityPause indicates that no new workloads should use the + // volume, but existing workloads can continue to use it. + AvailabilityPause Availability = "pause" + + // AvailabilityDrain indicates that all workloads using this volume + // should be rescheduled, and the volume unpublished from all nodes. + AvailabilityDrain Availability = "drain" +) + +// AccessMode defines the access mode of a volume. +type AccessMode struct { + // Scope defines the set of nodes this volume can be used on at one time. + Scope Scope `json:",omitempty"` + + // Sharing defines the number and way that different tasks can use this + // volume at one time. + Sharing SharingMode `json:",omitempty"` + + // MountVolume defines options for using this volume as a Mount-type + // volume. + // + // Either BlockVolume or MountVolume, but not both, must be present. + MountVolume *TypeMount `json:",omitempty"` + + // BlockVolume defines options for using this volume as a Block-type + // volume. + // + // Either BlockVolume or MountVolume, but not both, must be present. + BlockVolume *TypeBlock `json:",omitempty"` +} + +// Scope defines the Scope of a Cluster Volume. This is how many nodes a +// Volume can be accessed simultaneously on. +type Scope string + +const ( + // ScopeSingleNode indicates the volume can be used on one node at a + // time. + ScopeSingleNode Scope = "single" + + // ScopeMultiNode indicates the volume can be used on many nodes at + // the same time. + ScopeMultiNode Scope = "multi" +) + +// SharingMode defines the Sharing of a Cluster Volume. This is how Tasks using a +// Volume at the same time can use it. +type SharingMode string + +const ( + // SharingNone indicates that only one Task may use the Volume at a + // time. + SharingNone SharingMode = "none" + + // SharingReadOnly indicates that the Volume may be shared by any + // number of Tasks, but they must be read-only. + SharingReadOnly SharingMode = "readonly" + + // SharingOneWriter indicates that the Volume may be shared by any + // number of Tasks, but all after the first must be read-only. + SharingOneWriter SharingMode = "onewriter" + + // SharingAll means that the Volume may be shared by any number of + // Tasks, as readers or writers. + SharingAll SharingMode = "all" +) + +// TypeBlock defines options for using a volume as a block-type volume. +// +// Intentionally empty. +type TypeBlock struct{} + +// TypeMount contains options for using a volume as a Mount-type +// volume. +type TypeMount struct { + // FsType specifies the filesystem type for the mount volume. Optional. + FsType string `json:",omitempty"` + + // MountFlags defines flags to pass when mounting the volume. Optional. + MountFlags []string `json:",omitempty"` +} + +// TopologyRequirement expresses the user's requirements for a volume's +// accessible topology. +type TopologyRequirement struct { + // Requisite specifies a list of Topologies, at least one of which the + // volume must be accessible from. + // + // Taken verbatim from the CSI Spec: + // + // Specifies the list of topologies the provisioned volume MUST be + // accessible from. + // This field is OPTIONAL. If TopologyRequirement is specified either + // requisite or preferred or both MUST be specified. + // + // If requisite is specified, the provisioned volume MUST be + // accessible from at least one of the requisite topologies. + // + // Given + // x = number of topologies provisioned volume is accessible from + // n = number of requisite topologies + // The CO MUST ensure n >= 1. The SP MUST ensure x >= 1 + // If x==n, then the SP MUST make the provisioned volume available to + // all topologies from the list of requisite topologies. If it is + // unable to do so, the SP MUST fail the CreateVolume call. + // For example, if a volume should be accessible from a single zone, + // and requisite = + // {"region": "R1", "zone": "Z2"} + // then the provisioned volume MUST be accessible from the "region" + // "R1" and the "zone" "Z2". + // Similarly, if a volume should be accessible from two zones, and + // requisite = + // {"region": "R1", "zone": "Z2"}, + // {"region": "R1", "zone": "Z3"} + // then the provisioned volume MUST be accessible from the "region" + // "R1" and both "zone" "Z2" and "zone" "Z3". + // + // If xn, then the SP MUST make the provisioned volume available from + // all topologies from the list of requisite topologies and MAY choose + // the remaining x-n unique topologies from the list of all possible + // topologies. If it is unable to do so, the SP MUST fail the + // CreateVolume call. + // For example, if a volume should be accessible from two zones, and + // requisite = + // {"region": "R1", "zone": "Z2"} + // then the provisioned volume MUST be accessible from the "region" + // "R1" and the "zone" "Z2" and the SP may select the second zone + // independently, e.g. "R1/Z4". + Requisite []Topology `json:",omitempty"` + + // Preferred is a list of Topologies that the volume should attempt to be + // provisioned in. + // + // Taken from the CSI spec: + // + // Specifies the list of topologies the CO would prefer the volume to + // be provisioned in. + // + // This field is OPTIONAL. If TopologyRequirement is specified either + // requisite or preferred or both MUST be specified. + // + // An SP MUST attempt to make the provisioned volume available using + // the preferred topologies in order from first to last. + // + // If requisite is specified, all topologies in preferred list MUST + // also be present in the list of requisite topologies. + // + // If the SP is unable to to make the provisioned volume available + // from any of the preferred topologies, the SP MAY choose a topology + // from the list of requisite topologies. + // If the list of requisite topologies is not specified, then the SP + // MAY choose from the list of all possible topologies. + // If the list of requisite topologies is specified and the SP is + // unable to to make the provisioned volume available from any of the + // requisite topologies it MUST fail the CreateVolume call. + // + // Example 1: + // Given a volume should be accessible from a single zone, and + // requisite = + // {"region": "R1", "zone": "Z2"}, + // {"region": "R1", "zone": "Z3"} + // preferred = + // {"region": "R1", "zone": "Z3"} + // then the the SP SHOULD first attempt to make the provisioned volume + // available from "zone" "Z3" in the "region" "R1" and fall back to + // "zone" "Z2" in the "region" "R1" if that is not possible. + // + // Example 2: + // Given a volume should be accessible from a single zone, and + // requisite = + // {"region": "R1", "zone": "Z2"}, + // {"region": "R1", "zone": "Z3"}, + // {"region": "R1", "zone": "Z4"}, + // {"region": "R1", "zone": "Z5"} + // preferred = + // {"region": "R1", "zone": "Z4"}, + // {"region": "R1", "zone": "Z2"} + // then the the SP SHOULD first attempt to make the provisioned volume + // accessible from "zone" "Z4" in the "region" "R1" and fall back to + // "zone" "Z2" in the "region" "R1" if that is not possible. If that + // is not possible, the SP may choose between either the "zone" + // "Z3" or "Z5" in the "region" "R1". + // + // Example 3: + // Given a volume should be accessible from TWO zones (because an + // opaque parameter in CreateVolumeRequest, for example, specifies + // the volume is accessible from two zones, aka synchronously + // replicated), and + // requisite = + // {"region": "R1", "zone": "Z2"}, + // {"region": "R1", "zone": "Z3"}, + // {"region": "R1", "zone": "Z4"}, + // {"region": "R1", "zone": "Z5"} + // preferred = + // {"region": "R1", "zone": "Z5"}, + // {"region": "R1", "zone": "Z3"} + // then the the SP SHOULD first attempt to make the provisioned volume + // accessible from the combination of the two "zones" "Z5" and "Z3" in + // the "region" "R1". If that's not possible, it should fall back to + // a combination of "Z5" and other possibilities from the list of + // requisite. If that's not possible, it should fall back to a + // combination of "Z3" and other possibilities from the list of + // requisite. If that's not possible, it should fall back to a + // combination of other possibilities from the list of requisite. + Preferred []Topology `json:",omitempty"` +} + +// Topology is a map of topological domains to topological segments. +// +// This description is taken verbatim from the CSI Spec: +// +// A topological domain is a sub-division of a cluster, like "region", +// "zone", "rack", etc. +// A topological segment is a specific instance of a topological domain, +// like "zone3", "rack3", etc. +// For example {"com.company/zone": "Z1", "com.company/rack": "R3"} +// Valid keys have two segments: an OPTIONAL prefix and name, separated +// by a slash (/), for example: "com.company.example/zone". +// The key name segment is REQUIRED. The prefix is OPTIONAL. +// The key name MUST be 63 characters or less, begin and end with an +// alphanumeric character ([a-z0-9A-Z]), and contain only dashes (-), +// underscores (_), dots (.), or alphanumerics in between, for example +// "zone". +// The key prefix MUST be 63 characters or less, begin and end with a +// lower-case alphanumeric character ([a-z0-9]), contain only +// dashes (-), dots (.), or lower-case alphanumerics in between, and +// follow domain name notation format +// (https://tools.ietf.org/html/rfc1035#section-2.3.1). +// The key prefix SHOULD include the plugin's host company name and/or +// the plugin name, to minimize the possibility of collisions with keys +// from other plugins. +// If a key prefix is specified, it MUST be identical across all +// topology keys returned by the SP (across all RPCs). +// Keys MUST be case-insensitive. Meaning the keys "Zone" and "zone" +// MUST not both exist. +// Each value (topological segment) MUST contain 1 or more strings. +// Each string MUST be 63 characters or less and begin and end with an +// alphanumeric character with '-', '_', '.', or alphanumerics in +// between. +type Topology struct { + Segments map[string]string `json:",omitempty"` +} + +// CapacityRange describes the minimum and maximum capacity a volume should be +// created with +type CapacityRange struct { + // RequiredBytes specifies that a volume must be at least this big. The + // value of 0 indicates an unspecified minimum. + RequiredBytes int64 + + // LimitBytes specifies that a volume must not be bigger than this. The + // value of 0 indicates an unspecified maximum + LimitBytes int64 +} + +// Secret represents a Swarm Secret value that must be passed to the CSI +// storage plugin when operating on this Volume. It represents one key-value +// pair of possibly many. +type Secret struct { + // Key is the name of the key of the key-value pair passed to the plugin. + Key string + + // Secret is the swarm Secret object from which to read data. This can be a + // Secret name or ID. The Secret data is retrieved by Swarm and used as the + // value of the key-value pair passed to the plugin. + Secret string +} + +// PublishState represents the state of a Volume as it pertains to its +// use on a particular Node. +type PublishState string + +const ( + // StatePending indicates that the volume should be published on + // this node, but the call to ControllerPublishVolume has not been + // successfully completed yet and the result recorded by swarmkit. + StatePending PublishState = "pending-publish" + + // StatePublished means the volume is published successfully to the node. + StatePublished PublishState = "published" + + // StatePendingNodeUnpublish indicates that the Volume should be + // unpublished on the Node, and we're waiting for confirmation that it has + // done so. After the Node has confirmed that the Volume has been + // unpublished, the state will move to StatePendingUnpublish. + StatePendingNodeUnpublish PublishState = "pending-node-unpublish" + + // StatePendingUnpublish means the volume is still published to the node + // by the controller, awaiting the operation to unpublish it. + StatePendingUnpublish PublishState = "pending-controller-unpublish" +) + +// PublishStatus represents the status of the volume as published to an +// individual node +type PublishStatus struct { + // NodeID is the ID of the swarm node this Volume is published to. + NodeID string `json:",omitempty"` + + // State is the publish state of the volume. + State PublishState `json:",omitempty"` + + // PublishContext is the PublishContext returned by the CSI plugin when + // a volume is published. + PublishContext map[string]string `json:",omitempty"` +} + +// Info contains information about the Volume as a whole as provided by +// the CSI storage plugin. +type Info struct { + // CapacityBytes is the capacity of the volume in bytes. A value of 0 + // indicates that the capacity is unknown. + CapacityBytes int64 `json:",omitempty"` + + // VolumeContext is the context originating from the CSI storage plugin + // when the Volume is created. + VolumeContext map[string]string `json:",omitempty"` + + // VolumeID is the ID of the Volume as seen by the CSI storage plugin. This + // is distinct from the Volume's Swarm ID, which is the ID used by all of + // the Docker Engine to refer to the Volume. If this field is blank, then + // the Volume has not been successfully created yet. + VolumeID string `json:",omitempty"` + + // AccessibleTopolgoy is the topology this volume is actually accessible + // from. + AccessibleTopology []Topology `json:",omitempty"` +} diff --git a/vendor/github.com/docker/docker/api/types/volume/create_options.go b/vendor/github.com/docker/docker/api/types/volume/create_options.go new file mode 100644 index 0000000000..37c41a6096 --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/volume/create_options.go @@ -0,0 +1,29 @@ +package volume + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +// CreateOptions VolumeConfig +// +// Volume configuration +// swagger:model CreateOptions +type CreateOptions struct { + + // cluster volume spec + ClusterVolumeSpec *ClusterVolumeSpec `json:"ClusterVolumeSpec,omitempty"` + + // Name of the volume driver to use. + Driver string `json:"Driver,omitempty"` + + // A mapping of driver options and values. These options are + // passed directly to the driver and are driver specific. + // + DriverOpts map[string]string `json:"DriverOpts,omitempty"` + + // User-defined key/value metadata. + Labels map[string]string `json:"Labels,omitempty"` + + // The new volume's name. If not specified, Docker generates a name. + // + Name string `json:"Name,omitempty"` +} diff --git a/vendor/github.com/docker/docker/api/types/volume/deprecated.go b/vendor/github.com/docker/docker/api/types/volume/deprecated.go new file mode 100644 index 0000000000..ab622d8ccb --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/volume/deprecated.go @@ -0,0 +1,11 @@ +package volume // import "github.com/docker/docker/api/types/volume" + +// VolumeCreateBody Volume configuration +// +// Deprecated: use CreateOptions +type VolumeCreateBody = CreateOptions + +// VolumeListOKBody Volume list response +// +// Deprecated: use ListResponse +type VolumeListOKBody = ListResponse diff --git a/vendor/github.com/docker/docker/api/types/volume/list_response.go b/vendor/github.com/docker/docker/api/types/volume/list_response.go new file mode 100644 index 0000000000..ca5192a2a9 --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/volume/list_response.go @@ -0,0 +1,18 @@ +package volume + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +// ListResponse VolumeListResponse +// +// Volume list response +// swagger:model ListResponse +type ListResponse struct { + + // List of volumes + Volumes []*Volume `json:"Volumes"` + + // Warnings that occurred when fetching the list of volumes. + // + Warnings []string `json:"Warnings"` +} diff --git a/vendor/github.com/docker/docker/api/types/volume/options.go b/vendor/github.com/docker/docker/api/types/volume/options.go new file mode 100644 index 0000000000..8b0dd13899 --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/volume/options.go @@ -0,0 +1,8 @@ +package volume // import "github.com/docker/docker/api/types/volume" + +import "github.com/docker/docker/api/types/filters" + +// ListOptions holds parameters to list volumes. +type ListOptions struct { + Filters filters.Args +} diff --git a/vendor/github.com/docker/docker/api/types/volume/volume.go b/vendor/github.com/docker/docker/api/types/volume/volume.go new file mode 100644 index 0000000000..ea7d555e5b --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/volume/volume.go @@ -0,0 +1,75 @@ +package volume + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +// Volume volume +// swagger:model Volume +type Volume struct { + + // cluster volume + ClusterVolume *ClusterVolume `json:"ClusterVolume,omitempty"` + + // Date/Time the volume was created. + CreatedAt string `json:"CreatedAt,omitempty"` + + // Name of the volume driver used by the volume. + // Required: true + Driver string `json:"Driver"` + + // User-defined key/value metadata. + // Required: true + Labels map[string]string `json:"Labels"` + + // Mount path of the volume on the host. + // Required: true + Mountpoint string `json:"Mountpoint"` + + // Name of the volume. + // Required: true + Name string `json:"Name"` + + // The driver specific options used when creating the volume. + // + // Required: true + Options map[string]string `json:"Options"` + + // The level at which the volume exists. Either `global` for cluster-wide, + // or `local` for machine level. + // + // Required: true + Scope string `json:"Scope"` + + // Low-level details about the volume, provided by the volume driver. + // Details are returned as a map with key/value pairs: + // `{"key":"value","key2":"value2"}`. + // + // The `Status` field is optional, and is omitted if the volume driver + // does not support this feature. + // + Status map[string]interface{} `json:"Status,omitempty"` + + // usage data + UsageData *UsageData `json:"UsageData,omitempty"` +} + +// UsageData Usage details about the volume. This information is used by the +// `GET /system/df` endpoint, and omitted in other endpoints. +// +// swagger:model UsageData +type UsageData struct { + + // The number of containers referencing this volume. This field + // is set to `-1` if the reference-count is not available. + // + // Required: true + RefCount int64 `json:"RefCount"` + + // Amount of disk space used by the volume (in bytes). This information + // is only available for volumes created with the `"local"` volume + // driver. For volumes created with other volume drivers, this field + // is set to `-1` ("not available") + // + // Required: true + Size int64 `json:"Size"` +} diff --git a/vendor/github.com/docker/docker/api/types/volume/volume_update.go b/vendor/github.com/docker/docker/api/types/volume/volume_update.go new file mode 100644 index 0000000000..f958f80a66 --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/volume/volume_update.go @@ -0,0 +1,7 @@ +package volume // import "github.com/docker/docker/api/types/volume" + +// UpdateOptions is configuration to update a Volume with. +type UpdateOptions struct { + // Spec is the ClusterVolumeSpec to update the volume to. + Spec *ClusterVolumeSpec `json:"Spec,omitempty"` +} diff --git a/vendor/github.com/docker/docker/client/README.md b/vendor/github.com/docker/docker/client/README.md new file mode 100644 index 0000000000..992f18117d --- /dev/null +++ b/vendor/github.com/docker/docker/client/README.md @@ -0,0 +1,35 @@ +# Go client for the Docker Engine API + +The `docker` command uses this package to communicate with the daemon. It can also be used by your own Go applications to do anything the command-line interface does – running containers, pulling images, managing swarms, etc. + +For example, to list running containers (the equivalent of `docker ps`): + +```go +package main + +import ( + "context" + "fmt" + + "github.com/docker/docker/api/types" + "github.com/docker/docker/client" +) + +func main() { + cli, err := client.NewClientWithOpts(client.FromEnv) + if err != nil { + panic(err) + } + + containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{}) + if err != nil { + panic(err) + } + + for _, container := range containers { + fmt.Printf("%s %s\n", container.ID[:10], container.Image) + } +} +``` + +[Full documentation is available on GoDoc.](https://godoc.org/github.com/docker/docker/client) diff --git a/vendor/github.com/docker/docker/client/build_cancel.go b/vendor/github.com/docker/docker/client/build_cancel.go new file mode 100644 index 0000000000..b76bf366bb --- /dev/null +++ b/vendor/github.com/docker/docker/client/build_cancel.go @@ -0,0 +1,16 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "net/url" +) + +// BuildCancel requests the daemon to cancel the ongoing build request. +func (cli *Client) BuildCancel(ctx context.Context, id string) error { + query := url.Values{} + query.Set("id", id) + + serverResp, err := cli.post(ctx, "/build/cancel", query, nil, nil) + ensureReaderClosed(serverResp) + return err +} diff --git a/vendor/github.com/docker/docker/client/build_prune.go b/vendor/github.com/docker/docker/client/build_prune.go new file mode 100644 index 0000000000..397d67cdcf --- /dev/null +++ b/vendor/github.com/docker/docker/client/build_prune.go @@ -0,0 +1,45 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "encoding/json" + "fmt" + "net/url" + + "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/filters" + "github.com/pkg/errors" +) + +// BuildCachePrune requests the daemon to delete unused cache data +func (cli *Client) BuildCachePrune(ctx context.Context, opts types.BuildCachePruneOptions) (*types.BuildCachePruneReport, error) { + if err := cli.NewVersionError("1.31", "build prune"); err != nil { + return nil, err + } + + report := types.BuildCachePruneReport{} + + query := url.Values{} + if opts.All { + query.Set("all", "1") + } + query.Set("keep-storage", fmt.Sprintf("%d", opts.KeepStorage)) + filters, err := filters.ToJSON(opts.Filters) + if err != nil { + return nil, errors.Wrap(err, "prune could not marshal filters option") + } + query.Set("filters", filters) + + serverResp, err := cli.post(ctx, "/build/prune", query, nil, nil) + defer ensureReaderClosed(serverResp) + + if err != nil { + return nil, err + } + + if err := json.NewDecoder(serverResp.body).Decode(&report); err != nil { + return nil, fmt.Errorf("Error retrieving disk usage: %v", err) + } + + return &report, nil +} diff --git a/vendor/github.com/docker/docker/client/checkpoint_create.go b/vendor/github.com/docker/docker/client/checkpoint_create.go new file mode 100644 index 0000000000..921024fe4f --- /dev/null +++ b/vendor/github.com/docker/docker/client/checkpoint_create.go @@ -0,0 +1,14 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + + "github.com/docker/docker/api/types" +) + +// CheckpointCreate creates a checkpoint from the given container with the given name +func (cli *Client) CheckpointCreate(ctx context.Context, container string, options types.CheckpointCreateOptions) error { + resp, err := cli.post(ctx, "/containers/"+container+"/checkpoints", nil, options, nil) + ensureReaderClosed(resp) + return err +} diff --git a/vendor/github.com/docker/docker/client/checkpoint_delete.go b/vendor/github.com/docker/docker/client/checkpoint_delete.go new file mode 100644 index 0000000000..54f55fa76e --- /dev/null +++ b/vendor/github.com/docker/docker/client/checkpoint_delete.go @@ -0,0 +1,20 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "net/url" + + "github.com/docker/docker/api/types" +) + +// CheckpointDelete deletes the checkpoint with the given name from the given container +func (cli *Client) CheckpointDelete(ctx context.Context, containerID string, options types.CheckpointDeleteOptions) error { + query := url.Values{} + if options.CheckpointDir != "" { + query.Set("dir", options.CheckpointDir) + } + + resp, err := cli.delete(ctx, "/containers/"+containerID+"/checkpoints/"+options.CheckpointID, query, nil) + ensureReaderClosed(resp) + return err +} diff --git a/vendor/github.com/docker/docker/client/checkpoint_list.go b/vendor/github.com/docker/docker/client/checkpoint_list.go new file mode 100644 index 0000000000..39cfb959ff --- /dev/null +++ b/vendor/github.com/docker/docker/client/checkpoint_list.go @@ -0,0 +1,28 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "encoding/json" + "net/url" + + "github.com/docker/docker/api/types" +) + +// CheckpointList returns the checkpoints of the given container in the docker host +func (cli *Client) CheckpointList(ctx context.Context, container string, options types.CheckpointListOptions) ([]types.Checkpoint, error) { + var checkpoints []types.Checkpoint + + query := url.Values{} + if options.CheckpointDir != "" { + query.Set("dir", options.CheckpointDir) + } + + resp, err := cli.get(ctx, "/containers/"+container+"/checkpoints", query, nil) + defer ensureReaderClosed(resp) + if err != nil { + return checkpoints, err + } + + err = json.NewDecoder(resp.body).Decode(&checkpoints) + return checkpoints, err +} diff --git a/vendor/github.com/docker/docker/client/client.go b/vendor/github.com/docker/docker/client/client.go new file mode 100644 index 0000000000..09ea4851ff --- /dev/null +++ b/vendor/github.com/docker/docker/client/client.go @@ -0,0 +1,321 @@ +/* +Package client is a Go client for the Docker Engine API. + +For more information about the Engine API, see the documentation: +https://docs.docker.com/engine/api/ + +# Usage + +You use the library by constructing a client object using [NewClientWithOpts] +and calling methods on it. The client can be configured from environment +variables by passing the [FromEnv] option, or configured manually by passing any +of the other available [Opts]. + +For example, to list running containers (the equivalent of "docker ps"): + + package main + + import ( + "context" + "fmt" + + "github.com/docker/docker/api/types" + "github.com/docker/docker/client" + ) + + func main() { + cli, err := client.NewClientWithOpts(client.FromEnv) + if err != nil { + panic(err) + } + + containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{}) + if err != nil { + panic(err) + } + + for _, container := range containers { + fmt.Printf("%s %s\n", container.ID[:10], container.Image) + } + } +*/ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "net" + "net/http" + "net/url" + "path" + "strings" + + "github.com/docker/docker/api" + "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/versions" + "github.com/docker/go-connections/sockets" + "github.com/pkg/errors" +) + +// ErrRedirect is the error returned by checkRedirect when the request is non-GET. +var ErrRedirect = errors.New("unexpected redirect in response") + +// Client is the API client that performs all operations +// against a docker server. +type Client struct { + // scheme sets the scheme for the client + scheme string + // host holds the server address to connect to + host string + // proto holds the client protocol i.e. unix. + proto string + // addr holds the client address. + addr string + // basePath holds the path to prepend to the requests. + basePath string + // client used to send and receive http requests. + client *http.Client + // version of the server to talk to. + version string + // custom http headers configured by users. + customHTTPHeaders map[string]string + // manualOverride is set to true when the version was set by users. + manualOverride bool + + // negotiateVersion indicates if the client should automatically negotiate + // the API version to use when making requests. API version negotiation is + // performed on the first request, after which negotiated is set to "true" + // so that subsequent requests do not re-negotiate. + negotiateVersion bool + + // negotiated indicates that API version negotiation took place + negotiated bool +} + +// CheckRedirect specifies the policy for dealing with redirect responses: +// If the request is non-GET return ErrRedirect, otherwise use the last response. +// +// Go 1.8 changes behavior for HTTP redirects (specifically 301, 307, and 308) +// in the client. The Docker client (and by extension docker API client) can be +// made to send a request like POST /containers//start where what would normally +// be in the name section of the URL is empty. This triggers an HTTP 301 from +// the daemon. +// +// In go 1.8 this 301 will be converted to a GET request, and ends up getting +// a 404 from the daemon. This behavior change manifests in the client in that +// before, the 301 was not followed and the client did not generate an error, +// but now results in a message like Error response from daemon: page not found. +func CheckRedirect(req *http.Request, via []*http.Request) error { + if via[0].Method == http.MethodGet { + return http.ErrUseLastResponse + } + return ErrRedirect +} + +// NewClientWithOpts initializes a new API client with a default HTTPClient, and +// default API host and version. It also initializes the custom HTTP headers to +// add to each request. +// +// It takes an optional list of Opt functional arguments, which are applied in +// the order they're provided, which allows modifying the defaults when creating +// the client. For example, the following initializes a client that configures +// itself with values from environment variables (client.FromEnv), and has +// automatic API version negotiation enabled (client.WithAPIVersionNegotiation()). +// +// cli, err := client.NewClientWithOpts( +// client.FromEnv, +// client.WithAPIVersionNegotiation(), +// ) +func NewClientWithOpts(ops ...Opt) (*Client, error) { + client, err := defaultHTTPClient(DefaultDockerHost) + if err != nil { + return nil, err + } + c := &Client{ + host: DefaultDockerHost, + version: api.DefaultVersion, + client: client, + proto: defaultProto, + addr: defaultAddr, + } + + for _, op := range ops { + if err := op(c); err != nil { + return nil, err + } + } + + if c.scheme == "" { + c.scheme = "http" + + tlsConfig := resolveTLSConfig(c.client.Transport) + if tlsConfig != nil { + // TODO(stevvooe): This isn't really the right way to write clients in Go. + // `NewClient` should probably only take an `*http.Client` and work from there. + // Unfortunately, the model of having a host-ish/url-thingy as the connection + // string has us confusing protocol and transport layers. We continue doing + // this to avoid breaking existing clients but this should be addressed. + c.scheme = "https" + } + } + + return c, nil +} + +func defaultHTTPClient(host string) (*http.Client, error) { + hostURL, err := ParseHostURL(host) + if err != nil { + return nil, err + } + transport := &http.Transport{} + _ = sockets.ConfigureTransport(transport, hostURL.Scheme, hostURL.Host) + return &http.Client{ + Transport: transport, + CheckRedirect: CheckRedirect, + }, nil +} + +// Close the transport used by the client +func (cli *Client) Close() error { + if t, ok := cli.client.Transport.(*http.Transport); ok { + t.CloseIdleConnections() + } + return nil +} + +// getAPIPath returns the versioned request path to call the api. +// It appends the query parameters to the path if they are not empty. +func (cli *Client) getAPIPath(ctx context.Context, p string, query url.Values) string { + var apiPath string + if cli.negotiateVersion && !cli.negotiated { + cli.NegotiateAPIVersion(ctx) + } + if cli.version != "" { + v := strings.TrimPrefix(cli.version, "v") + apiPath = path.Join(cli.basePath, "/v"+v, p) + } else { + apiPath = path.Join(cli.basePath, p) + } + return (&url.URL{Path: apiPath, RawQuery: query.Encode()}).String() +} + +// ClientVersion returns the API version used by this client. +func (cli *Client) ClientVersion() string { + return cli.version +} + +// NegotiateAPIVersion queries the API and updates the version to match the API +// version. NegotiateAPIVersion downgrades the client's API version to match the +// APIVersion if the ping version is lower than the default version. If the API +// version reported by the server is higher than the maximum version supported +// by the client, it uses the client's maximum version. +// +// If a manual override is in place, either through the "DOCKER_API_VERSION" +// (EnvOverrideAPIVersion) environment variable, or if the client is initialized +// with a fixed version (WithVersion(xx)), no negotiation is performed. +// +// If the API server's ping response does not contain an API version, or if the +// client did not get a successful ping response, it assumes it is connected with +// an old daemon that does not support API version negotiation, in which case it +// downgrades to the latest version of the API before version negotiation was +// added (1.24). +func (cli *Client) NegotiateAPIVersion(ctx context.Context) { + if !cli.manualOverride { + ping, _ := cli.Ping(ctx) + cli.negotiateAPIVersionPing(ping) + } +} + +// NegotiateAPIVersionPing downgrades the client's API version to match the +// APIVersion in the ping response. If the API version in pingResponse is higher +// than the maximum version supported by the client, it uses the client's maximum +// version. +// +// If a manual override is in place, either through the "DOCKER_API_VERSION" +// (EnvOverrideAPIVersion) environment variable, or if the client is initialized +// with a fixed version (WithVersion(xx)), no negotiation is performed. +// +// If the API server's ping response does not contain an API version, we assume +// we are connected with an old daemon without API version negotiation support, +// and downgrade to the latest version of the API before version negotiation was +// added (1.24). +func (cli *Client) NegotiateAPIVersionPing(pingResponse types.Ping) { + if !cli.manualOverride { + cli.negotiateAPIVersionPing(pingResponse) + } +} + +// negotiateAPIVersionPing queries the API and updates the version to match the +// API version from the ping response. +func (cli *Client) negotiateAPIVersionPing(pingResponse types.Ping) { + // default to the latest version before versioning headers existed + if pingResponse.APIVersion == "" { + pingResponse.APIVersion = "1.24" + } + + // if the client is not initialized with a version, start with the latest supported version + if cli.version == "" { + cli.version = api.DefaultVersion + } + + // if server version is lower than the client version, downgrade + if versions.LessThan(pingResponse.APIVersion, cli.version) { + cli.version = pingResponse.APIVersion + } + + // Store the results, so that automatic API version negotiation (if enabled) + // won't be performed on the next request. + if cli.negotiateVersion { + cli.negotiated = true + } +} + +// DaemonHost returns the host address used by the client +func (cli *Client) DaemonHost() string { + return cli.host +} + +// HTTPClient returns a copy of the HTTP client bound to the server +func (cli *Client) HTTPClient() *http.Client { + c := *cli.client + return &c +} + +// ParseHostURL parses a url string, validates the string is a host url, and +// returns the parsed URL +func ParseHostURL(host string) (*url.URL, error) { + protoAddrParts := strings.SplitN(host, "://", 2) + if len(protoAddrParts) == 1 { + return nil, errors.Errorf("unable to parse docker host `%s`", host) + } + + var basePath string + proto, addr := protoAddrParts[0], protoAddrParts[1] + if proto == "tcp" { + parsed, err := url.Parse("tcp://" + addr) + if err != nil { + return nil, err + } + addr = parsed.Host + basePath = parsed.Path + } + return &url.URL{ + Scheme: proto, + Host: addr, + Path: basePath, + }, nil +} + +// Dialer returns a dialer for a raw stream connection, with an HTTP/1.1 header, +// that can be used for proxying the daemon connection. +// +// Used by `docker dial-stdio` (docker/cli#889). +func (cli *Client) Dialer() func(context.Context) (net.Conn, error) { + return func(ctx context.Context) (net.Conn, error) { + if transport, ok := cli.client.Transport.(*http.Transport); ok { + if transport.DialContext != nil && transport.TLSClientConfig == nil { + return transport.DialContext(ctx, cli.proto, cli.addr) + } + } + return fallbackDial(cli.proto, cli.addr, resolveTLSConfig(cli.client.Transport)) + } +} diff --git a/vendor/github.com/docker/docker/client/client_deprecated.go b/vendor/github.com/docker/docker/client/client_deprecated.go new file mode 100644 index 0000000000..9e366ce20d --- /dev/null +++ b/vendor/github.com/docker/docker/client/client_deprecated.go @@ -0,0 +1,27 @@ +package client + +import "net/http" + +// NewClient initializes a new API client for the given host and API version. +// It uses the given http client as transport. +// It also initializes the custom http headers to add to each request. +// +// It won't send any version information if the version number is empty. It is +// highly recommended that you set a version or your client may break if the +// server is upgraded. +// +// Deprecated: use [NewClientWithOpts] passing the [WithHost], [WithVersion], +// [WithHTTPClient] and [WithHTTPHeaders] options. We recommend enabling API +// version negotiation by passing the [WithAPIVersionNegotiation] option instead +// of WithVersion. +func NewClient(host string, version string, client *http.Client, httpHeaders map[string]string) (*Client, error) { + return NewClientWithOpts(WithHost(host), WithVersion(version), WithHTTPClient(client), WithHTTPHeaders(httpHeaders)) +} + +// NewEnvClient initializes a new API client based on environment variables. +// See FromEnv for a list of support environment variables. +// +// Deprecated: use [NewClientWithOpts] passing the [FromEnv] option. +func NewEnvClient() (*Client, error) { + return NewClientWithOpts(FromEnv) +} diff --git a/vendor/github.com/docker/docker/client/client_unix.go b/vendor/github.com/docker/docker/client/client_unix.go new file mode 100644 index 0000000000..f0783f7085 --- /dev/null +++ b/vendor/github.com/docker/docker/client/client_unix.go @@ -0,0 +1,11 @@ +//go:build linux || freebsd || openbsd || netbsd || darwin || solaris || illumos || dragonfly +// +build linux freebsd openbsd netbsd darwin solaris illumos dragonfly + +package client // import "github.com/docker/docker/client" + +// DefaultDockerHost defines OS-specific default host if the DOCKER_HOST +// (EnvOverrideHost) environment variable is unset or empty. +const DefaultDockerHost = "unix:///var/run/docker.sock" + +const defaultProto = "unix" +const defaultAddr = "/var/run/docker.sock" diff --git a/vendor/github.com/docker/docker/client/client_windows.go b/vendor/github.com/docker/docker/client/client_windows.go new file mode 100644 index 0000000000..5abe60457d --- /dev/null +++ b/vendor/github.com/docker/docker/client/client_windows.go @@ -0,0 +1,8 @@ +package client // import "github.com/docker/docker/client" + +// DefaultDockerHost defines OS-specific default host if the DOCKER_HOST +// (EnvOverrideHost) environment variable is unset or empty. +const DefaultDockerHost = "npipe:////./pipe/docker_engine" + +const defaultProto = "npipe" +const defaultAddr = "//./pipe/docker_engine" diff --git a/vendor/github.com/docker/docker/client/config_create.go b/vendor/github.com/docker/docker/client/config_create.go new file mode 100644 index 0000000000..f6b1881fc3 --- /dev/null +++ b/vendor/github.com/docker/docker/client/config_create.go @@ -0,0 +1,25 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "encoding/json" + + "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/swarm" +) + +// ConfigCreate creates a new config. +func (cli *Client) ConfigCreate(ctx context.Context, config swarm.ConfigSpec) (types.ConfigCreateResponse, error) { + var response types.ConfigCreateResponse + if err := cli.NewVersionError("1.30", "config create"); err != nil { + return response, err + } + resp, err := cli.post(ctx, "/configs/create", nil, config, nil) + defer ensureReaderClosed(resp) + if err != nil { + return response, err + } + + err = json.NewDecoder(resp.body).Decode(&response) + return response, err +} diff --git a/vendor/github.com/docker/docker/client/config_inspect.go b/vendor/github.com/docker/docker/client/config_inspect.go new file mode 100644 index 0000000000..9be7882c3d --- /dev/null +++ b/vendor/github.com/docker/docker/client/config_inspect.go @@ -0,0 +1,36 @@ +package client // import "github.com/docker/docker/client" + +import ( + "bytes" + "context" + "encoding/json" + "io" + + "github.com/docker/docker/api/types/swarm" +) + +// ConfigInspectWithRaw returns the config information with raw data +func (cli *Client) ConfigInspectWithRaw(ctx context.Context, id string) (swarm.Config, []byte, error) { + if id == "" { + return swarm.Config{}, nil, objectNotFoundError{object: "config", id: id} + } + if err := cli.NewVersionError("1.30", "config inspect"); err != nil { + return swarm.Config{}, nil, err + } + resp, err := cli.get(ctx, "/configs/"+id, nil, nil) + defer ensureReaderClosed(resp) + if err != nil { + return swarm.Config{}, nil, err + } + + body, err := io.ReadAll(resp.body) + if err != nil { + return swarm.Config{}, nil, err + } + + var config swarm.Config + rdr := bytes.NewReader(body) + err = json.NewDecoder(rdr).Decode(&config) + + return config, body, err +} diff --git a/vendor/github.com/docker/docker/client/config_list.go b/vendor/github.com/docker/docker/client/config_list.go new file mode 100644 index 0000000000..565acc6e27 --- /dev/null +++ b/vendor/github.com/docker/docker/client/config_list.go @@ -0,0 +1,38 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "encoding/json" + "net/url" + + "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/filters" + "github.com/docker/docker/api/types/swarm" +) + +// ConfigList returns the list of configs. +func (cli *Client) ConfigList(ctx context.Context, options types.ConfigListOptions) ([]swarm.Config, error) { + if err := cli.NewVersionError("1.30", "config list"); err != nil { + return nil, err + } + query := url.Values{} + + if options.Filters.Len() > 0 { + filterJSON, err := filters.ToJSON(options.Filters) + if err != nil { + return nil, err + } + + query.Set("filters", filterJSON) + } + + resp, err := cli.get(ctx, "/configs", query, nil) + defer ensureReaderClosed(resp) + if err != nil { + return nil, err + } + + var configs []swarm.Config + err = json.NewDecoder(resp.body).Decode(&configs) + return configs, err +} diff --git a/vendor/github.com/docker/docker/client/config_remove.go b/vendor/github.com/docker/docker/client/config_remove.go new file mode 100644 index 0000000000..24b94e9c18 --- /dev/null +++ b/vendor/github.com/docker/docker/client/config_remove.go @@ -0,0 +1,13 @@ +package client // import "github.com/docker/docker/client" + +import "context" + +// ConfigRemove removes a config. +func (cli *Client) ConfigRemove(ctx context.Context, id string) error { + if err := cli.NewVersionError("1.30", "config remove"); err != nil { + return err + } + resp, err := cli.delete(ctx, "/configs/"+id, nil, nil) + defer ensureReaderClosed(resp) + return err +} diff --git a/vendor/github.com/docker/docker/client/config_update.go b/vendor/github.com/docker/docker/client/config_update.go new file mode 100644 index 0000000000..1ac2985435 --- /dev/null +++ b/vendor/github.com/docker/docker/client/config_update.go @@ -0,0 +1,20 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "net/url" + + "github.com/docker/docker/api/types/swarm" +) + +// ConfigUpdate attempts to update a config +func (cli *Client) ConfigUpdate(ctx context.Context, id string, version swarm.Version, config swarm.ConfigSpec) error { + if err := cli.NewVersionError("1.30", "config update"); err != nil { + return err + } + query := url.Values{} + query.Set("version", version.String()) + resp, err := cli.post(ctx, "/configs/"+id+"/update", query, config, nil) + ensureReaderClosed(resp) + return err +} diff --git a/vendor/github.com/docker/docker/client/container_attach.go b/vendor/github.com/docker/docker/client/container_attach.go new file mode 100644 index 0000000000..ba92117d3e --- /dev/null +++ b/vendor/github.com/docker/docker/client/container_attach.go @@ -0,0 +1,59 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "net/url" + + "github.com/docker/docker/api/types" +) + +// ContainerAttach attaches a connection to a container in the server. +// It returns a types.HijackedConnection with the hijacked connection +// and the a reader to get output. It's up to the called to close +// the hijacked connection by calling types.HijackedResponse.Close. +// +// The stream format on the response will be in one of two formats: +// +// If the container is using a TTY, there is only a single stream (stdout), and +// data is copied directly from the container output stream, no extra +// multiplexing or headers. +// +// If the container is *not* using a TTY, streams for stdout and stderr are +// multiplexed. +// The format of the multiplexed stream is as follows: +// +// [8]byte{STREAM_TYPE, 0, 0, 0, SIZE1, SIZE2, SIZE3, SIZE4}[]byte{OUTPUT} +// +// STREAM_TYPE can be 1 for stdout and 2 for stderr +// +// SIZE1, SIZE2, SIZE3, and SIZE4 are four bytes of uint32 encoded as big endian. +// This is the size of OUTPUT. +// +// You can use github.com/docker/docker/pkg/stdcopy.StdCopy to demultiplex this +// stream. +func (cli *Client) ContainerAttach(ctx context.Context, container string, options types.ContainerAttachOptions) (types.HijackedResponse, error) { + query := url.Values{} + if options.Stream { + query.Set("stream", "1") + } + if options.Stdin { + query.Set("stdin", "1") + } + if options.Stdout { + query.Set("stdout", "1") + } + if options.Stderr { + query.Set("stderr", "1") + } + if options.DetachKeys != "" { + query.Set("detachKeys", options.DetachKeys) + } + if options.Logs { + query.Set("logs", "1") + } + + headers := map[string][]string{ + "Content-Type": {"text/plain"}, + } + return cli.postHijacked(ctx, "/containers/"+container+"/attach", query, nil, headers) +} diff --git a/vendor/github.com/docker/docker/client/container_commit.go b/vendor/github.com/docker/docker/client/container_commit.go new file mode 100644 index 0000000000..cd7f763464 --- /dev/null +++ b/vendor/github.com/docker/docker/client/container_commit.go @@ -0,0 +1,55 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "encoding/json" + "errors" + "net/url" + + "github.com/docker/distribution/reference" + "github.com/docker/docker/api/types" +) + +// ContainerCommit applies changes to a container and creates a new tagged image. +func (cli *Client) ContainerCommit(ctx context.Context, container string, options types.ContainerCommitOptions) (types.IDResponse, error) { + var repository, tag string + if options.Reference != "" { + ref, err := reference.ParseNormalizedNamed(options.Reference) + if err != nil { + return types.IDResponse{}, err + } + + if _, isCanonical := ref.(reference.Canonical); isCanonical { + return types.IDResponse{}, errors.New("refusing to create a tag with a digest reference") + } + ref = reference.TagNameOnly(ref) + + if tagged, ok := ref.(reference.Tagged); ok { + tag = tagged.Tag() + } + repository = reference.FamiliarName(ref) + } + + query := url.Values{} + query.Set("container", container) + query.Set("repo", repository) + query.Set("tag", tag) + query.Set("comment", options.Comment) + query.Set("author", options.Author) + for _, change := range options.Changes { + query.Add("changes", change) + } + if !options.Pause { + query.Set("pause", "0") + } + + var response types.IDResponse + resp, err := cli.post(ctx, "/commit", query, options.Config, nil) + defer ensureReaderClosed(resp) + if err != nil { + return response, err + } + + err = json.NewDecoder(resp.body).Decode(&response) + return response, err +} diff --git a/vendor/github.com/docker/docker/client/container_copy.go b/vendor/github.com/docker/docker/client/container_copy.go new file mode 100644 index 0000000000..883be7fa34 --- /dev/null +++ b/vendor/github.com/docker/docker/client/container_copy.go @@ -0,0 +1,93 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "encoding/base64" + "encoding/json" + "fmt" + "io" + "net/http" + "net/url" + "path/filepath" + "strings" + + "github.com/docker/docker/api/types" +) + +// ContainerStatPath returns stat information about a path inside the container filesystem. +func (cli *Client) ContainerStatPath(ctx context.Context, containerID, path string) (types.ContainerPathStat, error) { + query := url.Values{} + query.Set("path", filepath.ToSlash(path)) // Normalize the paths used in the API. + + urlStr := "/containers/" + containerID + "/archive" + response, err := cli.head(ctx, urlStr, query, nil) + defer ensureReaderClosed(response) + if err != nil { + return types.ContainerPathStat{}, err + } + return getContainerPathStatFromHeader(response.header) +} + +// CopyToContainer copies content into the container filesystem. +// Note that `content` must be a Reader for a TAR archive +func (cli *Client) CopyToContainer(ctx context.Context, containerID, dstPath string, content io.Reader, options types.CopyToContainerOptions) error { + query := url.Values{} + query.Set("path", filepath.ToSlash(dstPath)) // Normalize the paths used in the API. + // Do not allow for an existing directory to be overwritten by a non-directory and vice versa. + if !options.AllowOverwriteDirWithFile { + query.Set("noOverwriteDirNonDir", "true") + } + + if options.CopyUIDGID { + query.Set("copyUIDGID", "true") + } + + apiPath := "/containers/" + containerID + "/archive" + + response, err := cli.putRaw(ctx, apiPath, query, content, nil) + defer ensureReaderClosed(response) + if err != nil { + return err + } + + return nil +} + +// CopyFromContainer gets the content from the container and returns it as a Reader +// for a TAR archive to manipulate it in the host. It's up to the caller to close the reader. +func (cli *Client) CopyFromContainer(ctx context.Context, containerID, srcPath string) (io.ReadCloser, types.ContainerPathStat, error) { + query := make(url.Values, 1) + query.Set("path", filepath.ToSlash(srcPath)) // Normalize the paths used in the API. + + apiPath := "/containers/" + containerID + "/archive" + response, err := cli.get(ctx, apiPath, query, nil) + if err != nil { + return nil, types.ContainerPathStat{}, err + } + + // In order to get the copy behavior right, we need to know information + // about both the source and the destination. The response headers include + // stat info about the source that we can use in deciding exactly how to + // copy it locally. Along with the stat info about the local destination, + // we have everything we need to handle the multiple possibilities there + // can be when copying a file/dir from one location to another file/dir. + stat, err := getContainerPathStatFromHeader(response.header) + if err != nil { + return nil, stat, fmt.Errorf("unable to get resource stat from response: %s", err) + } + return response.body, stat, err +} + +func getContainerPathStatFromHeader(header http.Header) (types.ContainerPathStat, error) { + var stat types.ContainerPathStat + + encodedStat := header.Get("X-Docker-Container-Path-Stat") + statDecoder := base64.NewDecoder(base64.StdEncoding, strings.NewReader(encodedStat)) + + err := json.NewDecoder(statDecoder).Decode(&stat) + if err != nil { + err = fmt.Errorf("unable to decode container path stat header: %s", err) + } + + return stat, err +} diff --git a/vendor/github.com/docker/docker/client/container_create.go b/vendor/github.com/docker/docker/client/container_create.go new file mode 100644 index 0000000000..f82420b673 --- /dev/null +++ b/vendor/github.com/docker/docker/client/container_create.go @@ -0,0 +1,83 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "encoding/json" + "net/url" + "path" + + "github.com/docker/docker/api/types/container" + "github.com/docker/docker/api/types/network" + "github.com/docker/docker/api/types/versions" + specs "github.com/opencontainers/image-spec/specs-go/v1" +) + +type configWrapper struct { + *container.Config + HostConfig *container.HostConfig + NetworkingConfig *network.NetworkingConfig +} + +// ContainerCreate creates a new container based on the given configuration. +// It can be associated with a name, but it's not mandatory. +func (cli *Client) ContainerCreate(ctx context.Context, config *container.Config, hostConfig *container.HostConfig, networkingConfig *network.NetworkingConfig, platform *specs.Platform, containerName string) (container.CreateResponse, error) { + var response container.CreateResponse + + if err := cli.NewVersionError("1.25", "stop timeout"); config != nil && config.StopTimeout != nil && err != nil { + return response, err + } + if err := cli.NewVersionError("1.41", "specify container image platform"); platform != nil && err != nil { + return response, err + } + + if hostConfig != nil { + if versions.LessThan(cli.ClientVersion(), "1.25") { + // When using API 1.24 and under, the client is responsible for removing the container + hostConfig.AutoRemove = false + } + if versions.GreaterThanOrEqualTo(cli.ClientVersion(), "1.42") || versions.LessThan(cli.ClientVersion(), "1.40") { + // KernelMemory was added in API 1.40, and deprecated in API 1.42 + hostConfig.KernelMemory = 0 + } + if platform != nil && platform.OS == "linux" && versions.LessThan(cli.ClientVersion(), "1.42") { + // When using API under 1.42, the Linux daemon doesn't respect the ConsoleSize + hostConfig.ConsoleSize = [2]uint{0, 0} + } + } + + query := url.Values{} + if p := formatPlatform(platform); p != "" { + query.Set("platform", p) + } + + if containerName != "" { + query.Set("name", containerName) + } + + body := configWrapper{ + Config: config, + HostConfig: hostConfig, + NetworkingConfig: networkingConfig, + } + + serverResp, err := cli.post(ctx, "/containers/create", query, body, nil) + defer ensureReaderClosed(serverResp) + if err != nil { + return response, err + } + + err = json.NewDecoder(serverResp.body).Decode(&response) + return response, err +} + +// formatPlatform returns a formatted string representing platform (e.g. linux/arm/v7). +// +// Similar to containerd's platforms.Format(), but does allow components to be +// omitted (e.g. pass "architecture" only, without "os": +// https://github.com/containerd/containerd/blob/v1.5.2/platforms/platforms.go#L243-L263 +func formatPlatform(platform *specs.Platform) string { + if platform == nil { + return "" + } + return path.Join(platform.OS, platform.Architecture, platform.Variant) +} diff --git a/vendor/github.com/docker/docker/client/container_diff.go b/vendor/github.com/docker/docker/client/container_diff.go new file mode 100644 index 0000000000..29dac8491d --- /dev/null +++ b/vendor/github.com/docker/docker/client/container_diff.go @@ -0,0 +1,23 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "encoding/json" + "net/url" + + "github.com/docker/docker/api/types/container" +) + +// ContainerDiff shows differences in a container filesystem since it was started. +func (cli *Client) ContainerDiff(ctx context.Context, containerID string) ([]container.ContainerChangeResponseItem, error) { + var changes []container.ContainerChangeResponseItem + + serverResp, err := cli.get(ctx, "/containers/"+containerID+"/changes", url.Values{}, nil) + defer ensureReaderClosed(serverResp) + if err != nil { + return changes, err + } + + err = json.NewDecoder(serverResp.body).Decode(&changes) + return changes, err +} diff --git a/vendor/github.com/docker/docker/client/container_exec.go b/vendor/github.com/docker/docker/client/container_exec.go new file mode 100644 index 0000000000..6a2cb006f8 --- /dev/null +++ b/vendor/github.com/docker/docker/client/container_exec.go @@ -0,0 +1,66 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "encoding/json" + + "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/versions" +) + +// ContainerExecCreate creates a new exec configuration to run an exec process. +func (cli *Client) ContainerExecCreate(ctx context.Context, container string, config types.ExecConfig) (types.IDResponse, error) { + var response types.IDResponse + + if err := cli.NewVersionError("1.25", "env"); len(config.Env) != 0 && err != nil { + return response, err + } + if versions.LessThan(cli.ClientVersion(), "1.42") { + config.ConsoleSize = nil + } + + resp, err := cli.post(ctx, "/containers/"+container+"/exec", nil, config, nil) + defer ensureReaderClosed(resp) + if err != nil { + return response, err + } + err = json.NewDecoder(resp.body).Decode(&response) + return response, err +} + +// ContainerExecStart starts an exec process already created in the docker host. +func (cli *Client) ContainerExecStart(ctx context.Context, execID string, config types.ExecStartCheck) error { + if versions.LessThan(cli.ClientVersion(), "1.42") { + config.ConsoleSize = nil + } + resp, err := cli.post(ctx, "/exec/"+execID+"/start", nil, config, nil) + ensureReaderClosed(resp) + return err +} + +// ContainerExecAttach attaches a connection to an exec process in the server. +// It returns a types.HijackedConnection with the hijacked connection +// and the a reader to get output. It's up to the called to close +// the hijacked connection by calling types.HijackedResponse.Close. +func (cli *Client) ContainerExecAttach(ctx context.Context, execID string, config types.ExecStartCheck) (types.HijackedResponse, error) { + if versions.LessThan(cli.ClientVersion(), "1.42") { + config.ConsoleSize = nil + } + headers := map[string][]string{ + "Content-Type": {"application/json"}, + } + return cli.postHijacked(ctx, "/exec/"+execID+"/start", nil, config, headers) +} + +// ContainerExecInspect returns information about a specific exec process on the docker host. +func (cli *Client) ContainerExecInspect(ctx context.Context, execID string) (types.ContainerExecInspect, error) { + var response types.ContainerExecInspect + resp, err := cli.get(ctx, "/exec/"+execID+"/json", nil, nil) + if err != nil { + return response, err + } + + err = json.NewDecoder(resp.body).Decode(&response) + ensureReaderClosed(resp) + return response, err +} diff --git a/vendor/github.com/docker/docker/client/container_export.go b/vendor/github.com/docker/docker/client/container_export.go new file mode 100644 index 0000000000..d0c0a5cbad --- /dev/null +++ b/vendor/github.com/docker/docker/client/container_export.go @@ -0,0 +1,19 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "io" + "net/url" +) + +// ContainerExport retrieves the raw contents of a container +// and returns them as an io.ReadCloser. It's up to the caller +// to close the stream. +func (cli *Client) ContainerExport(ctx context.Context, containerID string) (io.ReadCloser, error) { + serverResp, err := cli.get(ctx, "/containers/"+containerID+"/export", url.Values{}, nil) + if err != nil { + return nil, err + } + + return serverResp.body, nil +} diff --git a/vendor/github.com/docker/docker/client/container_inspect.go b/vendor/github.com/docker/docker/client/container_inspect.go new file mode 100644 index 0000000000..d48f0d3a68 --- /dev/null +++ b/vendor/github.com/docker/docker/client/container_inspect.go @@ -0,0 +1,53 @@ +package client // import "github.com/docker/docker/client" + +import ( + "bytes" + "context" + "encoding/json" + "io" + "net/url" + + "github.com/docker/docker/api/types" +) + +// ContainerInspect returns the container information. +func (cli *Client) ContainerInspect(ctx context.Context, containerID string) (types.ContainerJSON, error) { + if containerID == "" { + return types.ContainerJSON{}, objectNotFoundError{object: "container", id: containerID} + } + serverResp, err := cli.get(ctx, "/containers/"+containerID+"/json", nil, nil) + defer ensureReaderClosed(serverResp) + if err != nil { + return types.ContainerJSON{}, err + } + + var response types.ContainerJSON + err = json.NewDecoder(serverResp.body).Decode(&response) + return response, err +} + +// ContainerInspectWithRaw returns the container information and its raw representation. +func (cli *Client) ContainerInspectWithRaw(ctx context.Context, containerID string, getSize bool) (types.ContainerJSON, []byte, error) { + if containerID == "" { + return types.ContainerJSON{}, nil, objectNotFoundError{object: "container", id: containerID} + } + query := url.Values{} + if getSize { + query.Set("size", "1") + } + serverResp, err := cli.get(ctx, "/containers/"+containerID+"/json", query, nil) + defer ensureReaderClosed(serverResp) + if err != nil { + return types.ContainerJSON{}, nil, err + } + + body, err := io.ReadAll(serverResp.body) + if err != nil { + return types.ContainerJSON{}, nil, err + } + + var response types.ContainerJSON + rdr := bytes.NewReader(body) + err = json.NewDecoder(rdr).Decode(&response) + return response, body, err +} diff --git a/vendor/github.com/docker/docker/client/container_kill.go b/vendor/github.com/docker/docker/client/container_kill.go new file mode 100644 index 0000000000..7c9529f1e1 --- /dev/null +++ b/vendor/github.com/docker/docker/client/container_kill.go @@ -0,0 +1,18 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "net/url" +) + +// ContainerKill terminates the container process but does not remove the container from the docker host. +func (cli *Client) ContainerKill(ctx context.Context, containerID, signal string) error { + query := url.Values{} + if signal != "" { + query.Set("signal", signal) + } + + resp, err := cli.post(ctx, "/containers/"+containerID+"/kill", query, nil, nil) + ensureReaderClosed(resp) + return err +} diff --git a/vendor/github.com/docker/docker/client/container_list.go b/vendor/github.com/docker/docker/client/container_list.go new file mode 100644 index 0000000000..bd491b3db9 --- /dev/null +++ b/vendor/github.com/docker/docker/client/container_list.go @@ -0,0 +1,57 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "encoding/json" + "net/url" + "strconv" + + "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/filters" +) + +// ContainerList returns the list of containers in the docker host. +func (cli *Client) ContainerList(ctx context.Context, options types.ContainerListOptions) ([]types.Container, error) { + query := url.Values{} + + if options.All { + query.Set("all", "1") + } + + if options.Limit > 0 { + query.Set("limit", strconv.Itoa(options.Limit)) + } + + if options.Since != "" { + query.Set("since", options.Since) + } + + if options.Before != "" { + query.Set("before", options.Before) + } + + if options.Size { + query.Set("size", "1") + } + + if options.Filters.Len() > 0 { + //nolint:staticcheck // ignore SA1019 for old code + filterJSON, err := filters.ToParamWithVersion(cli.version, options.Filters) + + if err != nil { + return nil, err + } + + query.Set("filters", filterJSON) + } + + resp, err := cli.get(ctx, "/containers/json", query, nil) + defer ensureReaderClosed(resp) + if err != nil { + return nil, err + } + + var containers []types.Container + err = json.NewDecoder(resp.body).Decode(&containers) + return containers, err +} diff --git a/vendor/github.com/docker/docker/client/container_logs.go b/vendor/github.com/docker/docker/client/container_logs.go new file mode 100644 index 0000000000..9bdf2b0fa6 --- /dev/null +++ b/vendor/github.com/docker/docker/client/container_logs.go @@ -0,0 +1,80 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "io" + "net/url" + "time" + + "github.com/docker/docker/api/types" + timetypes "github.com/docker/docker/api/types/time" + "github.com/pkg/errors" +) + +// ContainerLogs returns the logs generated by a container in an io.ReadCloser. +// It's up to the caller to close the stream. +// +// The stream format on the response will be in one of two formats: +// +// If the container is using a TTY, there is only a single stream (stdout), and +// data is copied directly from the container output stream, no extra +// multiplexing or headers. +// +// If the container is *not* using a TTY, streams for stdout and stderr are +// multiplexed. +// The format of the multiplexed stream is as follows: +// +// [8]byte{STREAM_TYPE, 0, 0, 0, SIZE1, SIZE2, SIZE3, SIZE4}[]byte{OUTPUT} +// +// STREAM_TYPE can be 1 for stdout and 2 for stderr +// +// SIZE1, SIZE2, SIZE3, and SIZE4 are four bytes of uint32 encoded as big endian. +// This is the size of OUTPUT. +// +// You can use github.com/docker/docker/pkg/stdcopy.StdCopy to demultiplex this +// stream. +func (cli *Client) ContainerLogs(ctx context.Context, container string, options types.ContainerLogsOptions) (io.ReadCloser, error) { + query := url.Values{} + if options.ShowStdout { + query.Set("stdout", "1") + } + + if options.ShowStderr { + query.Set("stderr", "1") + } + + if options.Since != "" { + ts, err := timetypes.GetTimestamp(options.Since, time.Now()) + if err != nil { + return nil, errors.Wrap(err, `invalid value for "since"`) + } + query.Set("since", ts) + } + + if options.Until != "" { + ts, err := timetypes.GetTimestamp(options.Until, time.Now()) + if err != nil { + return nil, errors.Wrap(err, `invalid value for "until"`) + } + query.Set("until", ts) + } + + if options.Timestamps { + query.Set("timestamps", "1") + } + + if options.Details { + query.Set("details", "1") + } + + if options.Follow { + query.Set("follow", "1") + } + query.Set("tail", options.Tail) + + resp, err := cli.get(ctx, "/containers/"+container+"/logs", query, nil) + if err != nil { + return nil, err + } + return resp.body, nil +} diff --git a/vendor/github.com/docker/docker/client/container_pause.go b/vendor/github.com/docker/docker/client/container_pause.go new file mode 100644 index 0000000000..5e7271a371 --- /dev/null +++ b/vendor/github.com/docker/docker/client/container_pause.go @@ -0,0 +1,10 @@ +package client // import "github.com/docker/docker/client" + +import "context" + +// ContainerPause pauses the main process of a given container without terminating it. +func (cli *Client) ContainerPause(ctx context.Context, containerID string) error { + resp, err := cli.post(ctx, "/containers/"+containerID+"/pause", nil, nil, nil) + ensureReaderClosed(resp) + return err +} diff --git a/vendor/github.com/docker/docker/client/container_prune.go b/vendor/github.com/docker/docker/client/container_prune.go new file mode 100644 index 0000000000..04383deaaf --- /dev/null +++ b/vendor/github.com/docker/docker/client/container_prune.go @@ -0,0 +1,36 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "encoding/json" + "fmt" + + "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/filters" +) + +// ContainersPrune requests the daemon to delete unused data +func (cli *Client) ContainersPrune(ctx context.Context, pruneFilters filters.Args) (types.ContainersPruneReport, error) { + var report types.ContainersPruneReport + + if err := cli.NewVersionError("1.25", "container prune"); err != nil { + return report, err + } + + query, err := getFiltersQuery(pruneFilters) + if err != nil { + return report, err + } + + serverResp, err := cli.post(ctx, "/containers/prune", query, nil, nil) + defer ensureReaderClosed(serverResp) + if err != nil { + return report, err + } + + if err := json.NewDecoder(serverResp.body).Decode(&report); err != nil { + return report, fmt.Errorf("Error retrieving disk usage: %v", err) + } + + return report, nil +} diff --git a/vendor/github.com/docker/docker/client/container_remove.go b/vendor/github.com/docker/docker/client/container_remove.go new file mode 100644 index 0000000000..c21de609b0 --- /dev/null +++ b/vendor/github.com/docker/docker/client/container_remove.go @@ -0,0 +1,27 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "net/url" + + "github.com/docker/docker/api/types" +) + +// ContainerRemove kills and removes a container from the docker host. +func (cli *Client) ContainerRemove(ctx context.Context, containerID string, options types.ContainerRemoveOptions) error { + query := url.Values{} + if options.RemoveVolumes { + query.Set("v", "1") + } + if options.RemoveLinks { + query.Set("link", "1") + } + + if options.Force { + query.Set("force", "1") + } + + resp, err := cli.delete(ctx, "/containers/"+containerID, query, nil) + defer ensureReaderClosed(resp) + return err +} diff --git a/vendor/github.com/docker/docker/client/container_rename.go b/vendor/github.com/docker/docker/client/container_rename.go new file mode 100644 index 0000000000..240fdf552b --- /dev/null +++ b/vendor/github.com/docker/docker/client/container_rename.go @@ -0,0 +1,15 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "net/url" +) + +// ContainerRename changes the name of a given container. +func (cli *Client) ContainerRename(ctx context.Context, containerID, newContainerName string) error { + query := url.Values{} + query.Set("name", newContainerName) + resp, err := cli.post(ctx, "/containers/"+containerID+"/rename", query, nil, nil) + ensureReaderClosed(resp) + return err +} diff --git a/vendor/github.com/docker/docker/client/container_resize.go b/vendor/github.com/docker/docker/client/container_resize.go new file mode 100644 index 0000000000..a9d4c0c79a --- /dev/null +++ b/vendor/github.com/docker/docker/client/container_resize.go @@ -0,0 +1,29 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "net/url" + "strconv" + + "github.com/docker/docker/api/types" +) + +// ContainerResize changes the size of the tty for a container. +func (cli *Client) ContainerResize(ctx context.Context, containerID string, options types.ResizeOptions) error { + return cli.resize(ctx, "/containers/"+containerID, options.Height, options.Width) +} + +// ContainerExecResize changes the size of the tty for an exec process running inside a container. +func (cli *Client) ContainerExecResize(ctx context.Context, execID string, options types.ResizeOptions) error { + return cli.resize(ctx, "/exec/"+execID, options.Height, options.Width) +} + +func (cli *Client) resize(ctx context.Context, basePath string, height, width uint) error { + query := url.Values{} + query.Set("h", strconv.Itoa(int(height))) + query.Set("w", strconv.Itoa(int(width))) + + resp, err := cli.post(ctx, basePath+"/resize", query, nil, nil) + ensureReaderClosed(resp) + return err +} diff --git a/vendor/github.com/docker/docker/client/container_restart.go b/vendor/github.com/docker/docker/client/container_restart.go new file mode 100644 index 0000000000..1e0ad99981 --- /dev/null +++ b/vendor/github.com/docker/docker/client/container_restart.go @@ -0,0 +1,26 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "net/url" + "strconv" + + "github.com/docker/docker/api/types/container" + "github.com/docker/docker/api/types/versions" +) + +// ContainerRestart stops and starts a container again. +// It makes the daemon wait for the container to be up again for +// a specific amount of time, given the timeout. +func (cli *Client) ContainerRestart(ctx context.Context, containerID string, options container.StopOptions) error { + query := url.Values{} + if options.Timeout != nil { + query.Set("t", strconv.Itoa(*options.Timeout)) + } + if options.Signal != "" && versions.GreaterThanOrEqualTo(cli.version, "1.42") { + query.Set("signal", options.Signal) + } + resp, err := cli.post(ctx, "/containers/"+containerID+"/restart", query, nil, nil) + ensureReaderClosed(resp) + return err +} diff --git a/vendor/github.com/docker/docker/client/container_start.go b/vendor/github.com/docker/docker/client/container_start.go new file mode 100644 index 0000000000..c2e0b15dca --- /dev/null +++ b/vendor/github.com/docker/docker/client/container_start.go @@ -0,0 +1,23 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "net/url" + + "github.com/docker/docker/api/types" +) + +// ContainerStart sends a request to the docker daemon to start a container. +func (cli *Client) ContainerStart(ctx context.Context, containerID string, options types.ContainerStartOptions) error { + query := url.Values{} + if len(options.CheckpointID) != 0 { + query.Set("checkpoint", options.CheckpointID) + } + if len(options.CheckpointDir) != 0 { + query.Set("checkpoint-dir", options.CheckpointDir) + } + + resp, err := cli.post(ctx, "/containers/"+containerID+"/start", query, nil, nil) + ensureReaderClosed(resp) + return err +} diff --git a/vendor/github.com/docker/docker/client/container_stats.go b/vendor/github.com/docker/docker/client/container_stats.go new file mode 100644 index 0000000000..0a6488dde8 --- /dev/null +++ b/vendor/github.com/docker/docker/client/container_stats.go @@ -0,0 +1,42 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "net/url" + + "github.com/docker/docker/api/types" +) + +// ContainerStats returns near realtime stats for a given container. +// It's up to the caller to close the io.ReadCloser returned. +func (cli *Client) ContainerStats(ctx context.Context, containerID string, stream bool) (types.ContainerStats, error) { + query := url.Values{} + query.Set("stream", "0") + if stream { + query.Set("stream", "1") + } + + resp, err := cli.get(ctx, "/containers/"+containerID+"/stats", query, nil) + if err != nil { + return types.ContainerStats{}, err + } + + osType := getDockerOS(resp.header.Get("Server")) + return types.ContainerStats{Body: resp.body, OSType: osType}, err +} + +// ContainerStatsOneShot gets a single stat entry from a container. +// It differs from `ContainerStats` in that the API should not wait to prime the stats +func (cli *Client) ContainerStatsOneShot(ctx context.Context, containerID string) (types.ContainerStats, error) { + query := url.Values{} + query.Set("stream", "0") + query.Set("one-shot", "1") + + resp, err := cli.get(ctx, "/containers/"+containerID+"/stats", query, nil) + if err != nil { + return types.ContainerStats{}, err + } + + osType := getDockerOS(resp.header.Get("Server")) + return types.ContainerStats{Body: resp.body, OSType: osType}, err +} diff --git a/vendor/github.com/docker/docker/client/container_stop.go b/vendor/github.com/docker/docker/client/container_stop.go new file mode 100644 index 0000000000..2a43ce2274 --- /dev/null +++ b/vendor/github.com/docker/docker/client/container_stop.go @@ -0,0 +1,30 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "net/url" + "strconv" + + "github.com/docker/docker/api/types/container" + "github.com/docker/docker/api/types/versions" +) + +// ContainerStop stops a container. In case the container fails to stop +// gracefully within a time frame specified by the timeout argument, +// it is forcefully terminated (killed). +// +// If the timeout is nil, the container's StopTimeout value is used, if set, +// otherwise the engine default. A negative timeout value can be specified, +// meaning no timeout, i.e. no forceful termination is performed. +func (cli *Client) ContainerStop(ctx context.Context, containerID string, options container.StopOptions) error { + query := url.Values{} + if options.Timeout != nil { + query.Set("t", strconv.Itoa(*options.Timeout)) + } + if options.Signal != "" && versions.GreaterThanOrEqualTo(cli.version, "1.42") { + query.Set("signal", options.Signal) + } + resp, err := cli.post(ctx, "/containers/"+containerID+"/stop", query, nil, nil) + ensureReaderClosed(resp) + return err +} diff --git a/vendor/github.com/docker/docker/client/container_top.go b/vendor/github.com/docker/docker/client/container_top.go new file mode 100644 index 0000000000..a5b78999bf --- /dev/null +++ b/vendor/github.com/docker/docker/client/container_top.go @@ -0,0 +1,28 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "encoding/json" + "net/url" + "strings" + + "github.com/docker/docker/api/types/container" +) + +// ContainerTop shows process information from within a container. +func (cli *Client) ContainerTop(ctx context.Context, containerID string, arguments []string) (container.ContainerTopOKBody, error) { + var response container.ContainerTopOKBody + query := url.Values{} + if len(arguments) > 0 { + query.Set("ps_args", strings.Join(arguments, " ")) + } + + resp, err := cli.get(ctx, "/containers/"+containerID+"/top", query, nil) + defer ensureReaderClosed(resp) + if err != nil { + return response, err + } + + err = json.NewDecoder(resp.body).Decode(&response) + return response, err +} diff --git a/vendor/github.com/docker/docker/client/container_unpause.go b/vendor/github.com/docker/docker/client/container_unpause.go new file mode 100644 index 0000000000..1d8f873169 --- /dev/null +++ b/vendor/github.com/docker/docker/client/container_unpause.go @@ -0,0 +1,10 @@ +package client // import "github.com/docker/docker/client" + +import "context" + +// ContainerUnpause resumes the process execution within a container +func (cli *Client) ContainerUnpause(ctx context.Context, containerID string) error { + resp, err := cli.post(ctx, "/containers/"+containerID+"/unpause", nil, nil, nil) + ensureReaderClosed(resp) + return err +} diff --git a/vendor/github.com/docker/docker/client/container_update.go b/vendor/github.com/docker/docker/client/container_update.go new file mode 100644 index 0000000000..bf68a5300e --- /dev/null +++ b/vendor/github.com/docker/docker/client/container_update.go @@ -0,0 +1,21 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "encoding/json" + + "github.com/docker/docker/api/types/container" +) + +// ContainerUpdate updates the resources of a container. +func (cli *Client) ContainerUpdate(ctx context.Context, containerID string, updateConfig container.UpdateConfig) (container.ContainerUpdateOKBody, error) { + var response container.ContainerUpdateOKBody + serverResp, err := cli.post(ctx, "/containers/"+containerID+"/update", nil, updateConfig, nil) + defer ensureReaderClosed(serverResp) + if err != nil { + return response, err + } + + err = json.NewDecoder(serverResp.body).Decode(&response) + return response, err +} diff --git a/vendor/github.com/docker/docker/client/container_wait.go b/vendor/github.com/docker/docker/client/container_wait.go new file mode 100644 index 0000000000..2375eb1e80 --- /dev/null +++ b/vendor/github.com/docker/docker/client/container_wait.go @@ -0,0 +1,104 @@ +package client // import "github.com/docker/docker/client" + +import ( + "bytes" + "context" + "encoding/json" + "errors" + "io" + "net/url" + + "github.com/docker/docker/api/types/container" + "github.com/docker/docker/api/types/versions" +) + +const containerWaitErrorMsgLimit = 2 * 1024 /* Max: 2KiB */ + +// ContainerWait waits until the specified container is in a certain state +// indicated by the given condition, either "not-running" (default), +// "next-exit", or "removed". +// +// If this client's API version is before 1.30, condition is ignored and +// ContainerWait will return immediately with the two channels, as the server +// will wait as if the condition were "not-running". +// +// If this client's API version is at least 1.30, ContainerWait blocks until +// the request has been acknowledged by the server (with a response header), +// then returns two channels on which the caller can wait for the exit status +// of the container or an error if there was a problem either beginning the +// wait request or in getting the response. This allows the caller to +// synchronize ContainerWait with other calls, such as specifying a +// "next-exit" condition before issuing a ContainerStart request. +func (cli *Client) ContainerWait(ctx context.Context, containerID string, condition container.WaitCondition) (<-chan container.WaitResponse, <-chan error) { + if versions.LessThan(cli.ClientVersion(), "1.30") { + return cli.legacyContainerWait(ctx, containerID) + } + + resultC := make(chan container.WaitResponse) + errC := make(chan error, 1) + + query := url.Values{} + if condition != "" { + query.Set("condition", string(condition)) + } + + resp, err := cli.post(ctx, "/containers/"+containerID+"/wait", query, nil, nil) + if err != nil { + defer ensureReaderClosed(resp) + errC <- err + return resultC, errC + } + + go func() { + defer ensureReaderClosed(resp) + + body := resp.body + responseText := bytes.NewBuffer(nil) + stream := io.TeeReader(body, responseText) + + var res container.WaitResponse + if err := json.NewDecoder(stream).Decode(&res); err != nil { + // NOTE(nicks): The /wait API does not work well with HTTP proxies. + // At any time, the proxy could cut off the response stream. + // + // But because the HTTP status has already been written, the proxy's + // only option is to write a plaintext error message. + // + // If there's a JSON parsing error, read the real error message + // off the body and send it to the client. + _, _ = io.ReadAll(io.LimitReader(stream, containerWaitErrorMsgLimit)) + errC <- errors.New(responseText.String()) + return + } + + resultC <- res + }() + + return resultC, errC +} + +// legacyContainerWait returns immediately and doesn't have an option to wait +// until the container is removed. +func (cli *Client) legacyContainerWait(ctx context.Context, containerID string) (<-chan container.WaitResponse, <-chan error) { + resultC := make(chan container.WaitResponse) + errC := make(chan error) + + go func() { + resp, err := cli.post(ctx, "/containers/"+containerID+"/wait", nil, nil, nil) + if err != nil { + errC <- err + return + } + defer ensureReaderClosed(resp) + + var res container.WaitResponse + if err := json.NewDecoder(resp.body).Decode(&res); err != nil { + errC <- err + return + } + + resultC <- res + }() + + return resultC, errC +} diff --git a/vendor/github.com/docker/docker/client/disk_usage.go b/vendor/github.com/docker/docker/client/disk_usage.go new file mode 100644 index 0000000000..ba0d92e9e6 --- /dev/null +++ b/vendor/github.com/docker/docker/client/disk_usage.go @@ -0,0 +1,33 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "encoding/json" + "fmt" + "net/url" + + "github.com/docker/docker/api/types" +) + +// DiskUsage requests the current data usage from the daemon +func (cli *Client) DiskUsage(ctx context.Context, options types.DiskUsageOptions) (types.DiskUsage, error) { + var query url.Values + if len(options.Types) > 0 { + query = url.Values{} + for _, t := range options.Types { + query.Add("type", string(t)) + } + } + + serverResp, err := cli.get(ctx, "/system/df", query, nil) + defer ensureReaderClosed(serverResp) + if err != nil { + return types.DiskUsage{}, err + } + + var du types.DiskUsage + if err := json.NewDecoder(serverResp.body).Decode(&du); err != nil { + return types.DiskUsage{}, fmt.Errorf("Error retrieving disk usage: %v", err) + } + return du, nil +} diff --git a/vendor/github.com/docker/docker/client/distribution_inspect.go b/vendor/github.com/docker/docker/client/distribution_inspect.go new file mode 100644 index 0000000000..7f36c99a01 --- /dev/null +++ b/vendor/github.com/docker/docker/client/distribution_inspect.go @@ -0,0 +1,38 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "encoding/json" + "net/url" + + registrytypes "github.com/docker/docker/api/types/registry" +) + +// DistributionInspect returns the image digest with the full manifest. +func (cli *Client) DistributionInspect(ctx context.Context, image, encodedRegistryAuth string) (registrytypes.DistributionInspect, error) { + // Contact the registry to retrieve digest and platform information + var distributionInspect registrytypes.DistributionInspect + if image == "" { + return distributionInspect, objectNotFoundError{object: "distribution", id: image} + } + + if err := cli.NewVersionError("1.30", "distribution inspect"); err != nil { + return distributionInspect, err + } + var headers map[string][]string + + if encodedRegistryAuth != "" { + headers = map[string][]string{ + "X-Registry-Auth": {encodedRegistryAuth}, + } + } + + resp, err := cli.get(ctx, "/distribution/"+image+"/json", url.Values{}, headers) + defer ensureReaderClosed(resp) + if err != nil { + return distributionInspect, err + } + + err = json.NewDecoder(resp.body).Decode(&distributionInspect) + return distributionInspect, err +} diff --git a/vendor/github.com/docker/docker/client/envvars.go b/vendor/github.com/docker/docker/client/envvars.go new file mode 100644 index 0000000000..61dd45c1d7 --- /dev/null +++ b/vendor/github.com/docker/docker/client/envvars.go @@ -0,0 +1,90 @@ +package client // import "github.com/docker/docker/client" + +const ( + // EnvOverrideHost is the name of the environment variable that can be used + // to override the default host to connect to (DefaultDockerHost). + // + // This env-var is read by FromEnv and WithHostFromEnv and when set to a + // non-empty value, takes precedence over the default host (which is platform + // specific), or any host already set. + EnvOverrideHost = "DOCKER_HOST" + + // EnvOverrideAPIVersion is the name of the environment variable that can + // be used to override the API version to use. Value should be + // formatted as MAJOR.MINOR, for example, "1.19". + // + // This env-var is read by FromEnv and WithVersionFromEnv and when set to a + // non-empty value, takes precedence over API version negotiation. + // + // This environment variable should be used for debugging purposes only, as + // it can set the client to use an incompatible (or invalid) API version. + EnvOverrideAPIVersion = "DOCKER_API_VERSION" + + // EnvOverrideCertPath is the name of the environment variable that can be + // used to specify the directory from which to load the TLS certificates + // (ca.pem, cert.pem, key.pem) from. These certificates are used to configure + // the Client for a TCP connection protected by TLS client authentication. + // + // TLS certificate verification is enabled by default if the Client is configured + // to use a TLS connection. Refer to EnvTLSVerify below to learn how to + // disable verification for testing purposes. + // + // WARNING: Access to the remote API is equivalent to root access to the + // host where the daemon runs. Do not expose the API without protection, + // and only if needed. Make sure you are familiar with the "daemon attack + // surface" (https://docs.docker.com/go/attack-surface/). + // + // For local access to the API, it is recommended to connect with the daemon + // using the default local socket connection (on Linux), or the named pipe + // (on Windows). + // + // If you need to access the API of a remote daemon, consider using an SSH + // (ssh://) connection, which is easier to set up, and requires no additional + // configuration if the host is accessible using ssh. + // + // If you cannot use the alternatives above, and you must expose the API over + // a TCP connection, refer to https://docs.docker.com/engine/security/protect-access/ + // to learn how to configure the daemon and client to use a TCP connection + // with TLS client authentication. Make sure you know the differences between + // a regular TLS connection and a TLS connection protected by TLS client + // authentication, and verify that the API cannot be accessed by other clients. + EnvOverrideCertPath = "DOCKER_CERT_PATH" + + // EnvTLSVerify is the name of the environment variable that can be used to + // enable or disable TLS certificate verification. When set to a non-empty + // value, TLS certificate verification is enabled, and the client is configured + // to use a TLS connection, using certificates from the default directories + // (within `~/.docker`); refer to EnvOverrideCertPath above for additional + // details. + // + // WARNING: Access to the remote API is equivalent to root access to the + // host where the daemon runs. Do not expose the API without protection, + // and only if needed. Make sure you are familiar with the "daemon attack + // surface" (https://docs.docker.com/go/attack-surface/). + // + // Before setting up your client and daemon to use a TCP connection with TLS + // client authentication, consider using one of the alternatives mentioned + // in EnvOverrideCertPath above. + // + // Disabling TLS certificate verification (for testing purposes) + // + // TLS certificate verification is enabled by default if the Client is configured + // to use a TLS connection, and it is highly recommended to keep verification + // enabled to prevent machine-in-the-middle attacks. Refer to the documentation + // at https://docs.docker.com/engine/security/protect-access/ and pages linked + // from that page to learn how to configure the daemon and client to use a + // TCP connection with TLS client authentication enabled. + // + // Set the "DOCKER_TLS_VERIFY" environment to an empty string ("") to + // disable TLS certificate verification. Disabling verification is insecure, + // so should only be done for testing purposes. From the Go documentation + // (https://pkg.go.dev/crypto/tls#Config): + // + // InsecureSkipVerify controls whether a client verifies the server's + // certificate chain and host name. If InsecureSkipVerify is true, crypto/tls + // accepts any certificate presented by the server and any host name in that + // certificate. In this mode, TLS is susceptible to machine-in-the-middle + // attacks unless custom verification is used. This should be used only for + // testing or in combination with VerifyConnection or VerifyPeerCertificate. + EnvTLSVerify = "DOCKER_TLS_VERIFY" +) diff --git a/vendor/github.com/docker/docker/client/errors.go b/vendor/github.com/docker/docker/client/errors.go new file mode 100644 index 0000000000..e5a8a865f9 --- /dev/null +++ b/vendor/github.com/docker/docker/client/errors.go @@ -0,0 +1,93 @@ +package client // import "github.com/docker/docker/client" + +import ( + "fmt" + + "github.com/docker/docker/api/types/versions" + "github.com/docker/docker/errdefs" + "github.com/pkg/errors" +) + +// errConnectionFailed implements an error returned when connection failed. +type errConnectionFailed struct { + host string +} + +// Error returns a string representation of an errConnectionFailed +func (err errConnectionFailed) Error() string { + if err.host == "" { + return "Cannot connect to the Docker daemon. Is the docker daemon running on this host?" + } + return fmt.Sprintf("Cannot connect to the Docker daemon at %s. Is the docker daemon running?", err.host) +} + +// IsErrConnectionFailed returns true if the error is caused by connection failed. +func IsErrConnectionFailed(err error) bool { + return errors.As(err, &errConnectionFailed{}) +} + +// ErrorConnectionFailed returns an error with host in the error message when connection to docker daemon failed. +func ErrorConnectionFailed(host string) error { + return errConnectionFailed{host: host} +} + +// Deprecated: use the errdefs.NotFound() interface instead. Kept for backward compatibility +type notFound interface { + error + NotFound() bool +} + +// IsErrNotFound returns true if the error is a NotFound error, which is returned +// by the API when some object is not found. +func IsErrNotFound(err error) bool { + if errdefs.IsNotFound(err) { + return true + } + var e notFound + return errors.As(err, &e) +} + +type objectNotFoundError struct { + object string + id string +} + +func (e objectNotFoundError) NotFound() {} + +func (e objectNotFoundError) Error() string { + return fmt.Sprintf("Error: No such %s: %s", e.object, e.id) +} + +// IsErrUnauthorized returns true if the error is caused +// when a remote registry authentication fails +// +// Deprecated: use errdefs.IsUnauthorized +func IsErrUnauthorized(err error) bool { + return errdefs.IsUnauthorized(err) +} + +type pluginPermissionDenied struct { + name string +} + +func (e pluginPermissionDenied) Error() string { + return "Permission denied while installing plugin " + e.name +} + +// IsErrNotImplemented returns true if the error is a NotImplemented error. +// This is returned by the API when a requested feature has not been +// implemented. +// +// Deprecated: use errdefs.IsNotImplemented +func IsErrNotImplemented(err error) bool { + return errdefs.IsNotImplemented(err) +} + +// NewVersionError returns an error if the APIVersion required +// if less than the current supported version +func (cli *Client) NewVersionError(APIrequired, feature string) error { + if cli.version != "" && versions.LessThan(cli.version, APIrequired) { + return fmt.Errorf("%q requires API version %s, but the Docker daemon API version is %s", feature, APIrequired, cli.version) + } + return nil +} diff --git a/vendor/github.com/docker/docker/client/events.go b/vendor/github.com/docker/docker/client/events.go new file mode 100644 index 0000000000..a9c48a9288 --- /dev/null +++ b/vendor/github.com/docker/docker/client/events.go @@ -0,0 +1,101 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "encoding/json" + "net/url" + "time" + + "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/events" + "github.com/docker/docker/api/types/filters" + timetypes "github.com/docker/docker/api/types/time" +) + +// Events returns a stream of events in the daemon. It's up to the caller to close the stream +// by cancelling the context. Once the stream has been completely read an io.EOF error will +// be sent over the error channel. If an error is sent all processing will be stopped. It's up +// to the caller to reopen the stream in the event of an error by reinvoking this method. +func (cli *Client) Events(ctx context.Context, options types.EventsOptions) (<-chan events.Message, <-chan error) { + messages := make(chan events.Message) + errs := make(chan error, 1) + + started := make(chan struct{}) + go func() { + defer close(errs) + + query, err := buildEventsQueryParams(cli.version, options) + if err != nil { + close(started) + errs <- err + return + } + + resp, err := cli.get(ctx, "/events", query, nil) + if err != nil { + close(started) + errs <- err + return + } + defer resp.body.Close() + + decoder := json.NewDecoder(resp.body) + + close(started) + for { + select { + case <-ctx.Done(): + errs <- ctx.Err() + return + default: + var event events.Message + if err := decoder.Decode(&event); err != nil { + errs <- err + return + } + + select { + case messages <- event: + case <-ctx.Done(): + errs <- ctx.Err() + return + } + } + } + }() + <-started + + return messages, errs +} + +func buildEventsQueryParams(cliVersion string, options types.EventsOptions) (url.Values, error) { + query := url.Values{} + ref := time.Now() + + if options.Since != "" { + ts, err := timetypes.GetTimestamp(options.Since, ref) + if err != nil { + return nil, err + } + query.Set("since", ts) + } + + if options.Until != "" { + ts, err := timetypes.GetTimestamp(options.Until, ref) + if err != nil { + return nil, err + } + query.Set("until", ts) + } + + if options.Filters.Len() > 0 { + //nolint:staticcheck // ignore SA1019 for old code + filterJSON, err := filters.ToParamWithVersion(cliVersion, options.Filters) + if err != nil { + return nil, err + } + query.Set("filters", filterJSON) + } + + return query, nil +} diff --git a/vendor/github.com/docker/docker/client/hijack.go b/vendor/github.com/docker/docker/client/hijack.go new file mode 100644 index 0000000000..6bdacab10a --- /dev/null +++ b/vendor/github.com/docker/docker/client/hijack.go @@ -0,0 +1,153 @@ +package client // import "github.com/docker/docker/client" + +import ( + "bufio" + "context" + "crypto/tls" + "fmt" + "net" + "net/http" + "net/http/httputil" + "net/url" + "time" + + "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/versions" + "github.com/docker/go-connections/sockets" + "github.com/pkg/errors" +) + +// postHijacked sends a POST request and hijacks the connection. +func (cli *Client) postHijacked(ctx context.Context, path string, query url.Values, body interface{}, headers map[string][]string) (types.HijackedResponse, error) { + bodyEncoded, err := encodeData(body) + if err != nil { + return types.HijackedResponse{}, err + } + + apiPath := cli.getAPIPath(ctx, path, query) + req, err := http.NewRequest(http.MethodPost, apiPath, bodyEncoded) + if err != nil { + return types.HijackedResponse{}, err + } + req = cli.addHeaders(req, headers) + + conn, mediaType, err := cli.setupHijackConn(ctx, req, "tcp") + if err != nil { + return types.HijackedResponse{}, err + } + + return types.NewHijackedResponse(conn, mediaType), err +} + +// DialHijack returns a hijacked connection with negotiated protocol proto. +func (cli *Client) DialHijack(ctx context.Context, url, proto string, meta map[string][]string) (net.Conn, error) { + req, err := http.NewRequest(http.MethodPost, url, nil) + if err != nil { + return nil, err + } + req = cli.addHeaders(req, meta) + + conn, _, err := cli.setupHijackConn(ctx, req, proto) + return conn, err +} + +// fallbackDial is used when WithDialer() was not called. +// See cli.Dialer(). +func fallbackDial(proto, addr string, tlsConfig *tls.Config) (net.Conn, error) { + if tlsConfig != nil && proto != "unix" && proto != "npipe" { + return tls.Dial(proto, addr, tlsConfig) + } + if proto == "npipe" { + return sockets.DialPipe(addr, 32*time.Second) + } + return net.Dial(proto, addr) +} + +func (cli *Client) setupHijackConn(ctx context.Context, req *http.Request, proto string) (net.Conn, string, error) { + req.Host = cli.addr + req.Header.Set("Connection", "Upgrade") + req.Header.Set("Upgrade", proto) + + dialer := cli.Dialer() + conn, err := dialer(ctx) + if err != nil { + return nil, "", errors.Wrap(err, "cannot connect to the Docker daemon. Is 'docker daemon' running on this host?") + } + + // When we set up a TCP connection for hijack, there could be long periods + // of inactivity (a long running command with no output) that in certain + // network setups may cause ECONNTIMEOUT, leaving the client in an unknown + // state. Setting TCP KeepAlive on the socket connection will prohibit + // ECONNTIMEOUT unless the socket connection truly is broken + if tcpConn, ok := conn.(*net.TCPConn); ok { + tcpConn.SetKeepAlive(true) + tcpConn.SetKeepAlivePeriod(30 * time.Second) + } + + clientconn := httputil.NewClientConn(conn, nil) + defer clientconn.Close() + + // Server hijacks the connection, error 'connection closed' expected + resp, err := clientconn.Do(req) + + //nolint:staticcheck // ignore SA1019 for connecting to old (pre go1.8) daemons + if err != httputil.ErrPersistEOF { + if err != nil { + return nil, "", err + } + if resp.StatusCode != http.StatusSwitchingProtocols { + resp.Body.Close() + return nil, "", fmt.Errorf("unable to upgrade to %s, received %d", proto, resp.StatusCode) + } + } + + c, br := clientconn.Hijack() + if br.Buffered() > 0 { + // If there is buffered content, wrap the connection. We return an + // object that implements CloseWrite if the underlying connection + // implements it. + if _, ok := c.(types.CloseWriter); ok { + c = &hijackedConnCloseWriter{&hijackedConn{c, br}} + } else { + c = &hijackedConn{c, br} + } + } else { + br.Reset(nil) + } + + var mediaType string + if versions.GreaterThanOrEqualTo(cli.ClientVersion(), "1.42") { + // Prior to 1.42, Content-Type is always set to raw-stream and not relevant + mediaType = resp.Header.Get("Content-Type") + } + + return c, mediaType, nil +} + +// hijackedConn wraps a net.Conn and is returned by setupHijackConn in the case +// that a) there was already buffered data in the http layer when Hijack() was +// called, and b) the underlying net.Conn does *not* implement CloseWrite(). +// hijackedConn does not implement CloseWrite() either. +type hijackedConn struct { + net.Conn + r *bufio.Reader +} + +func (c *hijackedConn) Read(b []byte) (int, error) { + return c.r.Read(b) +} + +// hijackedConnCloseWriter is a hijackedConn which additionally implements +// CloseWrite(). It is returned by setupHijackConn in the case that a) there +// was already buffered data in the http layer when Hijack() was called, and b) +// the underlying net.Conn *does* implement CloseWrite(). +type hijackedConnCloseWriter struct { + *hijackedConn +} + +var _ types.CloseWriter = &hijackedConnCloseWriter{} + +func (c *hijackedConnCloseWriter) CloseWrite() error { + conn := c.Conn.(types.CloseWriter) + return conn.CloseWrite() +} diff --git a/vendor/github.com/docker/docker/client/image_build.go b/vendor/github.com/docker/docker/client/image_build.go new file mode 100644 index 0000000000..d16e1d8ea9 --- /dev/null +++ b/vendor/github.com/docker/docker/client/image_build.go @@ -0,0 +1,146 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "encoding/base64" + "encoding/json" + "io" + "net/http" + "net/url" + "strconv" + "strings" + + "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/container" +) + +// ImageBuild sends a request to the daemon to build images. +// The Body in the response implements an io.ReadCloser and it's up to the caller to +// close it. +func (cli *Client) ImageBuild(ctx context.Context, buildContext io.Reader, options types.ImageBuildOptions) (types.ImageBuildResponse, error) { + query, err := cli.imageBuildOptionsToQuery(options) + if err != nil { + return types.ImageBuildResponse{}, err + } + + headers := http.Header(make(map[string][]string)) + buf, err := json.Marshal(options.AuthConfigs) + if err != nil { + return types.ImageBuildResponse{}, err + } + headers.Add("X-Registry-Config", base64.URLEncoding.EncodeToString(buf)) + + headers.Set("Content-Type", "application/x-tar") + + serverResp, err := cli.postRaw(ctx, "/build", query, buildContext, headers) + if err != nil { + return types.ImageBuildResponse{}, err + } + + osType := getDockerOS(serverResp.header.Get("Server")) + + return types.ImageBuildResponse{ + Body: serverResp.body, + OSType: osType, + }, nil +} + +func (cli *Client) imageBuildOptionsToQuery(options types.ImageBuildOptions) (url.Values, error) { + query := url.Values{ + "t": options.Tags, + "securityopt": options.SecurityOpt, + "extrahosts": options.ExtraHosts, + } + if options.SuppressOutput { + query.Set("q", "1") + } + if options.RemoteContext != "" { + query.Set("remote", options.RemoteContext) + } + if options.NoCache { + query.Set("nocache", "1") + } + if options.Remove { + query.Set("rm", "1") + } else { + query.Set("rm", "0") + } + + if options.ForceRemove { + query.Set("forcerm", "1") + } + + if options.PullParent { + query.Set("pull", "1") + } + + if options.Squash { + if err := cli.NewVersionError("1.25", "squash"); err != nil { + return query, err + } + query.Set("squash", "1") + } + + if !container.Isolation.IsDefault(options.Isolation) { + query.Set("isolation", string(options.Isolation)) + } + + query.Set("cpusetcpus", options.CPUSetCPUs) + query.Set("networkmode", options.NetworkMode) + query.Set("cpusetmems", options.CPUSetMems) + query.Set("cpushares", strconv.FormatInt(options.CPUShares, 10)) + query.Set("cpuquota", strconv.FormatInt(options.CPUQuota, 10)) + query.Set("cpuperiod", strconv.FormatInt(options.CPUPeriod, 10)) + query.Set("memory", strconv.FormatInt(options.Memory, 10)) + query.Set("memswap", strconv.FormatInt(options.MemorySwap, 10)) + query.Set("cgroupparent", options.CgroupParent) + query.Set("shmsize", strconv.FormatInt(options.ShmSize, 10)) + query.Set("dockerfile", options.Dockerfile) + query.Set("target", options.Target) + + ulimitsJSON, err := json.Marshal(options.Ulimits) + if err != nil { + return query, err + } + query.Set("ulimits", string(ulimitsJSON)) + + buildArgsJSON, err := json.Marshal(options.BuildArgs) + if err != nil { + return query, err + } + query.Set("buildargs", string(buildArgsJSON)) + + labelsJSON, err := json.Marshal(options.Labels) + if err != nil { + return query, err + } + query.Set("labels", string(labelsJSON)) + + cacheFromJSON, err := json.Marshal(options.CacheFrom) + if err != nil { + return query, err + } + query.Set("cachefrom", string(cacheFromJSON)) + if options.SessionID != "" { + query.Set("session", options.SessionID) + } + if options.Platform != "" { + if err := cli.NewVersionError("1.32", "platform"); err != nil { + return query, err + } + query.Set("platform", strings.ToLower(options.Platform)) + } + if options.BuildID != "" { + query.Set("buildid", options.BuildID) + } + query.Set("version", string(options.Version)) + + if options.Outputs != nil { + outputsJSON, err := json.Marshal(options.Outputs) + if err != nil { + return query, err + } + query.Set("outputs", string(outputsJSON)) + } + return query, nil +} diff --git a/vendor/github.com/docker/docker/client/image_create.go b/vendor/github.com/docker/docker/client/image_create.go new file mode 100644 index 0000000000..b1c0227775 --- /dev/null +++ b/vendor/github.com/docker/docker/client/image_create.go @@ -0,0 +1,37 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "io" + "net/url" + "strings" + + "github.com/docker/distribution/reference" + "github.com/docker/docker/api/types" +) + +// ImageCreate creates a new image based on the parent options. +// It returns the JSON content in the response body. +func (cli *Client) ImageCreate(ctx context.Context, parentReference string, options types.ImageCreateOptions) (io.ReadCloser, error) { + ref, err := reference.ParseNormalizedNamed(parentReference) + if err != nil { + return nil, err + } + + query := url.Values{} + query.Set("fromImage", reference.FamiliarName(ref)) + query.Set("tag", getAPITagFromNamedRef(ref)) + if options.Platform != "" { + query.Set("platform", strings.ToLower(options.Platform)) + } + resp, err := cli.tryImageCreate(ctx, query, options.RegistryAuth) + if err != nil { + return nil, err + } + return resp.body, nil +} + +func (cli *Client) tryImageCreate(ctx context.Context, query url.Values, registryAuth string) (serverResponse, error) { + headers := map[string][]string{"X-Registry-Auth": {registryAuth}} + return cli.post(ctx, "/images/create", query, nil, headers) +} diff --git a/vendor/github.com/docker/docker/client/image_history.go b/vendor/github.com/docker/docker/client/image_history.go new file mode 100644 index 0000000000..b5bea10d8f --- /dev/null +++ b/vendor/github.com/docker/docker/client/image_history.go @@ -0,0 +1,22 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "encoding/json" + "net/url" + + "github.com/docker/docker/api/types/image" +) + +// ImageHistory returns the changes in an image in history format. +func (cli *Client) ImageHistory(ctx context.Context, imageID string) ([]image.HistoryResponseItem, error) { + var history []image.HistoryResponseItem + serverResp, err := cli.get(ctx, "/images/"+imageID+"/history", url.Values{}, nil) + defer ensureReaderClosed(serverResp) + if err != nil { + return history, err + } + + err = json.NewDecoder(serverResp.body).Decode(&history) + return history, err +} diff --git a/vendor/github.com/docker/docker/client/image_import.go b/vendor/github.com/docker/docker/client/image_import.go new file mode 100644 index 0000000000..c5de42cb79 --- /dev/null +++ b/vendor/github.com/docker/docker/client/image_import.go @@ -0,0 +1,40 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "io" + "net/url" + "strings" + + "github.com/docker/distribution/reference" + "github.com/docker/docker/api/types" +) + +// ImageImport creates a new image based on the source options. +// It returns the JSON content in the response body. +func (cli *Client) ImageImport(ctx context.Context, source types.ImageImportSource, ref string, options types.ImageImportOptions) (io.ReadCloser, error) { + if ref != "" { + // Check if the given image name can be resolved + if _, err := reference.ParseNormalizedNamed(ref); err != nil { + return nil, err + } + } + + query := url.Values{} + query.Set("fromSrc", source.SourceName) + query.Set("repo", ref) + query.Set("tag", options.Tag) + query.Set("message", options.Message) + if options.Platform != "" { + query.Set("platform", strings.ToLower(options.Platform)) + } + for _, change := range options.Changes { + query.Add("changes", change) + } + + resp, err := cli.postRaw(ctx, "/images/create", query, source.Source, nil) + if err != nil { + return nil, err + } + return resp.body, nil +} diff --git a/vendor/github.com/docker/docker/client/image_inspect.go b/vendor/github.com/docker/docker/client/image_inspect.go new file mode 100644 index 0000000000..1de10e5a08 --- /dev/null +++ b/vendor/github.com/docker/docker/client/image_inspect.go @@ -0,0 +1,32 @@ +package client // import "github.com/docker/docker/client" + +import ( + "bytes" + "context" + "encoding/json" + "io" + + "github.com/docker/docker/api/types" +) + +// ImageInspectWithRaw returns the image information and its raw representation. +func (cli *Client) ImageInspectWithRaw(ctx context.Context, imageID string) (types.ImageInspect, []byte, error) { + if imageID == "" { + return types.ImageInspect{}, nil, objectNotFoundError{object: "image", id: imageID} + } + serverResp, err := cli.get(ctx, "/images/"+imageID+"/json", nil, nil) + defer ensureReaderClosed(serverResp) + if err != nil { + return types.ImageInspect{}, nil, err + } + + body, err := io.ReadAll(serverResp.body) + if err != nil { + return types.ImageInspect{}, nil, err + } + + var response types.ImageInspect + rdr := bytes.NewReader(body) + err = json.NewDecoder(rdr).Decode(&response) + return response, body, err +} diff --git a/vendor/github.com/docker/docker/client/image_list.go b/vendor/github.com/docker/docker/client/image_list.go new file mode 100644 index 0000000000..950d513334 --- /dev/null +++ b/vendor/github.com/docker/docker/client/image_list.go @@ -0,0 +1,49 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "encoding/json" + "net/url" + + "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/filters" + "github.com/docker/docker/api/types/versions" +) + +// ImageList returns a list of images in the docker host. +func (cli *Client) ImageList(ctx context.Context, options types.ImageListOptions) ([]types.ImageSummary, error) { + var images []types.ImageSummary + query := url.Values{} + + optionFilters := options.Filters + referenceFilters := optionFilters.Get("reference") + if versions.LessThan(cli.version, "1.25") && len(referenceFilters) > 0 { + query.Set("filter", referenceFilters[0]) + for _, filterValue := range referenceFilters { + optionFilters.Del("reference", filterValue) + } + } + if optionFilters.Len() > 0 { + //nolint:staticcheck // ignore SA1019 for old code + filterJSON, err := filters.ToParamWithVersion(cli.version, optionFilters) + if err != nil { + return images, err + } + query.Set("filters", filterJSON) + } + if options.All { + query.Set("all", "1") + } + if options.SharedSize && versions.GreaterThanOrEqualTo(cli.version, "1.42") { + query.Set("shared-size", "1") + } + + serverResp, err := cli.get(ctx, "/images/json", query, nil) + defer ensureReaderClosed(serverResp) + if err != nil { + return images, err + } + + err = json.NewDecoder(serverResp.body).Decode(&images) + return images, err +} diff --git a/vendor/github.com/docker/docker/client/image_load.go b/vendor/github.com/docker/docker/client/image_load.go new file mode 100644 index 0000000000..91016e493c --- /dev/null +++ b/vendor/github.com/docker/docker/client/image_load.go @@ -0,0 +1,29 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "io" + "net/url" + + "github.com/docker/docker/api/types" +) + +// ImageLoad loads an image in the docker host from the client host. +// It's up to the caller to close the io.ReadCloser in the +// ImageLoadResponse returned by this function. +func (cli *Client) ImageLoad(ctx context.Context, input io.Reader, quiet bool) (types.ImageLoadResponse, error) { + v := url.Values{} + v.Set("quiet", "0") + if quiet { + v.Set("quiet", "1") + } + headers := map[string][]string{"Content-Type": {"application/x-tar"}} + resp, err := cli.postRaw(ctx, "/images/load", v, input, headers) + if err != nil { + return types.ImageLoadResponse{}, err + } + return types.ImageLoadResponse{ + Body: resp.body, + JSON: resp.header.Get("Content-Type") == "application/json", + }, nil +} diff --git a/vendor/github.com/docker/docker/client/image_prune.go b/vendor/github.com/docker/docker/client/image_prune.go new file mode 100644 index 0000000000..56af6d7f98 --- /dev/null +++ b/vendor/github.com/docker/docker/client/image_prune.go @@ -0,0 +1,36 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "encoding/json" + "fmt" + + "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/filters" +) + +// ImagesPrune requests the daemon to delete unused data +func (cli *Client) ImagesPrune(ctx context.Context, pruneFilters filters.Args) (types.ImagesPruneReport, error) { + var report types.ImagesPruneReport + + if err := cli.NewVersionError("1.25", "image prune"); err != nil { + return report, err + } + + query, err := getFiltersQuery(pruneFilters) + if err != nil { + return report, err + } + + serverResp, err := cli.post(ctx, "/images/prune", query, nil, nil) + defer ensureReaderClosed(serverResp) + if err != nil { + return report, err + } + + if err := json.NewDecoder(serverResp.body).Decode(&report); err != nil { + return report, fmt.Errorf("Error retrieving disk usage: %v", err) + } + + return report, nil +} diff --git a/vendor/github.com/docker/docker/client/image_pull.go b/vendor/github.com/docker/docker/client/image_pull.go new file mode 100644 index 0000000000..a23975591b --- /dev/null +++ b/vendor/github.com/docker/docker/client/image_pull.go @@ -0,0 +1,64 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "io" + "net/url" + "strings" + + "github.com/docker/distribution/reference" + "github.com/docker/docker/api/types" + "github.com/docker/docker/errdefs" +) + +// ImagePull requests the docker host to pull an image from a remote registry. +// It executes the privileged function if the operation is unauthorized +// and it tries one more time. +// It's up to the caller to handle the io.ReadCloser and close it properly. +// +// FIXME(vdemeester): there is currently used in a few way in docker/docker +// - if not in trusted content, ref is used to pass the whole reference, and tag is empty +// - if in trusted content, ref is used to pass the reference name, and tag for the digest +func (cli *Client) ImagePull(ctx context.Context, refStr string, options types.ImagePullOptions) (io.ReadCloser, error) { + ref, err := reference.ParseNormalizedNamed(refStr) + if err != nil { + return nil, err + } + + query := url.Values{} + query.Set("fromImage", reference.FamiliarName(ref)) + if !options.All { + query.Set("tag", getAPITagFromNamedRef(ref)) + } + if options.Platform != "" { + query.Set("platform", strings.ToLower(options.Platform)) + } + + resp, err := cli.tryImageCreate(ctx, query, options.RegistryAuth) + if errdefs.IsUnauthorized(err) && options.PrivilegeFunc != nil { + newAuthHeader, privilegeErr := options.PrivilegeFunc() + if privilegeErr != nil { + return nil, privilegeErr + } + resp, err = cli.tryImageCreate(ctx, query, newAuthHeader) + } + if err != nil { + return nil, err + } + return resp.body, nil +} + +// getAPITagFromNamedRef returns a tag from the specified reference. +// This function is necessary as long as the docker "server" api expects +// digests to be sent as tags and makes a distinction between the name +// and tag/digest part of a reference. +func getAPITagFromNamedRef(ref reference.Named) string { + if digested, ok := ref.(reference.Digested); ok { + return digested.Digest().String() + } + ref = reference.TagNameOnly(ref) + if tagged, ok := ref.(reference.Tagged); ok { + return tagged.Tag() + } + return "" +} diff --git a/vendor/github.com/docker/docker/client/image_push.go b/vendor/github.com/docker/docker/client/image_push.go new file mode 100644 index 0000000000..845580d4a4 --- /dev/null +++ b/vendor/github.com/docker/docker/client/image_push.go @@ -0,0 +1,54 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "errors" + "io" + "net/url" + + "github.com/docker/distribution/reference" + "github.com/docker/docker/api/types" + "github.com/docker/docker/errdefs" +) + +// ImagePush requests the docker host to push an image to a remote registry. +// It executes the privileged function if the operation is unauthorized +// and it tries one more time. +// It's up to the caller to handle the io.ReadCloser and close it properly. +func (cli *Client) ImagePush(ctx context.Context, image string, options types.ImagePushOptions) (io.ReadCloser, error) { + ref, err := reference.ParseNormalizedNamed(image) + if err != nil { + return nil, err + } + + if _, isCanonical := ref.(reference.Canonical); isCanonical { + return nil, errors.New("cannot push a digest reference") + } + + name := reference.FamiliarName(ref) + query := url.Values{} + if !options.All { + ref = reference.TagNameOnly(ref) + if tagged, ok := ref.(reference.Tagged); ok { + query.Set("tag", tagged.Tag()) + } + } + + resp, err := cli.tryImagePush(ctx, name, query, options.RegistryAuth) + if errdefs.IsUnauthorized(err) && options.PrivilegeFunc != nil { + newAuthHeader, privilegeErr := options.PrivilegeFunc() + if privilegeErr != nil { + return nil, privilegeErr + } + resp, err = cli.tryImagePush(ctx, name, query, newAuthHeader) + } + if err != nil { + return nil, err + } + return resp.body, nil +} + +func (cli *Client) tryImagePush(ctx context.Context, imageID string, query url.Values, registryAuth string) (serverResponse, error) { + headers := map[string][]string{"X-Registry-Auth": {registryAuth}} + return cli.post(ctx, "/images/"+imageID+"/push", query, nil, headers) +} diff --git a/vendor/github.com/docker/docker/client/image_remove.go b/vendor/github.com/docker/docker/client/image_remove.go new file mode 100644 index 0000000000..6a9fb3f41f --- /dev/null +++ b/vendor/github.com/docker/docker/client/image_remove.go @@ -0,0 +1,31 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "encoding/json" + "net/url" + + "github.com/docker/docker/api/types" +) + +// ImageRemove removes an image from the docker host. +func (cli *Client) ImageRemove(ctx context.Context, imageID string, options types.ImageRemoveOptions) ([]types.ImageDeleteResponseItem, error) { + query := url.Values{} + + if options.Force { + query.Set("force", "1") + } + if !options.PruneChildren { + query.Set("noprune", "1") + } + + var dels []types.ImageDeleteResponseItem + resp, err := cli.delete(ctx, "/images/"+imageID, query, nil) + defer ensureReaderClosed(resp) + if err != nil { + return dels, err + } + + err = json.NewDecoder(resp.body).Decode(&dels) + return dels, err +} diff --git a/vendor/github.com/docker/docker/client/image_save.go b/vendor/github.com/docker/docker/client/image_save.go new file mode 100644 index 0000000000..d1314e4b22 --- /dev/null +++ b/vendor/github.com/docker/docker/client/image_save.go @@ -0,0 +1,21 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "io" + "net/url" +) + +// ImageSave retrieves one or more images from the docker host as an io.ReadCloser. +// It's up to the caller to store the images and close the stream. +func (cli *Client) ImageSave(ctx context.Context, imageIDs []string) (io.ReadCloser, error) { + query := url.Values{ + "names": imageIDs, + } + + resp, err := cli.get(ctx, "/images/get", query, nil) + if err != nil { + return nil, err + } + return resp.body, nil +} diff --git a/vendor/github.com/docker/docker/client/image_search.go b/vendor/github.com/docker/docker/client/image_search.go new file mode 100644 index 0000000000..e69fa37225 --- /dev/null +++ b/vendor/github.com/docker/docker/client/image_search.go @@ -0,0 +1,53 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "encoding/json" + "net/url" + "strconv" + + "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/filters" + "github.com/docker/docker/api/types/registry" + "github.com/docker/docker/errdefs" +) + +// ImageSearch makes the docker host search by a term in a remote registry. +// The list of results is not sorted in any fashion. +func (cli *Client) ImageSearch(ctx context.Context, term string, options types.ImageSearchOptions) ([]registry.SearchResult, error) { + var results []registry.SearchResult + query := url.Values{} + query.Set("term", term) + if options.Limit > 0 { + query.Set("limit", strconv.Itoa(options.Limit)) + } + + if options.Filters.Len() > 0 { + filterJSON, err := filters.ToJSON(options.Filters) + if err != nil { + return results, err + } + query.Set("filters", filterJSON) + } + + resp, err := cli.tryImageSearch(ctx, query, options.RegistryAuth) + defer ensureReaderClosed(resp) + if errdefs.IsUnauthorized(err) && options.PrivilegeFunc != nil { + newAuthHeader, privilegeErr := options.PrivilegeFunc() + if privilegeErr != nil { + return results, privilegeErr + } + resp, err = cli.tryImageSearch(ctx, query, newAuthHeader) + } + if err != nil { + return results, err + } + + err = json.NewDecoder(resp.body).Decode(&results) + return results, err +} + +func (cli *Client) tryImageSearch(ctx context.Context, query url.Values, registryAuth string) (serverResponse, error) { + headers := map[string][]string{"X-Registry-Auth": {registryAuth}} + return cli.get(ctx, "/images/search", query, headers) +} diff --git a/vendor/github.com/docker/docker/client/image_tag.go b/vendor/github.com/docker/docker/client/image_tag.go new file mode 100644 index 0000000000..5652bfc252 --- /dev/null +++ b/vendor/github.com/docker/docker/client/image_tag.go @@ -0,0 +1,37 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "net/url" + + "github.com/docker/distribution/reference" + "github.com/pkg/errors" +) + +// ImageTag tags an image in the docker host +func (cli *Client) ImageTag(ctx context.Context, source, target string) error { + if _, err := reference.ParseAnyReference(source); err != nil { + return errors.Wrapf(err, "Error parsing reference: %q is not a valid repository/tag", source) + } + + ref, err := reference.ParseNormalizedNamed(target) + if err != nil { + return errors.Wrapf(err, "Error parsing reference: %q is not a valid repository/tag", target) + } + + if _, isCanonical := ref.(reference.Canonical); isCanonical { + return errors.New("refusing to create a tag with a digest reference") + } + + ref = reference.TagNameOnly(ref) + + query := url.Values{} + query.Set("repo", reference.FamiliarName(ref)) + if tagged, ok := ref.(reference.Tagged); ok { + query.Set("tag", tagged.Tag()) + } + + resp, err := cli.post(ctx, "/images/"+source+"/tag", query, nil, nil) + ensureReaderClosed(resp) + return err +} diff --git a/vendor/github.com/docker/docker/client/info.go b/vendor/github.com/docker/docker/client/info.go new file mode 100644 index 0000000000..c856704e23 --- /dev/null +++ b/vendor/github.com/docker/docker/client/info.go @@ -0,0 +1,26 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "encoding/json" + "fmt" + "net/url" + + "github.com/docker/docker/api/types" +) + +// Info returns information about the docker server. +func (cli *Client) Info(ctx context.Context) (types.Info, error) { + var info types.Info + serverResp, err := cli.get(ctx, "/info", url.Values{}, nil) + defer ensureReaderClosed(serverResp) + if err != nil { + return info, err + } + + if err := json.NewDecoder(serverResp.body).Decode(&info); err != nil { + return info, fmt.Errorf("Error reading remote info: %v", err) + } + + return info, nil +} diff --git a/vendor/github.com/docker/docker/client/interface.go b/vendor/github.com/docker/docker/client/interface.go new file mode 100644 index 0000000000..e9c1ed722e --- /dev/null +++ b/vendor/github.com/docker/docker/client/interface.go @@ -0,0 +1,201 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "io" + "net" + "net/http" + + "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/container" + "github.com/docker/docker/api/types/events" + "github.com/docker/docker/api/types/filters" + "github.com/docker/docker/api/types/image" + "github.com/docker/docker/api/types/network" + "github.com/docker/docker/api/types/registry" + "github.com/docker/docker/api/types/swarm" + "github.com/docker/docker/api/types/volume" + specs "github.com/opencontainers/image-spec/specs-go/v1" +) + +// CommonAPIClient is the common methods between stable and experimental versions of APIClient. +type CommonAPIClient interface { + ConfigAPIClient + ContainerAPIClient + DistributionAPIClient + ImageAPIClient + NodeAPIClient + NetworkAPIClient + PluginAPIClient + ServiceAPIClient + SwarmAPIClient + SecretAPIClient + SystemAPIClient + VolumeAPIClient + ClientVersion() string + DaemonHost() string + HTTPClient() *http.Client + ServerVersion(ctx context.Context) (types.Version, error) + NegotiateAPIVersion(ctx context.Context) + NegotiateAPIVersionPing(types.Ping) + DialHijack(ctx context.Context, url, proto string, meta map[string][]string) (net.Conn, error) + Dialer() func(context.Context) (net.Conn, error) + Close() error +} + +// ContainerAPIClient defines API client methods for the containers +type ContainerAPIClient interface { + ContainerAttach(ctx context.Context, container string, options types.ContainerAttachOptions) (types.HijackedResponse, error) + ContainerCommit(ctx context.Context, container string, options types.ContainerCommitOptions) (types.IDResponse, error) + ContainerCreate(ctx context.Context, config *container.Config, hostConfig *container.HostConfig, networkingConfig *network.NetworkingConfig, platform *specs.Platform, containerName string) (container.CreateResponse, error) + ContainerDiff(ctx context.Context, container string) ([]container.ContainerChangeResponseItem, error) + ContainerExecAttach(ctx context.Context, execID string, config types.ExecStartCheck) (types.HijackedResponse, error) + ContainerExecCreate(ctx context.Context, container string, config types.ExecConfig) (types.IDResponse, error) + ContainerExecInspect(ctx context.Context, execID string) (types.ContainerExecInspect, error) + ContainerExecResize(ctx context.Context, execID string, options types.ResizeOptions) error + ContainerExecStart(ctx context.Context, execID string, config types.ExecStartCheck) error + ContainerExport(ctx context.Context, container string) (io.ReadCloser, error) + ContainerInspect(ctx context.Context, container string) (types.ContainerJSON, error) + ContainerInspectWithRaw(ctx context.Context, container string, getSize bool) (types.ContainerJSON, []byte, error) + ContainerKill(ctx context.Context, container, signal string) error + ContainerList(ctx context.Context, options types.ContainerListOptions) ([]types.Container, error) + ContainerLogs(ctx context.Context, container string, options types.ContainerLogsOptions) (io.ReadCloser, error) + ContainerPause(ctx context.Context, container string) error + ContainerRemove(ctx context.Context, container string, options types.ContainerRemoveOptions) error + ContainerRename(ctx context.Context, container, newContainerName string) error + ContainerResize(ctx context.Context, container string, options types.ResizeOptions) error + ContainerRestart(ctx context.Context, container string, options container.StopOptions) error + ContainerStatPath(ctx context.Context, container, path string) (types.ContainerPathStat, error) + ContainerStats(ctx context.Context, container string, stream bool) (types.ContainerStats, error) + ContainerStatsOneShot(ctx context.Context, container string) (types.ContainerStats, error) + ContainerStart(ctx context.Context, container string, options types.ContainerStartOptions) error + ContainerStop(ctx context.Context, container string, options container.StopOptions) error + ContainerTop(ctx context.Context, container string, arguments []string) (container.ContainerTopOKBody, error) + ContainerUnpause(ctx context.Context, container string) error + ContainerUpdate(ctx context.Context, container string, updateConfig container.UpdateConfig) (container.ContainerUpdateOKBody, error) + ContainerWait(ctx context.Context, container string, condition container.WaitCondition) (<-chan container.WaitResponse, <-chan error) + CopyFromContainer(ctx context.Context, container, srcPath string) (io.ReadCloser, types.ContainerPathStat, error) + CopyToContainer(ctx context.Context, container, path string, content io.Reader, options types.CopyToContainerOptions) error + ContainersPrune(ctx context.Context, pruneFilters filters.Args) (types.ContainersPruneReport, error) +} + +// DistributionAPIClient defines API client methods for the registry +type DistributionAPIClient interface { + DistributionInspect(ctx context.Context, image, encodedRegistryAuth string) (registry.DistributionInspect, error) +} + +// ImageAPIClient defines API client methods for the images +type ImageAPIClient interface { + ImageBuild(ctx context.Context, context io.Reader, options types.ImageBuildOptions) (types.ImageBuildResponse, error) + BuildCachePrune(ctx context.Context, opts types.BuildCachePruneOptions) (*types.BuildCachePruneReport, error) + BuildCancel(ctx context.Context, id string) error + ImageCreate(ctx context.Context, parentReference string, options types.ImageCreateOptions) (io.ReadCloser, error) + ImageHistory(ctx context.Context, image string) ([]image.HistoryResponseItem, error) + ImageImport(ctx context.Context, source types.ImageImportSource, ref string, options types.ImageImportOptions) (io.ReadCloser, error) + ImageInspectWithRaw(ctx context.Context, image string) (types.ImageInspect, []byte, error) + ImageList(ctx context.Context, options types.ImageListOptions) ([]types.ImageSummary, error) + ImageLoad(ctx context.Context, input io.Reader, quiet bool) (types.ImageLoadResponse, error) + ImagePull(ctx context.Context, ref string, options types.ImagePullOptions) (io.ReadCloser, error) + ImagePush(ctx context.Context, ref string, options types.ImagePushOptions) (io.ReadCloser, error) + ImageRemove(ctx context.Context, image string, options types.ImageRemoveOptions) ([]types.ImageDeleteResponseItem, error) + ImageSearch(ctx context.Context, term string, options types.ImageSearchOptions) ([]registry.SearchResult, error) + ImageSave(ctx context.Context, images []string) (io.ReadCloser, error) + ImageTag(ctx context.Context, image, ref string) error + ImagesPrune(ctx context.Context, pruneFilter filters.Args) (types.ImagesPruneReport, error) +} + +// NetworkAPIClient defines API client methods for the networks +type NetworkAPIClient interface { + NetworkConnect(ctx context.Context, network, container string, config *network.EndpointSettings) error + NetworkCreate(ctx context.Context, name string, options types.NetworkCreate) (types.NetworkCreateResponse, error) + NetworkDisconnect(ctx context.Context, network, container string, force bool) error + NetworkInspect(ctx context.Context, network string, options types.NetworkInspectOptions) (types.NetworkResource, error) + NetworkInspectWithRaw(ctx context.Context, network string, options types.NetworkInspectOptions) (types.NetworkResource, []byte, error) + NetworkList(ctx context.Context, options types.NetworkListOptions) ([]types.NetworkResource, error) + NetworkRemove(ctx context.Context, network string) error + NetworksPrune(ctx context.Context, pruneFilter filters.Args) (types.NetworksPruneReport, error) +} + +// NodeAPIClient defines API client methods for the nodes +type NodeAPIClient interface { + NodeInspectWithRaw(ctx context.Context, nodeID string) (swarm.Node, []byte, error) + NodeList(ctx context.Context, options types.NodeListOptions) ([]swarm.Node, error) + NodeRemove(ctx context.Context, nodeID string, options types.NodeRemoveOptions) error + NodeUpdate(ctx context.Context, nodeID string, version swarm.Version, node swarm.NodeSpec) error +} + +// PluginAPIClient defines API client methods for the plugins +type PluginAPIClient interface { + PluginList(ctx context.Context, filter filters.Args) (types.PluginsListResponse, error) + PluginRemove(ctx context.Context, name string, options types.PluginRemoveOptions) error + PluginEnable(ctx context.Context, name string, options types.PluginEnableOptions) error + PluginDisable(ctx context.Context, name string, options types.PluginDisableOptions) error + PluginInstall(ctx context.Context, name string, options types.PluginInstallOptions) (io.ReadCloser, error) + PluginUpgrade(ctx context.Context, name string, options types.PluginInstallOptions) (io.ReadCloser, error) + PluginPush(ctx context.Context, name string, registryAuth string) (io.ReadCloser, error) + PluginSet(ctx context.Context, name string, args []string) error + PluginInspectWithRaw(ctx context.Context, name string) (*types.Plugin, []byte, error) + PluginCreate(ctx context.Context, createContext io.Reader, options types.PluginCreateOptions) error +} + +// ServiceAPIClient defines API client methods for the services +type ServiceAPIClient interface { + ServiceCreate(ctx context.Context, service swarm.ServiceSpec, options types.ServiceCreateOptions) (types.ServiceCreateResponse, error) + ServiceInspectWithRaw(ctx context.Context, serviceID string, options types.ServiceInspectOptions) (swarm.Service, []byte, error) + ServiceList(ctx context.Context, options types.ServiceListOptions) ([]swarm.Service, error) + ServiceRemove(ctx context.Context, serviceID string) error + ServiceUpdate(ctx context.Context, serviceID string, version swarm.Version, service swarm.ServiceSpec, options types.ServiceUpdateOptions) (types.ServiceUpdateResponse, error) + ServiceLogs(ctx context.Context, serviceID string, options types.ContainerLogsOptions) (io.ReadCloser, error) + TaskLogs(ctx context.Context, taskID string, options types.ContainerLogsOptions) (io.ReadCloser, error) + TaskInspectWithRaw(ctx context.Context, taskID string) (swarm.Task, []byte, error) + TaskList(ctx context.Context, options types.TaskListOptions) ([]swarm.Task, error) +} + +// SwarmAPIClient defines API client methods for the swarm +type SwarmAPIClient interface { + SwarmInit(ctx context.Context, req swarm.InitRequest) (string, error) + SwarmJoin(ctx context.Context, req swarm.JoinRequest) error + SwarmGetUnlockKey(ctx context.Context) (types.SwarmUnlockKeyResponse, error) + SwarmUnlock(ctx context.Context, req swarm.UnlockRequest) error + SwarmLeave(ctx context.Context, force bool) error + SwarmInspect(ctx context.Context) (swarm.Swarm, error) + SwarmUpdate(ctx context.Context, version swarm.Version, swarm swarm.Spec, flags swarm.UpdateFlags) error +} + +// SystemAPIClient defines API client methods for the system +type SystemAPIClient interface { + Events(ctx context.Context, options types.EventsOptions) (<-chan events.Message, <-chan error) + Info(ctx context.Context) (types.Info, error) + RegistryLogin(ctx context.Context, auth types.AuthConfig) (registry.AuthenticateOKBody, error) + DiskUsage(ctx context.Context, options types.DiskUsageOptions) (types.DiskUsage, error) + Ping(ctx context.Context) (types.Ping, error) +} + +// VolumeAPIClient defines API client methods for the volumes +type VolumeAPIClient interface { + VolumeCreate(ctx context.Context, options volume.CreateOptions) (volume.Volume, error) + VolumeInspect(ctx context.Context, volumeID string) (volume.Volume, error) + VolumeInspectWithRaw(ctx context.Context, volumeID string) (volume.Volume, []byte, error) + VolumeList(ctx context.Context, filter filters.Args) (volume.ListResponse, error) + VolumeRemove(ctx context.Context, volumeID string, force bool) error + VolumesPrune(ctx context.Context, pruneFilter filters.Args) (types.VolumesPruneReport, error) + VolumeUpdate(ctx context.Context, volumeID string, version swarm.Version, options volume.UpdateOptions) error +} + +// SecretAPIClient defines API client methods for secrets +type SecretAPIClient interface { + SecretList(ctx context.Context, options types.SecretListOptions) ([]swarm.Secret, error) + SecretCreate(ctx context.Context, secret swarm.SecretSpec) (types.SecretCreateResponse, error) + SecretRemove(ctx context.Context, id string) error + SecretInspectWithRaw(ctx context.Context, name string) (swarm.Secret, []byte, error) + SecretUpdate(ctx context.Context, id string, version swarm.Version, secret swarm.SecretSpec) error +} + +// ConfigAPIClient defines API client methods for configs +type ConfigAPIClient interface { + ConfigList(ctx context.Context, options types.ConfigListOptions) ([]swarm.Config, error) + ConfigCreate(ctx context.Context, config swarm.ConfigSpec) (types.ConfigCreateResponse, error) + ConfigRemove(ctx context.Context, id string) error + ConfigInspectWithRaw(ctx context.Context, name string) (swarm.Config, []byte, error) + ConfigUpdate(ctx context.Context, id string, version swarm.Version, config swarm.ConfigSpec) error +} diff --git a/vendor/github.com/docker/docker/client/interface_experimental.go b/vendor/github.com/docker/docker/client/interface_experimental.go new file mode 100644 index 0000000000..402ffb512c --- /dev/null +++ b/vendor/github.com/docker/docker/client/interface_experimental.go @@ -0,0 +1,18 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + + "github.com/docker/docker/api/types" +) + +type apiClientExperimental interface { + CheckpointAPIClient +} + +// CheckpointAPIClient defines API client methods for the checkpoints +type CheckpointAPIClient interface { + CheckpointCreate(ctx context.Context, container string, options types.CheckpointCreateOptions) error + CheckpointDelete(ctx context.Context, container string, options types.CheckpointDeleteOptions) error + CheckpointList(ctx context.Context, container string, options types.CheckpointListOptions) ([]types.Checkpoint, error) +} diff --git a/vendor/github.com/docker/docker/client/interface_stable.go b/vendor/github.com/docker/docker/client/interface_stable.go new file mode 100644 index 0000000000..5502cd7426 --- /dev/null +++ b/vendor/github.com/docker/docker/client/interface_stable.go @@ -0,0 +1,10 @@ +package client // import "github.com/docker/docker/client" + +// APIClient is an interface that clients that talk with a docker server must implement. +type APIClient interface { + CommonAPIClient + apiClientExperimental +} + +// Ensure that Client always implements APIClient. +var _ APIClient = &Client{} diff --git a/vendor/github.com/docker/docker/client/login.go b/vendor/github.com/docker/docker/client/login.go new file mode 100644 index 0000000000..f058520638 --- /dev/null +++ b/vendor/github.com/docker/docker/client/login.go @@ -0,0 +1,25 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "encoding/json" + "net/url" + + "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/registry" +) + +// RegistryLogin authenticates the docker server with a given docker registry. +// It returns unauthorizedError when the authentication fails. +func (cli *Client) RegistryLogin(ctx context.Context, auth types.AuthConfig) (registry.AuthenticateOKBody, error) { + resp, err := cli.post(ctx, "/auth", url.Values{}, auth, nil) + defer ensureReaderClosed(resp) + + if err != nil { + return registry.AuthenticateOKBody{}, err + } + + var response registry.AuthenticateOKBody + err = json.NewDecoder(resp.body).Decode(&response) + return response, err +} diff --git a/vendor/github.com/docker/docker/client/network_connect.go b/vendor/github.com/docker/docker/client/network_connect.go new file mode 100644 index 0000000000..5718946134 --- /dev/null +++ b/vendor/github.com/docker/docker/client/network_connect.go @@ -0,0 +1,19 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + + "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/network" +) + +// NetworkConnect connects a container to an existent network in the docker host. +func (cli *Client) NetworkConnect(ctx context.Context, networkID, containerID string, config *network.EndpointSettings) error { + nc := types.NetworkConnect{ + Container: containerID, + EndpointConfig: config, + } + resp, err := cli.post(ctx, "/networks/"+networkID+"/connect", nil, nc, nil) + ensureReaderClosed(resp) + return err +} diff --git a/vendor/github.com/docker/docker/client/network_create.go b/vendor/github.com/docker/docker/client/network_create.go new file mode 100644 index 0000000000..278d9383a8 --- /dev/null +++ b/vendor/github.com/docker/docker/client/network_create.go @@ -0,0 +1,25 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "encoding/json" + + "github.com/docker/docker/api/types" +) + +// NetworkCreate creates a new network in the docker host. +func (cli *Client) NetworkCreate(ctx context.Context, name string, options types.NetworkCreate) (types.NetworkCreateResponse, error) { + networkCreateRequest := types.NetworkCreateRequest{ + NetworkCreate: options, + Name: name, + } + var response types.NetworkCreateResponse + serverResp, err := cli.post(ctx, "/networks/create", nil, networkCreateRequest, nil) + defer ensureReaderClosed(serverResp) + if err != nil { + return response, err + } + + err = json.NewDecoder(serverResp.body).Decode(&response) + return response, err +} diff --git a/vendor/github.com/docker/docker/client/network_disconnect.go b/vendor/github.com/docker/docker/client/network_disconnect.go new file mode 100644 index 0000000000..dd15676656 --- /dev/null +++ b/vendor/github.com/docker/docker/client/network_disconnect.go @@ -0,0 +1,15 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + + "github.com/docker/docker/api/types" +) + +// NetworkDisconnect disconnects a container from an existent network in the docker host. +func (cli *Client) NetworkDisconnect(ctx context.Context, networkID, containerID string, force bool) error { + nd := types.NetworkDisconnect{Container: containerID, Force: force} + resp, err := cli.post(ctx, "/networks/"+networkID+"/disconnect", nil, nd, nil) + ensureReaderClosed(resp) + return err +} diff --git a/vendor/github.com/docker/docker/client/network_inspect.go b/vendor/github.com/docker/docker/client/network_inspect.go new file mode 100644 index 0000000000..0f90e2bb90 --- /dev/null +++ b/vendor/github.com/docker/docker/client/network_inspect.go @@ -0,0 +1,49 @@ +package client // import "github.com/docker/docker/client" + +import ( + "bytes" + "context" + "encoding/json" + "io" + "net/url" + + "github.com/docker/docker/api/types" +) + +// NetworkInspect returns the information for a specific network configured in the docker host. +func (cli *Client) NetworkInspect(ctx context.Context, networkID string, options types.NetworkInspectOptions) (types.NetworkResource, error) { + networkResource, _, err := cli.NetworkInspectWithRaw(ctx, networkID, options) + return networkResource, err +} + +// NetworkInspectWithRaw returns the information for a specific network configured in the docker host and its raw representation. +func (cli *Client) NetworkInspectWithRaw(ctx context.Context, networkID string, options types.NetworkInspectOptions) (types.NetworkResource, []byte, error) { + if networkID == "" { + return types.NetworkResource{}, nil, objectNotFoundError{object: "network", id: networkID} + } + var ( + networkResource types.NetworkResource + resp serverResponse + err error + ) + query := url.Values{} + if options.Verbose { + query.Set("verbose", "true") + } + if options.Scope != "" { + query.Set("scope", options.Scope) + } + resp, err = cli.get(ctx, "/networks/"+networkID, query, nil) + defer ensureReaderClosed(resp) + if err != nil { + return networkResource, nil, err + } + + body, err := io.ReadAll(resp.body) + if err != nil { + return networkResource, nil, err + } + rdr := bytes.NewReader(body) + err = json.NewDecoder(rdr).Decode(&networkResource) + return networkResource, body, err +} diff --git a/vendor/github.com/docker/docker/client/network_list.go b/vendor/github.com/docker/docker/client/network_list.go new file mode 100644 index 0000000000..ed2acb5571 --- /dev/null +++ b/vendor/github.com/docker/docker/client/network_list.go @@ -0,0 +1,32 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "encoding/json" + "net/url" + + "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/filters" +) + +// NetworkList returns the list of networks configured in the docker host. +func (cli *Client) NetworkList(ctx context.Context, options types.NetworkListOptions) ([]types.NetworkResource, error) { + query := url.Values{} + if options.Filters.Len() > 0 { + //nolint:staticcheck // ignore SA1019 for old code + filterJSON, err := filters.ToParamWithVersion(cli.version, options.Filters) + if err != nil { + return nil, err + } + + query.Set("filters", filterJSON) + } + var networkResources []types.NetworkResource + resp, err := cli.get(ctx, "/networks", query, nil) + defer ensureReaderClosed(resp) + if err != nil { + return networkResources, err + } + err = json.NewDecoder(resp.body).Decode(&networkResources) + return networkResources, err +} diff --git a/vendor/github.com/docker/docker/client/network_prune.go b/vendor/github.com/docker/docker/client/network_prune.go new file mode 100644 index 0000000000..cebb188219 --- /dev/null +++ b/vendor/github.com/docker/docker/client/network_prune.go @@ -0,0 +1,36 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "encoding/json" + "fmt" + + "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/filters" +) + +// NetworksPrune requests the daemon to delete unused networks +func (cli *Client) NetworksPrune(ctx context.Context, pruneFilters filters.Args) (types.NetworksPruneReport, error) { + var report types.NetworksPruneReport + + if err := cli.NewVersionError("1.25", "network prune"); err != nil { + return report, err + } + + query, err := getFiltersQuery(pruneFilters) + if err != nil { + return report, err + } + + serverResp, err := cli.post(ctx, "/networks/prune", query, nil, nil) + defer ensureReaderClosed(serverResp) + if err != nil { + return report, err + } + + if err := json.NewDecoder(serverResp.body).Decode(&report); err != nil { + return report, fmt.Errorf("Error retrieving network prune report: %v", err) + } + + return report, nil +} diff --git a/vendor/github.com/docker/docker/client/network_remove.go b/vendor/github.com/docker/docker/client/network_remove.go new file mode 100644 index 0000000000..9d6c6cef07 --- /dev/null +++ b/vendor/github.com/docker/docker/client/network_remove.go @@ -0,0 +1,10 @@ +package client // import "github.com/docker/docker/client" + +import "context" + +// NetworkRemove removes an existent network from the docker host. +func (cli *Client) NetworkRemove(ctx context.Context, networkID string) error { + resp, err := cli.delete(ctx, "/networks/"+networkID, nil, nil) + defer ensureReaderClosed(resp) + return err +} diff --git a/vendor/github.com/docker/docker/client/node_inspect.go b/vendor/github.com/docker/docker/client/node_inspect.go new file mode 100644 index 0000000000..95ab9b1be0 --- /dev/null +++ b/vendor/github.com/docker/docker/client/node_inspect.go @@ -0,0 +1,32 @@ +package client // import "github.com/docker/docker/client" + +import ( + "bytes" + "context" + "encoding/json" + "io" + + "github.com/docker/docker/api/types/swarm" +) + +// NodeInspectWithRaw returns the node information. +func (cli *Client) NodeInspectWithRaw(ctx context.Context, nodeID string) (swarm.Node, []byte, error) { + if nodeID == "" { + return swarm.Node{}, nil, objectNotFoundError{object: "node", id: nodeID} + } + serverResp, err := cli.get(ctx, "/nodes/"+nodeID, nil, nil) + defer ensureReaderClosed(serverResp) + if err != nil { + return swarm.Node{}, nil, err + } + + body, err := io.ReadAll(serverResp.body) + if err != nil { + return swarm.Node{}, nil, err + } + + var response swarm.Node + rdr := bytes.NewReader(body) + err = json.NewDecoder(rdr).Decode(&response) + return response, body, err +} diff --git a/vendor/github.com/docker/docker/client/node_list.go b/vendor/github.com/docker/docker/client/node_list.go new file mode 100644 index 0000000000..c212906bc7 --- /dev/null +++ b/vendor/github.com/docker/docker/client/node_list.go @@ -0,0 +1,36 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "encoding/json" + "net/url" + + "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/filters" + "github.com/docker/docker/api/types/swarm" +) + +// NodeList returns the list of nodes. +func (cli *Client) NodeList(ctx context.Context, options types.NodeListOptions) ([]swarm.Node, error) { + query := url.Values{} + + if options.Filters.Len() > 0 { + filterJSON, err := filters.ToJSON(options.Filters) + + if err != nil { + return nil, err + } + + query.Set("filters", filterJSON) + } + + resp, err := cli.get(ctx, "/nodes", query, nil) + defer ensureReaderClosed(resp) + if err != nil { + return nil, err + } + + var nodes []swarm.Node + err = json.NewDecoder(resp.body).Decode(&nodes) + return nodes, err +} diff --git a/vendor/github.com/docker/docker/client/node_remove.go b/vendor/github.com/docker/docker/client/node_remove.go new file mode 100644 index 0000000000..e44436debc --- /dev/null +++ b/vendor/github.com/docker/docker/client/node_remove.go @@ -0,0 +1,20 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "net/url" + + "github.com/docker/docker/api/types" +) + +// NodeRemove removes a Node. +func (cli *Client) NodeRemove(ctx context.Context, nodeID string, options types.NodeRemoveOptions) error { + query := url.Values{} + if options.Force { + query.Set("force", "1") + } + + resp, err := cli.delete(ctx, "/nodes/"+nodeID, query, nil) + defer ensureReaderClosed(resp) + return err +} diff --git a/vendor/github.com/docker/docker/client/node_update.go b/vendor/github.com/docker/docker/client/node_update.go new file mode 100644 index 0000000000..0d0fc3b788 --- /dev/null +++ b/vendor/github.com/docker/docker/client/node_update.go @@ -0,0 +1,17 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "net/url" + + "github.com/docker/docker/api/types/swarm" +) + +// NodeUpdate updates a Node. +func (cli *Client) NodeUpdate(ctx context.Context, nodeID string, version swarm.Version, node swarm.NodeSpec) error { + query := url.Values{} + query.Set("version", version.String()) + resp, err := cli.post(ctx, "/nodes/"+nodeID+"/update", query, node, nil) + ensureReaderClosed(resp) + return err +} diff --git a/vendor/github.com/docker/docker/client/options.go b/vendor/github.com/docker/docker/client/options.go new file mode 100644 index 0000000000..099ad41846 --- /dev/null +++ b/vendor/github.com/docker/docker/client/options.go @@ -0,0 +1,210 @@ +package client + +import ( + "context" + "net" + "net/http" + "os" + "path/filepath" + "time" + + "github.com/docker/go-connections/sockets" + "github.com/docker/go-connections/tlsconfig" + "github.com/pkg/errors" +) + +// Opt is a configuration option to initialize a client +type Opt func(*Client) error + +// FromEnv configures the client with values from environment variables. +// +// FromEnv uses the following environment variables: +// +// DOCKER_HOST (EnvOverrideHost) to set the URL to the docker server. +// +// DOCKER_API_VERSION (EnvOverrideAPIVersion) to set the version of the API to +// use, leave empty for latest. +// +// DOCKER_CERT_PATH (EnvOverrideCertPath) to specify the directory from which to +// load the TLS certificates (ca.pem, cert.pem, key.pem). +// +// DOCKER_TLS_VERIFY (EnvTLSVerify) to enable or disable TLS verification (off by +// default). +func FromEnv(c *Client) error { + ops := []Opt{ + WithTLSClientConfigFromEnv(), + WithHostFromEnv(), + WithVersionFromEnv(), + } + for _, op := range ops { + if err := op(c); err != nil { + return err + } + } + return nil +} + +// WithDialContext applies the dialer to the client transport. This can be +// used to set the Timeout and KeepAlive settings of the client. +func WithDialContext(dialContext func(ctx context.Context, network, addr string) (net.Conn, error)) Opt { + return func(c *Client) error { + if transport, ok := c.client.Transport.(*http.Transport); ok { + transport.DialContext = dialContext + return nil + } + return errors.Errorf("cannot apply dialer to transport: %T", c.client.Transport) + } +} + +// WithHost overrides the client host with the specified one. +func WithHost(host string) Opt { + return func(c *Client) error { + hostURL, err := ParseHostURL(host) + if err != nil { + return err + } + c.host = host + c.proto = hostURL.Scheme + c.addr = hostURL.Host + c.basePath = hostURL.Path + if transport, ok := c.client.Transport.(*http.Transport); ok { + return sockets.ConfigureTransport(transport, c.proto, c.addr) + } + return errors.Errorf("cannot apply host to transport: %T", c.client.Transport) + } +} + +// WithHostFromEnv overrides the client host with the host specified in the +// DOCKER_HOST (EnvOverrideHost) environment variable. If DOCKER_HOST is not set, +// or set to an empty value, the host is not modified. +func WithHostFromEnv() Opt { + return func(c *Client) error { + if host := os.Getenv(EnvOverrideHost); host != "" { + return WithHost(host)(c) + } + return nil + } +} + +// WithHTTPClient overrides the client http client with the specified one +func WithHTTPClient(client *http.Client) Opt { + return func(c *Client) error { + if client != nil { + c.client = client + } + return nil + } +} + +// WithTimeout configures the time limit for requests made by the HTTP client +func WithTimeout(timeout time.Duration) Opt { + return func(c *Client) error { + c.client.Timeout = timeout + return nil + } +} + +// WithHTTPHeaders overrides the client default http headers +func WithHTTPHeaders(headers map[string]string) Opt { + return func(c *Client) error { + c.customHTTPHeaders = headers + return nil + } +} + +// WithScheme overrides the client scheme with the specified one +func WithScheme(scheme string) Opt { + return func(c *Client) error { + c.scheme = scheme + return nil + } +} + +// WithTLSClientConfig applies a tls config to the client transport. +func WithTLSClientConfig(cacertPath, certPath, keyPath string) Opt { + return func(c *Client) error { + opts := tlsconfig.Options{ + CAFile: cacertPath, + CertFile: certPath, + KeyFile: keyPath, + ExclusiveRootPools: true, + } + config, err := tlsconfig.Client(opts) + if err != nil { + return errors.Wrap(err, "failed to create tls config") + } + if transport, ok := c.client.Transport.(*http.Transport); ok { + transport.TLSClientConfig = config + return nil + } + return errors.Errorf("cannot apply tls config to transport: %T", c.client.Transport) + } +} + +// WithTLSClientConfigFromEnv configures the client's TLS settings with the +// settings in the DOCKER_CERT_PATH and DOCKER_TLS_VERIFY environment variables. +// If DOCKER_CERT_PATH is not set or empty, TLS configuration is not modified. +// +// WithTLSClientConfigFromEnv uses the following environment variables: +// +// DOCKER_CERT_PATH (EnvOverrideCertPath) to specify the directory from which to +// load the TLS certificates (ca.pem, cert.pem, key.pem). +// +// DOCKER_TLS_VERIFY (EnvTLSVerify) to enable or disable TLS verification (off by +// default). +func WithTLSClientConfigFromEnv() Opt { + return func(c *Client) error { + dockerCertPath := os.Getenv(EnvOverrideCertPath) + if dockerCertPath == "" { + return nil + } + options := tlsconfig.Options{ + CAFile: filepath.Join(dockerCertPath, "ca.pem"), + CertFile: filepath.Join(dockerCertPath, "cert.pem"), + KeyFile: filepath.Join(dockerCertPath, "key.pem"), + InsecureSkipVerify: os.Getenv(EnvTLSVerify) == "", + } + tlsc, err := tlsconfig.Client(options) + if err != nil { + return err + } + + c.client = &http.Client{ + Transport: &http.Transport{TLSClientConfig: tlsc}, + CheckRedirect: CheckRedirect, + } + return nil + } +} + +// WithVersion overrides the client version with the specified one. If an empty +// version is specified, the value will be ignored to allow version negotiation. +func WithVersion(version string) Opt { + return func(c *Client) error { + if version != "" { + c.version = version + c.manualOverride = true + } + return nil + } +} + +// WithVersionFromEnv overrides the client version with the version specified in +// the DOCKER_API_VERSION environment variable. If DOCKER_API_VERSION is not set, +// the version is not modified. +func WithVersionFromEnv() Opt { + return func(c *Client) error { + return WithVersion(os.Getenv(EnvOverrideAPIVersion))(c) + } +} + +// WithAPIVersionNegotiation enables automatic API version negotiation for the client. +// With this option enabled, the client automatically negotiates the API version +// to use when making requests. API version negotiation is performed on the first +// request; subsequent requests will not re-negotiate. +func WithAPIVersionNegotiation() Opt { + return func(c *Client) error { + c.negotiateVersion = true + return nil + } +} diff --git a/vendor/github.com/docker/docker/client/ping.go b/vendor/github.com/docker/docker/client/ping.go new file mode 100644 index 0000000000..27e8695cb5 --- /dev/null +++ b/vendor/github.com/docker/docker/client/ping.go @@ -0,0 +1,75 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "net/http" + "path" + "strings" + + "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/swarm" + "github.com/docker/docker/errdefs" +) + +// Ping pings the server and returns the value of the "Docker-Experimental", +// "Builder-Version", "OS-Type" & "API-Version" headers. It attempts to use +// a HEAD request on the endpoint, but falls back to GET if HEAD is not supported +// by the daemon. +func (cli *Client) Ping(ctx context.Context) (types.Ping, error) { + var ping types.Ping + + // Using cli.buildRequest() + cli.doRequest() instead of cli.sendRequest() + // because ping requests are used during API version negotiation, so we want + // to hit the non-versioned /_ping endpoint, not /v1.xx/_ping + req, err := cli.buildRequest(http.MethodHead, path.Join(cli.basePath, "/_ping"), nil, nil) + if err != nil { + return ping, err + } + serverResp, err := cli.doRequest(ctx, req) + if err == nil { + defer ensureReaderClosed(serverResp) + switch serverResp.statusCode { + case http.StatusOK, http.StatusInternalServerError: + // Server handled the request, so parse the response + return parsePingResponse(cli, serverResp) + } + } else if IsErrConnectionFailed(err) { + return ping, err + } + + req, err = cli.buildRequest(http.MethodGet, path.Join(cli.basePath, "/_ping"), nil, nil) + if err != nil { + return ping, err + } + serverResp, err = cli.doRequest(ctx, req) + defer ensureReaderClosed(serverResp) + if err != nil { + return ping, err + } + return parsePingResponse(cli, serverResp) +} + +func parsePingResponse(cli *Client, resp serverResponse) (types.Ping, error) { + var ping types.Ping + if resp.header == nil { + err := cli.checkResponseErr(resp) + return ping, errdefs.FromStatusCode(err, resp.statusCode) + } + ping.APIVersion = resp.header.Get("API-Version") + ping.OSType = resp.header.Get("OSType") + if resp.header.Get("Docker-Experimental") == "true" { + ping.Experimental = true + } + if bv := resp.header.Get("Builder-Version"); bv != "" { + ping.BuilderVersion = types.BuilderVersion(bv) + } + if si := resp.header.Get("Swarm"); si != "" { + parts := strings.SplitN(si, "/", 2) + ping.SwarmStatus = &swarm.Status{ + NodeState: swarm.LocalNodeState(parts[0]), + ControlAvailable: len(parts) == 2 && parts[1] == "manager", + } + } + err := cli.checkResponseErr(resp) + return ping, errdefs.FromStatusCode(err, resp.statusCode) +} diff --git a/vendor/github.com/docker/docker/client/plugin_create.go b/vendor/github.com/docker/docker/client/plugin_create.go new file mode 100644 index 0000000000..b95dbaf686 --- /dev/null +++ b/vendor/github.com/docker/docker/client/plugin_create.go @@ -0,0 +1,23 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "io" + "net/http" + "net/url" + + "github.com/docker/docker/api/types" +) + +// PluginCreate creates a plugin +func (cli *Client) PluginCreate(ctx context.Context, createContext io.Reader, createOptions types.PluginCreateOptions) error { + headers := http.Header(make(map[string][]string)) + headers.Set("Content-Type", "application/x-tar") + + query := url.Values{} + query.Set("name", createOptions.RepoName) + + resp, err := cli.postRaw(ctx, "/plugins/create", query, createContext, headers) + ensureReaderClosed(resp) + return err +} diff --git a/vendor/github.com/docker/docker/client/plugin_disable.go b/vendor/github.com/docker/docker/client/plugin_disable.go new file mode 100644 index 0000000000..01f6574f95 --- /dev/null +++ b/vendor/github.com/docker/docker/client/plugin_disable.go @@ -0,0 +1,19 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "net/url" + + "github.com/docker/docker/api/types" +) + +// PluginDisable disables a plugin +func (cli *Client) PluginDisable(ctx context.Context, name string, options types.PluginDisableOptions) error { + query := url.Values{} + if options.Force { + query.Set("force", "1") + } + resp, err := cli.post(ctx, "/plugins/"+name+"/disable", query, nil, nil) + ensureReaderClosed(resp) + return err +} diff --git a/vendor/github.com/docker/docker/client/plugin_enable.go b/vendor/github.com/docker/docker/client/plugin_enable.go new file mode 100644 index 0000000000..736da48bd1 --- /dev/null +++ b/vendor/github.com/docker/docker/client/plugin_enable.go @@ -0,0 +1,19 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "net/url" + "strconv" + + "github.com/docker/docker/api/types" +) + +// PluginEnable enables a plugin +func (cli *Client) PluginEnable(ctx context.Context, name string, options types.PluginEnableOptions) error { + query := url.Values{} + query.Set("timeout", strconv.Itoa(options.Timeout)) + + resp, err := cli.post(ctx, "/plugins/"+name+"/enable", query, nil, nil) + ensureReaderClosed(resp) + return err +} diff --git a/vendor/github.com/docker/docker/client/plugin_inspect.go b/vendor/github.com/docker/docker/client/plugin_inspect.go new file mode 100644 index 0000000000..f09e460660 --- /dev/null +++ b/vendor/github.com/docker/docker/client/plugin_inspect.go @@ -0,0 +1,31 @@ +package client // import "github.com/docker/docker/client" + +import ( + "bytes" + "context" + "encoding/json" + "io" + + "github.com/docker/docker/api/types" +) + +// PluginInspectWithRaw inspects an existing plugin +func (cli *Client) PluginInspectWithRaw(ctx context.Context, name string) (*types.Plugin, []byte, error) { + if name == "" { + return nil, nil, objectNotFoundError{object: "plugin", id: name} + } + resp, err := cli.get(ctx, "/plugins/"+name+"/json", nil, nil) + defer ensureReaderClosed(resp) + if err != nil { + return nil, nil, err + } + + body, err := io.ReadAll(resp.body) + if err != nil { + return nil, nil, err + } + var p types.Plugin + rdr := bytes.NewReader(body) + err = json.NewDecoder(rdr).Decode(&p) + return &p, body, err +} diff --git a/vendor/github.com/docker/docker/client/plugin_install.go b/vendor/github.com/docker/docker/client/plugin_install.go new file mode 100644 index 0000000000..012afe61ca --- /dev/null +++ b/vendor/github.com/docker/docker/client/plugin_install.go @@ -0,0 +1,113 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "encoding/json" + "io" + "net/url" + + "github.com/docker/distribution/reference" + "github.com/docker/docker/api/types" + "github.com/docker/docker/errdefs" + "github.com/pkg/errors" +) + +// PluginInstall installs a plugin +func (cli *Client) PluginInstall(ctx context.Context, name string, options types.PluginInstallOptions) (rc io.ReadCloser, err error) { + query := url.Values{} + if _, err := reference.ParseNormalizedNamed(options.RemoteRef); err != nil { + return nil, errors.Wrap(err, "invalid remote reference") + } + query.Set("remote", options.RemoteRef) + + privileges, err := cli.checkPluginPermissions(ctx, query, options) + if err != nil { + return nil, err + } + + // set name for plugin pull, if empty should default to remote reference + query.Set("name", name) + + resp, err := cli.tryPluginPull(ctx, query, privileges, options.RegistryAuth) + if err != nil { + return nil, err + } + + name = resp.header.Get("Docker-Plugin-Name") + + pr, pw := io.Pipe() + go func() { // todo: the client should probably be designed more around the actual api + _, err := io.Copy(pw, resp.body) + if err != nil { + pw.CloseWithError(err) + return + } + defer func() { + if err != nil { + delResp, _ := cli.delete(ctx, "/plugins/"+name, nil, nil) + ensureReaderClosed(delResp) + } + }() + if len(options.Args) > 0 { + if err := cli.PluginSet(ctx, name, options.Args); err != nil { + pw.CloseWithError(err) + return + } + } + + if options.Disabled { + pw.Close() + return + } + + enableErr := cli.PluginEnable(ctx, name, types.PluginEnableOptions{Timeout: 0}) + pw.CloseWithError(enableErr) + }() + return pr, nil +} + +func (cli *Client) tryPluginPrivileges(ctx context.Context, query url.Values, registryAuth string) (serverResponse, error) { + headers := map[string][]string{"X-Registry-Auth": {registryAuth}} + return cli.get(ctx, "/plugins/privileges", query, headers) +} + +func (cli *Client) tryPluginPull(ctx context.Context, query url.Values, privileges types.PluginPrivileges, registryAuth string) (serverResponse, error) { + headers := map[string][]string{"X-Registry-Auth": {registryAuth}} + return cli.post(ctx, "/plugins/pull", query, privileges, headers) +} + +func (cli *Client) checkPluginPermissions(ctx context.Context, query url.Values, options types.PluginInstallOptions) (types.PluginPrivileges, error) { + resp, err := cli.tryPluginPrivileges(ctx, query, options.RegistryAuth) + if errdefs.IsUnauthorized(err) && options.PrivilegeFunc != nil { + // todo: do inspect before to check existing name before checking privileges + newAuthHeader, privilegeErr := options.PrivilegeFunc() + if privilegeErr != nil { + ensureReaderClosed(resp) + return nil, privilegeErr + } + options.RegistryAuth = newAuthHeader + resp, err = cli.tryPluginPrivileges(ctx, query, options.RegistryAuth) + } + if err != nil { + ensureReaderClosed(resp) + return nil, err + } + + var privileges types.PluginPrivileges + if err := json.NewDecoder(resp.body).Decode(&privileges); err != nil { + ensureReaderClosed(resp) + return nil, err + } + ensureReaderClosed(resp) + + if !options.AcceptAllPermissions && options.AcceptPermissionsFunc != nil && len(privileges) > 0 { + accept, err := options.AcceptPermissionsFunc(privileges) + if err != nil { + return nil, err + } + if !accept { + return nil, pluginPermissionDenied{options.RemoteRef} + } + } + return privileges, nil +} diff --git a/vendor/github.com/docker/docker/client/plugin_list.go b/vendor/github.com/docker/docker/client/plugin_list.go new file mode 100644 index 0000000000..2091a054d6 --- /dev/null +++ b/vendor/github.com/docker/docker/client/plugin_list.go @@ -0,0 +1,33 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "encoding/json" + "net/url" + + "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/filters" +) + +// PluginList returns the installed plugins +func (cli *Client) PluginList(ctx context.Context, filter filters.Args) (types.PluginsListResponse, error) { + var plugins types.PluginsListResponse + query := url.Values{} + + if filter.Len() > 0 { + //nolint:staticcheck // ignore SA1019 for old code + filterJSON, err := filters.ToParamWithVersion(cli.version, filter) + if err != nil { + return plugins, err + } + query.Set("filters", filterJSON) + } + resp, err := cli.get(ctx, "/plugins", query, nil) + defer ensureReaderClosed(resp) + if err != nil { + return plugins, err + } + + err = json.NewDecoder(resp.body).Decode(&plugins) + return plugins, err +} diff --git a/vendor/github.com/docker/docker/client/plugin_push.go b/vendor/github.com/docker/docker/client/plugin_push.go new file mode 100644 index 0000000000..d20bfe8447 --- /dev/null +++ b/vendor/github.com/docker/docker/client/plugin_push.go @@ -0,0 +1,16 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "io" +) + +// PluginPush pushes a plugin to a registry +func (cli *Client) PluginPush(ctx context.Context, name string, registryAuth string) (io.ReadCloser, error) { + headers := map[string][]string{"X-Registry-Auth": {registryAuth}} + resp, err := cli.post(ctx, "/plugins/"+name+"/push", nil, nil, headers) + if err != nil { + return nil, err + } + return resp.body, nil +} diff --git a/vendor/github.com/docker/docker/client/plugin_remove.go b/vendor/github.com/docker/docker/client/plugin_remove.go new file mode 100644 index 0000000000..4cd66958c3 --- /dev/null +++ b/vendor/github.com/docker/docker/client/plugin_remove.go @@ -0,0 +1,20 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "net/url" + + "github.com/docker/docker/api/types" +) + +// PluginRemove removes a plugin +func (cli *Client) PluginRemove(ctx context.Context, name string, options types.PluginRemoveOptions) error { + query := url.Values{} + if options.Force { + query.Set("force", "1") + } + + resp, err := cli.delete(ctx, "/plugins/"+name, query, nil) + defer ensureReaderClosed(resp) + return err +} diff --git a/vendor/github.com/docker/docker/client/plugin_set.go b/vendor/github.com/docker/docker/client/plugin_set.go new file mode 100644 index 0000000000..dcf5752ca2 --- /dev/null +++ b/vendor/github.com/docker/docker/client/plugin_set.go @@ -0,0 +1,12 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" +) + +// PluginSet modifies settings for an existing plugin +func (cli *Client) PluginSet(ctx context.Context, name string, args []string) error { + resp, err := cli.post(ctx, "/plugins/"+name+"/set", nil, args, nil) + ensureReaderClosed(resp) + return err +} diff --git a/vendor/github.com/docker/docker/client/plugin_upgrade.go b/vendor/github.com/docker/docker/client/plugin_upgrade.go new file mode 100644 index 0000000000..115cea945b --- /dev/null +++ b/vendor/github.com/docker/docker/client/plugin_upgrade.go @@ -0,0 +1,39 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "io" + "net/url" + + "github.com/docker/distribution/reference" + "github.com/docker/docker/api/types" + "github.com/pkg/errors" +) + +// PluginUpgrade upgrades a plugin +func (cli *Client) PluginUpgrade(ctx context.Context, name string, options types.PluginInstallOptions) (rc io.ReadCloser, err error) { + if err := cli.NewVersionError("1.26", "plugin upgrade"); err != nil { + return nil, err + } + query := url.Values{} + if _, err := reference.ParseNormalizedNamed(options.RemoteRef); err != nil { + return nil, errors.Wrap(err, "invalid remote reference") + } + query.Set("remote", options.RemoteRef) + + privileges, err := cli.checkPluginPermissions(ctx, query, options) + if err != nil { + return nil, err + } + + resp, err := cli.tryPluginUpgrade(ctx, query, privileges, name, options.RegistryAuth) + if err != nil { + return nil, err + } + return resp.body, nil +} + +func (cli *Client) tryPluginUpgrade(ctx context.Context, query url.Values, privileges types.PluginPrivileges, name, registryAuth string) (serverResponse, error) { + headers := map[string][]string{"X-Registry-Auth": {registryAuth}} + return cli.post(ctx, "/plugins/"+name+"/upgrade", query, privileges, headers) +} diff --git a/vendor/github.com/docker/docker/client/request.go b/vendor/github.com/docker/docker/client/request.go new file mode 100644 index 0000000000..c799095c12 --- /dev/null +++ b/vendor/github.com/docker/docker/client/request.go @@ -0,0 +1,277 @@ +package client // import "github.com/docker/docker/client" + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "io" + "net" + "net/http" + "net/url" + "os" + "strings" + + "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/versions" + "github.com/docker/docker/errdefs" + "github.com/pkg/errors" +) + +// serverResponse is a wrapper for http API responses. +type serverResponse struct { + body io.ReadCloser + header http.Header + statusCode int + reqURL *url.URL +} + +// head sends an http request to the docker API using the method HEAD. +func (cli *Client) head(ctx context.Context, path string, query url.Values, headers map[string][]string) (serverResponse, error) { + return cli.sendRequest(ctx, http.MethodHead, path, query, nil, headers) +} + +// get sends an http request to the docker API using the method GET with a specific Go context. +func (cli *Client) get(ctx context.Context, path string, query url.Values, headers map[string][]string) (serverResponse, error) { + return cli.sendRequest(ctx, http.MethodGet, path, query, nil, headers) +} + +// post sends an http request to the docker API using the method POST with a specific Go context. +func (cli *Client) post(ctx context.Context, path string, query url.Values, obj interface{}, headers map[string][]string) (serverResponse, error) { + body, headers, err := encodeBody(obj, headers) + if err != nil { + return serverResponse{}, err + } + return cli.sendRequest(ctx, http.MethodPost, path, query, body, headers) +} + +func (cli *Client) postRaw(ctx context.Context, path string, query url.Values, body io.Reader, headers map[string][]string) (serverResponse, error) { + return cli.sendRequest(ctx, http.MethodPost, path, query, body, headers) +} + +func (cli *Client) put(ctx context.Context, path string, query url.Values, obj interface{}, headers map[string][]string) (serverResponse, error) { + body, headers, err := encodeBody(obj, headers) + if err != nil { + return serverResponse{}, err + } + return cli.sendRequest(ctx, http.MethodPut, path, query, body, headers) +} + +// putRaw sends an http request to the docker API using the method PUT. +func (cli *Client) putRaw(ctx context.Context, path string, query url.Values, body io.Reader, headers map[string][]string) (serverResponse, error) { + return cli.sendRequest(ctx, http.MethodPut, path, query, body, headers) +} + +// delete sends an http request to the docker API using the method DELETE. +func (cli *Client) delete(ctx context.Context, path string, query url.Values, headers map[string][]string) (serverResponse, error) { + return cli.sendRequest(ctx, http.MethodDelete, path, query, nil, headers) +} + +type headers map[string][]string + +func encodeBody(obj interface{}, headers headers) (io.Reader, headers, error) { + if obj == nil { + return nil, headers, nil + } + + body, err := encodeData(obj) + if err != nil { + return nil, headers, err + } + if headers == nil { + headers = make(map[string][]string) + } + headers["Content-Type"] = []string{"application/json"} + return body, headers, nil +} + +func (cli *Client) buildRequest(method, path string, body io.Reader, headers headers) (*http.Request, error) { + expectedPayload := (method == http.MethodPost || method == http.MethodPut) + if expectedPayload && body == nil { + body = bytes.NewReader([]byte{}) + } + + req, err := http.NewRequest(method, path, body) + if err != nil { + return nil, err + } + req = cli.addHeaders(req, headers) + + if cli.proto == "unix" || cli.proto == "npipe" { + // For local communications, it doesn't matter what the host is. We just + // need a valid and meaningful host name. (See #189) + req.Host = "docker" + } + + req.URL.Host = cli.addr + req.URL.Scheme = cli.scheme + + if expectedPayload && req.Header.Get("Content-Type") == "" { + req.Header.Set("Content-Type", "text/plain") + } + return req, nil +} + +func (cli *Client) sendRequest(ctx context.Context, method, path string, query url.Values, body io.Reader, headers headers) (serverResponse, error) { + req, err := cli.buildRequest(method, cli.getAPIPath(ctx, path, query), body, headers) + if err != nil { + return serverResponse{}, err + } + + resp, err := cli.doRequest(ctx, req) + switch { + case errors.Is(err, context.Canceled): + return serverResponse{}, errdefs.Cancelled(err) + case errors.Is(err, context.DeadlineExceeded): + return serverResponse{}, errdefs.Deadline(err) + case err == nil: + err = cli.checkResponseErr(resp) + } + return resp, errdefs.FromStatusCode(err, resp.statusCode) +} + +func (cli *Client) doRequest(ctx context.Context, req *http.Request) (serverResponse, error) { + serverResp := serverResponse{statusCode: -1, reqURL: req.URL} + + req = req.WithContext(ctx) + resp, err := cli.client.Do(req) + if err != nil { + if cli.scheme != "https" && strings.Contains(err.Error(), "malformed HTTP response") { + return serverResp, fmt.Errorf("%v.\n* Are you trying to connect to a TLS-enabled daemon without TLS?", err) + } + + if cli.scheme == "https" && strings.Contains(err.Error(), "bad certificate") { + return serverResp, errors.Wrap(err, "the server probably has client authentication (--tlsverify) enabled; check your TLS client certification settings") + } + + // Don't decorate context sentinel errors; users may be comparing to + // them directly. + if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) { + return serverResp, err + } + + if nErr, ok := err.(*url.Error); ok { + if nErr, ok := nErr.Err.(*net.OpError); ok { + if os.IsPermission(nErr.Err) { + return serverResp, errors.Wrapf(err, "permission denied while trying to connect to the Docker daemon socket at %v", cli.host) + } + } + } + + if err, ok := err.(net.Error); ok { + if err.Timeout() { + return serverResp, ErrorConnectionFailed(cli.host) + } + if strings.Contains(err.Error(), "connection refused") || strings.Contains(err.Error(), "dial unix") { + return serverResp, ErrorConnectionFailed(cli.host) + } + } + + // Although there's not a strongly typed error for this in go-winio, + // lots of people are using the default configuration for the docker + // daemon on Windows where the daemon is listening on a named pipe + // `//./pipe/docker_engine, and the client must be running elevated. + // Give users a clue rather than the not-overly useful message + // such as `error during connect: Get http://%2F%2F.%2Fpipe%2Fdocker_engine/v1.26/info: + // open //./pipe/docker_engine: The system cannot find the file specified.`. + // Note we can't string compare "The system cannot find the file specified" as + // this is localised - for example in French the error would be + // `open //./pipe/docker_engine: Le fichier spécifié est introuvable.` + if strings.Contains(err.Error(), `open //./pipe/docker_engine`) { + // Checks if client is running with elevated privileges + if f, elevatedErr := os.Open("\\\\.\\PHYSICALDRIVE0"); elevatedErr == nil { + err = errors.Wrap(err, "in the default daemon configuration on Windows, the docker client must be run with elevated privileges to connect") + } else { + f.Close() + err = errors.Wrap(err, "this error may indicate that the docker daemon is not running") + } + } + + return serverResp, errors.Wrap(err, "error during connect") + } + + if resp != nil { + serverResp.statusCode = resp.StatusCode + serverResp.body = resp.Body + serverResp.header = resp.Header + } + return serverResp, nil +} + +func (cli *Client) checkResponseErr(serverResp serverResponse) error { + if serverResp.statusCode >= 200 && serverResp.statusCode < 400 { + return nil + } + + var body []byte + var err error + if serverResp.body != nil { + bodyMax := 1 * 1024 * 1024 // 1 MiB + bodyR := &io.LimitedReader{ + R: serverResp.body, + N: int64(bodyMax), + } + body, err = io.ReadAll(bodyR) + if err != nil { + return err + } + if bodyR.N == 0 { + return fmt.Errorf("request returned %s with a message (> %d bytes) for API route and version %s, check if the server supports the requested API version", http.StatusText(serverResp.statusCode), bodyMax, serverResp.reqURL) + } + } + if len(body) == 0 { + return fmt.Errorf("request returned %s for API route and version %s, check if the server supports the requested API version", http.StatusText(serverResp.statusCode), serverResp.reqURL) + } + + var ct string + if serverResp.header != nil { + ct = serverResp.header.Get("Content-Type") + } + + var errorMessage string + if (cli.version == "" || versions.GreaterThan(cli.version, "1.23")) && ct == "application/json" { + var errorResponse types.ErrorResponse + if err := json.Unmarshal(body, &errorResponse); err != nil { + return errors.Wrap(err, "Error reading JSON") + } + errorMessage = strings.TrimSpace(errorResponse.Message) + } else { + errorMessage = strings.TrimSpace(string(body)) + } + + return errors.Wrap(errors.New(errorMessage), "Error response from daemon") +} + +func (cli *Client) addHeaders(req *http.Request, headers headers) *http.Request { + // Add CLI Config's HTTP Headers BEFORE we set the Docker headers + // then the user can't change OUR headers + for k, v := range cli.customHTTPHeaders { + if versions.LessThan(cli.version, "1.25") && http.CanonicalHeaderKey(k) == "User-Agent" { + continue + } + req.Header.Set(k, v) + } + + for k, v := range headers { + req.Header[http.CanonicalHeaderKey(k)] = v + } + return req +} + +func encodeData(data interface{}) (*bytes.Buffer, error) { + params := bytes.NewBuffer(nil) + if data != nil { + if err := json.NewEncoder(params).Encode(data); err != nil { + return nil, err + } + } + return params, nil +} + +func ensureReaderClosed(response serverResponse) { + if response.body != nil { + // Drain up to 512 bytes and close the body to let the Transport reuse the connection + io.CopyN(io.Discard, response.body, 512) + response.body.Close() + } +} diff --git a/vendor/github.com/docker/docker/client/secret_create.go b/vendor/github.com/docker/docker/client/secret_create.go new file mode 100644 index 0000000000..c65d38a191 --- /dev/null +++ b/vendor/github.com/docker/docker/client/secret_create.go @@ -0,0 +1,25 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "encoding/json" + + "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/swarm" +) + +// SecretCreate creates a new secret. +func (cli *Client) SecretCreate(ctx context.Context, secret swarm.SecretSpec) (types.SecretCreateResponse, error) { + var response types.SecretCreateResponse + if err := cli.NewVersionError("1.25", "secret create"); err != nil { + return response, err + } + resp, err := cli.post(ctx, "/secrets/create", nil, secret, nil) + defer ensureReaderClosed(resp) + if err != nil { + return response, err + } + + err = json.NewDecoder(resp.body).Decode(&response) + return response, err +} diff --git a/vendor/github.com/docker/docker/client/secret_inspect.go b/vendor/github.com/docker/docker/client/secret_inspect.go new file mode 100644 index 0000000000..5906874b15 --- /dev/null +++ b/vendor/github.com/docker/docker/client/secret_inspect.go @@ -0,0 +1,36 @@ +package client // import "github.com/docker/docker/client" + +import ( + "bytes" + "context" + "encoding/json" + "io" + + "github.com/docker/docker/api/types/swarm" +) + +// SecretInspectWithRaw returns the secret information with raw data +func (cli *Client) SecretInspectWithRaw(ctx context.Context, id string) (swarm.Secret, []byte, error) { + if err := cli.NewVersionError("1.25", "secret inspect"); err != nil { + return swarm.Secret{}, nil, err + } + if id == "" { + return swarm.Secret{}, nil, objectNotFoundError{object: "secret", id: id} + } + resp, err := cli.get(ctx, "/secrets/"+id, nil, nil) + defer ensureReaderClosed(resp) + if err != nil { + return swarm.Secret{}, nil, err + } + + body, err := io.ReadAll(resp.body) + if err != nil { + return swarm.Secret{}, nil, err + } + + var secret swarm.Secret + rdr := bytes.NewReader(body) + err = json.NewDecoder(rdr).Decode(&secret) + + return secret, body, err +} diff --git a/vendor/github.com/docker/docker/client/secret_list.go b/vendor/github.com/docker/docker/client/secret_list.go new file mode 100644 index 0000000000..a0289c9f44 --- /dev/null +++ b/vendor/github.com/docker/docker/client/secret_list.go @@ -0,0 +1,38 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "encoding/json" + "net/url" + + "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/filters" + "github.com/docker/docker/api/types/swarm" +) + +// SecretList returns the list of secrets. +func (cli *Client) SecretList(ctx context.Context, options types.SecretListOptions) ([]swarm.Secret, error) { + if err := cli.NewVersionError("1.25", "secret list"); err != nil { + return nil, err + } + query := url.Values{} + + if options.Filters.Len() > 0 { + filterJSON, err := filters.ToJSON(options.Filters) + if err != nil { + return nil, err + } + + query.Set("filters", filterJSON) + } + + resp, err := cli.get(ctx, "/secrets", query, nil) + defer ensureReaderClosed(resp) + if err != nil { + return nil, err + } + + var secrets []swarm.Secret + err = json.NewDecoder(resp.body).Decode(&secrets) + return secrets, err +} diff --git a/vendor/github.com/docker/docker/client/secret_remove.go b/vendor/github.com/docker/docker/client/secret_remove.go new file mode 100644 index 0000000000..f47f68b6e0 --- /dev/null +++ b/vendor/github.com/docker/docker/client/secret_remove.go @@ -0,0 +1,13 @@ +package client // import "github.com/docker/docker/client" + +import "context" + +// SecretRemove removes a secret. +func (cli *Client) SecretRemove(ctx context.Context, id string) error { + if err := cli.NewVersionError("1.25", "secret remove"); err != nil { + return err + } + resp, err := cli.delete(ctx, "/secrets/"+id, nil, nil) + defer ensureReaderClosed(resp) + return err +} diff --git a/vendor/github.com/docker/docker/client/secret_update.go b/vendor/github.com/docker/docker/client/secret_update.go new file mode 100644 index 0000000000..2e939e8ced --- /dev/null +++ b/vendor/github.com/docker/docker/client/secret_update.go @@ -0,0 +1,20 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "net/url" + + "github.com/docker/docker/api/types/swarm" +) + +// SecretUpdate attempts to update a secret. +func (cli *Client) SecretUpdate(ctx context.Context, id string, version swarm.Version, secret swarm.SecretSpec) error { + if err := cli.NewVersionError("1.25", "secret update"); err != nil { + return err + } + query := url.Values{} + query.Set("version", version.String()) + resp, err := cli.post(ctx, "/secrets/"+id+"/update", query, secret, nil) + ensureReaderClosed(resp) + return err +} diff --git a/vendor/github.com/docker/docker/client/service_create.go b/vendor/github.com/docker/docker/client/service_create.go new file mode 100644 index 0000000000..23024d0f8f --- /dev/null +++ b/vendor/github.com/docker/docker/client/service_create.go @@ -0,0 +1,178 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "encoding/json" + "fmt" + "strings" + + "github.com/docker/distribution/reference" + "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/swarm" + "github.com/opencontainers/go-digest" + "github.com/pkg/errors" +) + +// ServiceCreate creates a new service. +func (cli *Client) ServiceCreate(ctx context.Context, service swarm.ServiceSpec, options types.ServiceCreateOptions) (types.ServiceCreateResponse, error) { + var response types.ServiceCreateResponse + headers := map[string][]string{ + "version": {cli.version}, + } + + if options.EncodedRegistryAuth != "" { + headers["X-Registry-Auth"] = []string{options.EncodedRegistryAuth} + } + + // Make sure containerSpec is not nil when no runtime is set or the runtime is set to container + if service.TaskTemplate.ContainerSpec == nil && (service.TaskTemplate.Runtime == "" || service.TaskTemplate.Runtime == swarm.RuntimeContainer) { + service.TaskTemplate.ContainerSpec = &swarm.ContainerSpec{} + } + + if err := validateServiceSpec(service); err != nil { + return response, err + } + + // ensure that the image is tagged + var resolveWarning string + switch { + case service.TaskTemplate.ContainerSpec != nil: + if taggedImg := imageWithTagString(service.TaskTemplate.ContainerSpec.Image); taggedImg != "" { + service.TaskTemplate.ContainerSpec.Image = taggedImg + } + if options.QueryRegistry { + resolveWarning = resolveContainerSpecImage(ctx, cli, &service.TaskTemplate, options.EncodedRegistryAuth) + } + case service.TaskTemplate.PluginSpec != nil: + if taggedImg := imageWithTagString(service.TaskTemplate.PluginSpec.Remote); taggedImg != "" { + service.TaskTemplate.PluginSpec.Remote = taggedImg + } + if options.QueryRegistry { + resolveWarning = resolvePluginSpecRemote(ctx, cli, &service.TaskTemplate, options.EncodedRegistryAuth) + } + } + + resp, err := cli.post(ctx, "/services/create", nil, service, headers) + defer ensureReaderClosed(resp) + if err != nil { + return response, err + } + + err = json.NewDecoder(resp.body).Decode(&response) + if resolveWarning != "" { + response.Warnings = append(response.Warnings, resolveWarning) + } + + return response, err +} + +func resolveContainerSpecImage(ctx context.Context, cli DistributionAPIClient, taskSpec *swarm.TaskSpec, encodedAuth string) string { + var warning string + if img, imgPlatforms, err := imageDigestAndPlatforms(ctx, cli, taskSpec.ContainerSpec.Image, encodedAuth); err != nil { + warning = digestWarning(taskSpec.ContainerSpec.Image) + } else { + taskSpec.ContainerSpec.Image = img + if len(imgPlatforms) > 0 { + if taskSpec.Placement == nil { + taskSpec.Placement = &swarm.Placement{} + } + taskSpec.Placement.Platforms = imgPlatforms + } + } + return warning +} + +func resolvePluginSpecRemote(ctx context.Context, cli DistributionAPIClient, taskSpec *swarm.TaskSpec, encodedAuth string) string { + var warning string + if img, imgPlatforms, err := imageDigestAndPlatforms(ctx, cli, taskSpec.PluginSpec.Remote, encodedAuth); err != nil { + warning = digestWarning(taskSpec.PluginSpec.Remote) + } else { + taskSpec.PluginSpec.Remote = img + if len(imgPlatforms) > 0 { + if taskSpec.Placement == nil { + taskSpec.Placement = &swarm.Placement{} + } + taskSpec.Placement.Platforms = imgPlatforms + } + } + return warning +} + +func imageDigestAndPlatforms(ctx context.Context, cli DistributionAPIClient, image, encodedAuth string) (string, []swarm.Platform, error) { + distributionInspect, err := cli.DistributionInspect(ctx, image, encodedAuth) + var platforms []swarm.Platform + if err != nil { + return "", nil, err + } + + imageWithDigest := imageWithDigestString(image, distributionInspect.Descriptor.Digest) + + if len(distributionInspect.Platforms) > 0 { + platforms = make([]swarm.Platform, 0, len(distributionInspect.Platforms)) + for _, p := range distributionInspect.Platforms { + // clear architecture field for arm. This is a temporary patch to address + // https://github.com/docker/swarmkit/issues/2294. The issue is that while + // image manifests report "arm" as the architecture, the node reports + // something like "armv7l" (includes the variant), which causes arm images + // to stop working with swarm mode. This patch removes the architecture + // constraint for arm images to ensure tasks get scheduled. + arch := p.Architecture + if strings.ToLower(arch) == "arm" { + arch = "" + } + platforms = append(platforms, swarm.Platform{ + Architecture: arch, + OS: p.OS, + }) + } + } + return imageWithDigest, platforms, err +} + +// imageWithDigestString takes an image string and a digest, and updates +// the image string if it didn't originally contain a digest. It returns +// image unmodified in other situations. +func imageWithDigestString(image string, dgst digest.Digest) string { + namedRef, err := reference.ParseNormalizedNamed(image) + if err == nil { + if _, isCanonical := namedRef.(reference.Canonical); !isCanonical { + // ensure that image gets a default tag if none is provided + img, err := reference.WithDigest(namedRef, dgst) + if err == nil { + return reference.FamiliarString(img) + } + } + } + return image +} + +// imageWithTagString takes an image string, and returns a tagged image +// string, adding a 'latest' tag if one was not provided. It returns an +// empty string if a canonical reference was provided +func imageWithTagString(image string) string { + namedRef, err := reference.ParseNormalizedNamed(image) + if err == nil { + return reference.FamiliarString(reference.TagNameOnly(namedRef)) + } + return "" +} + +// digestWarning constructs a formatted warning string using the +// image name that could not be pinned by digest. The formatting +// is hardcoded, but could me made smarter in the future +func digestWarning(image string) string { + return fmt.Sprintf("image %s could not be accessed on a registry to record\nits digest. Each node will access %s independently,\npossibly leading to different nodes running different\nversions of the image.\n", image, image) +} + +func validateServiceSpec(s swarm.ServiceSpec) error { + if s.TaskTemplate.ContainerSpec != nil && s.TaskTemplate.PluginSpec != nil { + return errors.New("must not specify both a container spec and a plugin spec in the task template") + } + if s.TaskTemplate.PluginSpec != nil && s.TaskTemplate.Runtime != swarm.RuntimePlugin { + return errors.New("mismatched runtime with plugin spec") + } + if s.TaskTemplate.ContainerSpec != nil && (s.TaskTemplate.Runtime != "" && s.TaskTemplate.Runtime != swarm.RuntimeContainer) { + return errors.New("mismatched runtime with container spec") + } + return nil +} diff --git a/vendor/github.com/docker/docker/client/service_inspect.go b/vendor/github.com/docker/docker/client/service_inspect.go new file mode 100644 index 0000000000..cee020c98b --- /dev/null +++ b/vendor/github.com/docker/docker/client/service_inspect.go @@ -0,0 +1,37 @@ +package client // import "github.com/docker/docker/client" + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "io" + "net/url" + + "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/swarm" +) + +// ServiceInspectWithRaw returns the service information and the raw data. +func (cli *Client) ServiceInspectWithRaw(ctx context.Context, serviceID string, opts types.ServiceInspectOptions) (swarm.Service, []byte, error) { + if serviceID == "" { + return swarm.Service{}, nil, objectNotFoundError{object: "service", id: serviceID} + } + query := url.Values{} + query.Set("insertDefaults", fmt.Sprintf("%v", opts.InsertDefaults)) + serverResp, err := cli.get(ctx, "/services/"+serviceID, query, nil) + defer ensureReaderClosed(serverResp) + if err != nil { + return swarm.Service{}, nil, err + } + + body, err := io.ReadAll(serverResp.body) + if err != nil { + return swarm.Service{}, nil, err + } + + var response swarm.Service + rdr := bytes.NewReader(body) + err = json.NewDecoder(rdr).Decode(&response) + return response, body, err +} diff --git a/vendor/github.com/docker/docker/client/service_list.go b/vendor/github.com/docker/docker/client/service_list.go new file mode 100644 index 0000000000..f97ec75a5c --- /dev/null +++ b/vendor/github.com/docker/docker/client/service_list.go @@ -0,0 +1,39 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "encoding/json" + "net/url" + + "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/filters" + "github.com/docker/docker/api/types/swarm" +) + +// ServiceList returns the list of services. +func (cli *Client) ServiceList(ctx context.Context, options types.ServiceListOptions) ([]swarm.Service, error) { + query := url.Values{} + + if options.Filters.Len() > 0 { + filterJSON, err := filters.ToJSON(options.Filters) + if err != nil { + return nil, err + } + + query.Set("filters", filterJSON) + } + + if options.Status { + query.Set("status", "true") + } + + resp, err := cli.get(ctx, "/services", query, nil) + defer ensureReaderClosed(resp) + if err != nil { + return nil, err + } + + var services []swarm.Service + err = json.NewDecoder(resp.body).Decode(&services) + return services, err +} diff --git a/vendor/github.com/docker/docker/client/service_logs.go b/vendor/github.com/docker/docker/client/service_logs.go new file mode 100644 index 0000000000..906fd4059e --- /dev/null +++ b/vendor/github.com/docker/docker/client/service_logs.go @@ -0,0 +1,52 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "io" + "net/url" + "time" + + "github.com/docker/docker/api/types" + timetypes "github.com/docker/docker/api/types/time" + "github.com/pkg/errors" +) + +// ServiceLogs returns the logs generated by a service in an io.ReadCloser. +// It's up to the caller to close the stream. +func (cli *Client) ServiceLogs(ctx context.Context, serviceID string, options types.ContainerLogsOptions) (io.ReadCloser, error) { + query := url.Values{} + if options.ShowStdout { + query.Set("stdout", "1") + } + + if options.ShowStderr { + query.Set("stderr", "1") + } + + if options.Since != "" { + ts, err := timetypes.GetTimestamp(options.Since, time.Now()) + if err != nil { + return nil, errors.Wrap(err, `invalid value for "since"`) + } + query.Set("since", ts) + } + + if options.Timestamps { + query.Set("timestamps", "1") + } + + if options.Details { + query.Set("details", "1") + } + + if options.Follow { + query.Set("follow", "1") + } + query.Set("tail", options.Tail) + + resp, err := cli.get(ctx, "/services/"+serviceID+"/logs", query, nil) + if err != nil { + return nil, err + } + return resp.body, nil +} diff --git a/vendor/github.com/docker/docker/client/service_remove.go b/vendor/github.com/docker/docker/client/service_remove.go new file mode 100644 index 0000000000..2c46326ebc --- /dev/null +++ b/vendor/github.com/docker/docker/client/service_remove.go @@ -0,0 +1,10 @@ +package client // import "github.com/docker/docker/client" + +import "context" + +// ServiceRemove kills and removes a service. +func (cli *Client) ServiceRemove(ctx context.Context, serviceID string) error { + resp, err := cli.delete(ctx, "/services/"+serviceID, nil, nil) + defer ensureReaderClosed(resp) + return err +} diff --git a/vendor/github.com/docker/docker/client/service_update.go b/vendor/github.com/docker/docker/client/service_update.go new file mode 100644 index 0000000000..8014b86258 --- /dev/null +++ b/vendor/github.com/docker/docker/client/service_update.go @@ -0,0 +1,74 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "encoding/json" + "net/url" + + "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/swarm" +) + +// ServiceUpdate updates a Service. The version number is required to avoid conflicting writes. +// It should be the value as set *before* the update. You can find this value in the Meta field +// of swarm.Service, which can be found using ServiceInspectWithRaw. +func (cli *Client) ServiceUpdate(ctx context.Context, serviceID string, version swarm.Version, service swarm.ServiceSpec, options types.ServiceUpdateOptions) (types.ServiceUpdateResponse, error) { + var ( + query = url.Values{} + response = types.ServiceUpdateResponse{} + ) + + headers := map[string][]string{ + "version": {cli.version}, + } + + if options.EncodedRegistryAuth != "" { + headers["X-Registry-Auth"] = []string{options.EncodedRegistryAuth} + } + + if options.RegistryAuthFrom != "" { + query.Set("registryAuthFrom", options.RegistryAuthFrom) + } + + if options.Rollback != "" { + query.Set("rollback", options.Rollback) + } + + query.Set("version", version.String()) + + if err := validateServiceSpec(service); err != nil { + return response, err + } + + // ensure that the image is tagged + var resolveWarning string + switch { + case service.TaskTemplate.ContainerSpec != nil: + if taggedImg := imageWithTagString(service.TaskTemplate.ContainerSpec.Image); taggedImg != "" { + service.TaskTemplate.ContainerSpec.Image = taggedImg + } + if options.QueryRegistry { + resolveWarning = resolveContainerSpecImage(ctx, cli, &service.TaskTemplate, options.EncodedRegistryAuth) + } + case service.TaskTemplate.PluginSpec != nil: + if taggedImg := imageWithTagString(service.TaskTemplate.PluginSpec.Remote); taggedImg != "" { + service.TaskTemplate.PluginSpec.Remote = taggedImg + } + if options.QueryRegistry { + resolveWarning = resolvePluginSpecRemote(ctx, cli, &service.TaskTemplate, options.EncodedRegistryAuth) + } + } + + resp, err := cli.post(ctx, "/services/"+serviceID+"/update", query, service, headers) + defer ensureReaderClosed(resp) + if err != nil { + return response, err + } + + err = json.NewDecoder(resp.body).Decode(&response) + if resolveWarning != "" { + response.Warnings = append(response.Warnings, resolveWarning) + } + + return response, err +} diff --git a/vendor/github.com/docker/docker/client/swarm_get_unlock_key.go b/vendor/github.com/docker/docker/client/swarm_get_unlock_key.go new file mode 100644 index 0000000000..19f59dd582 --- /dev/null +++ b/vendor/github.com/docker/docker/client/swarm_get_unlock_key.go @@ -0,0 +1,21 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "encoding/json" + + "github.com/docker/docker/api/types" +) + +// SwarmGetUnlockKey retrieves the swarm's unlock key. +func (cli *Client) SwarmGetUnlockKey(ctx context.Context) (types.SwarmUnlockKeyResponse, error) { + serverResp, err := cli.get(ctx, "/swarm/unlockkey", nil, nil) + defer ensureReaderClosed(serverResp) + if err != nil { + return types.SwarmUnlockKeyResponse{}, err + } + + var response types.SwarmUnlockKeyResponse + err = json.NewDecoder(serverResp.body).Decode(&response) + return response, err +} diff --git a/vendor/github.com/docker/docker/client/swarm_init.go b/vendor/github.com/docker/docker/client/swarm_init.go new file mode 100644 index 0000000000..da3c1637ef --- /dev/null +++ b/vendor/github.com/docker/docker/client/swarm_init.go @@ -0,0 +1,21 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "encoding/json" + + "github.com/docker/docker/api/types/swarm" +) + +// SwarmInit initializes the swarm. +func (cli *Client) SwarmInit(ctx context.Context, req swarm.InitRequest) (string, error) { + serverResp, err := cli.post(ctx, "/swarm/init", nil, req, nil) + defer ensureReaderClosed(serverResp) + if err != nil { + return "", err + } + + var response string + err = json.NewDecoder(serverResp.body).Decode(&response) + return response, err +} diff --git a/vendor/github.com/docker/docker/client/swarm_inspect.go b/vendor/github.com/docker/docker/client/swarm_inspect.go new file mode 100644 index 0000000000..b52b67a884 --- /dev/null +++ b/vendor/github.com/docker/docker/client/swarm_inspect.go @@ -0,0 +1,21 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "encoding/json" + + "github.com/docker/docker/api/types/swarm" +) + +// SwarmInspect inspects the swarm. +func (cli *Client) SwarmInspect(ctx context.Context) (swarm.Swarm, error) { + serverResp, err := cli.get(ctx, "/swarm", nil, nil) + defer ensureReaderClosed(serverResp) + if err != nil { + return swarm.Swarm{}, err + } + + var response swarm.Swarm + err = json.NewDecoder(serverResp.body).Decode(&response) + return response, err +} diff --git a/vendor/github.com/docker/docker/client/swarm_join.go b/vendor/github.com/docker/docker/client/swarm_join.go new file mode 100644 index 0000000000..a1cf0455d2 --- /dev/null +++ b/vendor/github.com/docker/docker/client/swarm_join.go @@ -0,0 +1,14 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + + "github.com/docker/docker/api/types/swarm" +) + +// SwarmJoin joins the swarm. +func (cli *Client) SwarmJoin(ctx context.Context, req swarm.JoinRequest) error { + resp, err := cli.post(ctx, "/swarm/join", nil, req, nil) + ensureReaderClosed(resp) + return err +} diff --git a/vendor/github.com/docker/docker/client/swarm_leave.go b/vendor/github.com/docker/docker/client/swarm_leave.go new file mode 100644 index 0000000000..90ca84b363 --- /dev/null +++ b/vendor/github.com/docker/docker/client/swarm_leave.go @@ -0,0 +1,17 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "net/url" +) + +// SwarmLeave leaves the swarm. +func (cli *Client) SwarmLeave(ctx context.Context, force bool) error { + query := url.Values{} + if force { + query.Set("force", "1") + } + resp, err := cli.post(ctx, "/swarm/leave", query, nil, nil) + ensureReaderClosed(resp) + return err +} diff --git a/vendor/github.com/docker/docker/client/swarm_unlock.go b/vendor/github.com/docker/docker/client/swarm_unlock.go new file mode 100644 index 0000000000..d2412f7d44 --- /dev/null +++ b/vendor/github.com/docker/docker/client/swarm_unlock.go @@ -0,0 +1,14 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + + "github.com/docker/docker/api/types/swarm" +) + +// SwarmUnlock unlocks locked swarm. +func (cli *Client) SwarmUnlock(ctx context.Context, req swarm.UnlockRequest) error { + serverResp, err := cli.post(ctx, "/swarm/unlock", nil, req, nil) + ensureReaderClosed(serverResp) + return err +} diff --git a/vendor/github.com/docker/docker/client/swarm_update.go b/vendor/github.com/docker/docker/client/swarm_update.go new file mode 100644 index 0000000000..9fde7d75ee --- /dev/null +++ b/vendor/github.com/docker/docker/client/swarm_update.go @@ -0,0 +1,21 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "net/url" + "strconv" + + "github.com/docker/docker/api/types/swarm" +) + +// SwarmUpdate updates the swarm. +func (cli *Client) SwarmUpdate(ctx context.Context, version swarm.Version, swarm swarm.Spec, flags swarm.UpdateFlags) error { + query := url.Values{} + query.Set("version", version.String()) + query.Set("rotateWorkerToken", strconv.FormatBool(flags.RotateWorkerToken)) + query.Set("rotateManagerToken", strconv.FormatBool(flags.RotateManagerToken)) + query.Set("rotateManagerUnlockKey", strconv.FormatBool(flags.RotateManagerUnlockKey)) + resp, err := cli.post(ctx, "/swarm/update", query, swarm, nil) + ensureReaderClosed(resp) + return err +} diff --git a/vendor/github.com/docker/docker/client/task_inspect.go b/vendor/github.com/docker/docker/client/task_inspect.go new file mode 100644 index 0000000000..dde1f6c59d --- /dev/null +++ b/vendor/github.com/docker/docker/client/task_inspect.go @@ -0,0 +1,32 @@ +package client // import "github.com/docker/docker/client" + +import ( + "bytes" + "context" + "encoding/json" + "io" + + "github.com/docker/docker/api/types/swarm" +) + +// TaskInspectWithRaw returns the task information and its raw representation. +func (cli *Client) TaskInspectWithRaw(ctx context.Context, taskID string) (swarm.Task, []byte, error) { + if taskID == "" { + return swarm.Task{}, nil, objectNotFoundError{object: "task", id: taskID} + } + serverResp, err := cli.get(ctx, "/tasks/"+taskID, nil, nil) + defer ensureReaderClosed(serverResp) + if err != nil { + return swarm.Task{}, nil, err + } + + body, err := io.ReadAll(serverResp.body) + if err != nil { + return swarm.Task{}, nil, err + } + + var response swarm.Task + rdr := bytes.NewReader(body) + err = json.NewDecoder(rdr).Decode(&response) + return response, body, err +} diff --git a/vendor/github.com/docker/docker/client/task_list.go b/vendor/github.com/docker/docker/client/task_list.go new file mode 100644 index 0000000000..4869b44493 --- /dev/null +++ b/vendor/github.com/docker/docker/client/task_list.go @@ -0,0 +1,35 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "encoding/json" + "net/url" + + "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/filters" + "github.com/docker/docker/api/types/swarm" +) + +// TaskList returns the list of tasks. +func (cli *Client) TaskList(ctx context.Context, options types.TaskListOptions) ([]swarm.Task, error) { + query := url.Values{} + + if options.Filters.Len() > 0 { + filterJSON, err := filters.ToJSON(options.Filters) + if err != nil { + return nil, err + } + + query.Set("filters", filterJSON) + } + + resp, err := cli.get(ctx, "/tasks", query, nil) + defer ensureReaderClosed(resp) + if err != nil { + return nil, err + } + + var tasks []swarm.Task + err = json.NewDecoder(resp.body).Decode(&tasks) + return tasks, err +} diff --git a/vendor/github.com/docker/docker/client/task_logs.go b/vendor/github.com/docker/docker/client/task_logs.go new file mode 100644 index 0000000000..6222fab577 --- /dev/null +++ b/vendor/github.com/docker/docker/client/task_logs.go @@ -0,0 +1,51 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "io" + "net/url" + "time" + + "github.com/docker/docker/api/types" + timetypes "github.com/docker/docker/api/types/time" +) + +// TaskLogs returns the logs generated by a task in an io.ReadCloser. +// It's up to the caller to close the stream. +func (cli *Client) TaskLogs(ctx context.Context, taskID string, options types.ContainerLogsOptions) (io.ReadCloser, error) { + query := url.Values{} + if options.ShowStdout { + query.Set("stdout", "1") + } + + if options.ShowStderr { + query.Set("stderr", "1") + } + + if options.Since != "" { + ts, err := timetypes.GetTimestamp(options.Since, time.Now()) + if err != nil { + return nil, err + } + query.Set("since", ts) + } + + if options.Timestamps { + query.Set("timestamps", "1") + } + + if options.Details { + query.Set("details", "1") + } + + if options.Follow { + query.Set("follow", "1") + } + query.Set("tail", options.Tail) + + resp, err := cli.get(ctx, "/tasks/"+taskID+"/logs", query, nil) + if err != nil { + return nil, err + } + return resp.body, nil +} diff --git a/vendor/github.com/docker/docker/client/transport.go b/vendor/github.com/docker/docker/client/transport.go new file mode 100644 index 0000000000..5541344366 --- /dev/null +++ b/vendor/github.com/docker/docker/client/transport.go @@ -0,0 +1,17 @@ +package client // import "github.com/docker/docker/client" + +import ( + "crypto/tls" + "net/http" +) + +// resolveTLSConfig attempts to resolve the TLS configuration from the +// RoundTripper. +func resolveTLSConfig(transport http.RoundTripper) *tls.Config { + switch tr := transport.(type) { + case *http.Transport: + return tr.TLSClientConfig + default: + return nil + } +} diff --git a/vendor/github.com/docker/docker/client/utils.go b/vendor/github.com/docker/docker/client/utils.go new file mode 100644 index 0000000000..7f3ff44eb8 --- /dev/null +++ b/vendor/github.com/docker/docker/client/utils.go @@ -0,0 +1,34 @@ +package client // import "github.com/docker/docker/client" + +import ( + "net/url" + "regexp" + + "github.com/docker/docker/api/types/filters" +) + +var headerRegexp = regexp.MustCompile(`\ADocker/.+\s\((.+)\)\z`) + +// getDockerOS returns the operating system based on the server header from the daemon. +func getDockerOS(serverHeader string) string { + var osType string + matches := headerRegexp.FindStringSubmatch(serverHeader) + if len(matches) > 0 { + osType = matches[1] + } + return osType +} + +// getFiltersQuery returns a url query with "filters" query term, based on the +// filters provided. +func getFiltersQuery(f filters.Args) (url.Values, error) { + query := url.Values{} + if f.Len() > 0 { + filterJSON, err := filters.ToJSON(f) + if err != nil { + return query, err + } + query.Set("filters", filterJSON) + } + return query, nil +} diff --git a/vendor/github.com/docker/docker/client/version.go b/vendor/github.com/docker/docker/client/version.go new file mode 100644 index 0000000000..8f17ff4e87 --- /dev/null +++ b/vendor/github.com/docker/docker/client/version.go @@ -0,0 +1,21 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "encoding/json" + + "github.com/docker/docker/api/types" +) + +// ServerVersion returns information of the docker client and server host. +func (cli *Client) ServerVersion(ctx context.Context) (types.Version, error) { + resp, err := cli.get(ctx, "/version", nil, nil) + defer ensureReaderClosed(resp) + if err != nil { + return types.Version{}, err + } + + var server types.Version + err = json.NewDecoder(resp.body).Decode(&server) + return server, err +} diff --git a/vendor/github.com/docker/docker/client/volume_create.go b/vendor/github.com/docker/docker/client/volume_create.go new file mode 100644 index 0000000000..b3b182437b --- /dev/null +++ b/vendor/github.com/docker/docker/client/volume_create.go @@ -0,0 +1,20 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "encoding/json" + + "github.com/docker/docker/api/types/volume" +) + +// VolumeCreate creates a volume in the docker host. +func (cli *Client) VolumeCreate(ctx context.Context, options volume.CreateOptions) (volume.Volume, error) { + var vol volume.Volume + resp, err := cli.post(ctx, "/volumes/create", nil, options, nil) + defer ensureReaderClosed(resp) + if err != nil { + return vol, err + } + err = json.NewDecoder(resp.body).Decode(&vol) + return vol, err +} diff --git a/vendor/github.com/docker/docker/client/volume_inspect.go b/vendor/github.com/docker/docker/client/volume_inspect.go new file mode 100644 index 0000000000..b3ba4e6046 --- /dev/null +++ b/vendor/github.com/docker/docker/client/volume_inspect.go @@ -0,0 +1,38 @@ +package client // import "github.com/docker/docker/client" + +import ( + "bytes" + "context" + "encoding/json" + "io" + + "github.com/docker/docker/api/types/volume" +) + +// VolumeInspect returns the information about a specific volume in the docker host. +func (cli *Client) VolumeInspect(ctx context.Context, volumeID string) (volume.Volume, error) { + vol, _, err := cli.VolumeInspectWithRaw(ctx, volumeID) + return vol, err +} + +// VolumeInspectWithRaw returns the information about a specific volume in the docker host and its raw representation +func (cli *Client) VolumeInspectWithRaw(ctx context.Context, volumeID string) (volume.Volume, []byte, error) { + if volumeID == "" { + return volume.Volume{}, nil, objectNotFoundError{object: "volume", id: volumeID} + } + + var vol volume.Volume + resp, err := cli.get(ctx, "/volumes/"+volumeID, nil, nil) + defer ensureReaderClosed(resp) + if err != nil { + return vol, nil, err + } + + body, err := io.ReadAll(resp.body) + if err != nil { + return vol, nil, err + } + rdr := bytes.NewReader(body) + err = json.NewDecoder(rdr).Decode(&vol) + return vol, body, err +} diff --git a/vendor/github.com/docker/docker/client/volume_list.go b/vendor/github.com/docker/docker/client/volume_list.go new file mode 100644 index 0000000000..d8204f8db5 --- /dev/null +++ b/vendor/github.com/docker/docker/client/volume_list.go @@ -0,0 +1,33 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "encoding/json" + "net/url" + + "github.com/docker/docker/api/types/filters" + "github.com/docker/docker/api/types/volume" +) + +// VolumeList returns the volumes configured in the docker host. +func (cli *Client) VolumeList(ctx context.Context, filter filters.Args) (volume.ListResponse, error) { + var volumes volume.ListResponse + query := url.Values{} + + if filter.Len() > 0 { + //nolint:staticcheck // ignore SA1019 for old code + filterJSON, err := filters.ToParamWithVersion(cli.version, filter) + if err != nil { + return volumes, err + } + query.Set("filters", filterJSON) + } + resp, err := cli.get(ctx, "/volumes", query, nil) + defer ensureReaderClosed(resp) + if err != nil { + return volumes, err + } + + err = json.NewDecoder(resp.body).Decode(&volumes) + return volumes, err +} diff --git a/vendor/github.com/docker/docker/client/volume_prune.go b/vendor/github.com/docker/docker/client/volume_prune.go new file mode 100644 index 0000000000..6e324708f2 --- /dev/null +++ b/vendor/github.com/docker/docker/client/volume_prune.go @@ -0,0 +1,36 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "encoding/json" + "fmt" + + "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/filters" +) + +// VolumesPrune requests the daemon to delete unused data +func (cli *Client) VolumesPrune(ctx context.Context, pruneFilters filters.Args) (types.VolumesPruneReport, error) { + var report types.VolumesPruneReport + + if err := cli.NewVersionError("1.25", "volume prune"); err != nil { + return report, err + } + + query, err := getFiltersQuery(pruneFilters) + if err != nil { + return report, err + } + + serverResp, err := cli.post(ctx, "/volumes/prune", query, nil, nil) + defer ensureReaderClosed(serverResp) + if err != nil { + return report, err + } + + if err := json.NewDecoder(serverResp.body).Decode(&report); err != nil { + return report, fmt.Errorf("Error retrieving volume prune report: %v", err) + } + + return report, nil +} diff --git a/vendor/github.com/docker/docker/client/volume_remove.go b/vendor/github.com/docker/docker/client/volume_remove.go new file mode 100644 index 0000000000..1f26438360 --- /dev/null +++ b/vendor/github.com/docker/docker/client/volume_remove.go @@ -0,0 +1,21 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "net/url" + + "github.com/docker/docker/api/types/versions" +) + +// VolumeRemove removes a volume from the docker host. +func (cli *Client) VolumeRemove(ctx context.Context, volumeID string, force bool) error { + query := url.Values{} + if versions.GreaterThanOrEqualTo(cli.version, "1.25") { + if force { + query.Set("force", "1") + } + } + resp, err := cli.delete(ctx, "/volumes/"+volumeID, query, nil) + defer ensureReaderClosed(resp) + return err +} diff --git a/vendor/github.com/docker/docker/client/volume_update.go b/vendor/github.com/docker/docker/client/volume_update.go new file mode 100644 index 0000000000..33bd31e531 --- /dev/null +++ b/vendor/github.com/docker/docker/client/volume_update.go @@ -0,0 +1,24 @@ +package client // import "github.com/docker/docker/client" + +import ( + "context" + "net/url" + + "github.com/docker/docker/api/types/swarm" + "github.com/docker/docker/api/types/volume" +) + +// VolumeUpdate updates a volume. This only works for Cluster Volumes, and +// only some fields can be updated. +func (cli *Client) VolumeUpdate(ctx context.Context, volumeID string, version swarm.Version, options volume.UpdateOptions) error { + if err := cli.NewVersionError("1.42", "volume update"); err != nil { + return err + } + + query := url.Values{} + query.Set("version", version.String()) + + resp, err := cli.put(ctx, "/volumes/"+volumeID, query, options, nil) + ensureReaderClosed(resp) + return err +} diff --git a/vendor/github.com/docker/docker/errdefs/defs.go b/vendor/github.com/docker/docker/errdefs/defs.go new file mode 100644 index 0000000000..61e7456b4e --- /dev/null +++ b/vendor/github.com/docker/docker/errdefs/defs.go @@ -0,0 +1,69 @@ +package errdefs // import "github.com/docker/docker/errdefs" + +// ErrNotFound signals that the requested object doesn't exist +type ErrNotFound interface { + NotFound() +} + +// ErrInvalidParameter signals that the user input is invalid +type ErrInvalidParameter interface { + InvalidParameter() +} + +// ErrConflict signals that some internal state conflicts with the requested action and can't be performed. +// A change in state should be able to clear this error. +type ErrConflict interface { + Conflict() +} + +// ErrUnauthorized is used to signify that the user is not authorized to perform a specific action +type ErrUnauthorized interface { + Unauthorized() +} + +// ErrUnavailable signals that the requested action/subsystem is not available. +type ErrUnavailable interface { + Unavailable() +} + +// ErrForbidden signals that the requested action cannot be performed under any circumstances. +// When a ErrForbidden is returned, the caller should never retry the action. +type ErrForbidden interface { + Forbidden() +} + +// ErrSystem signals that some internal error occurred. +// An example of this would be a failed mount request. +type ErrSystem interface { + System() +} + +// ErrNotModified signals that an action can't be performed because it's already in the desired state +type ErrNotModified interface { + NotModified() +} + +// ErrNotImplemented signals that the requested action/feature is not implemented on the system as configured. +type ErrNotImplemented interface { + NotImplemented() +} + +// ErrUnknown signals that the kind of error that occurred is not known. +type ErrUnknown interface { + Unknown() +} + +// ErrCancelled signals that the action was cancelled. +type ErrCancelled interface { + Cancelled() +} + +// ErrDeadline signals that the deadline was reached before the action completed. +type ErrDeadline interface { + DeadlineExceeded() +} + +// ErrDataLoss indicates that data was lost or there is data corruption. +type ErrDataLoss interface { + DataLoss() +} diff --git a/vendor/github.com/docker/docker/errdefs/doc.go b/vendor/github.com/docker/docker/errdefs/doc.go new file mode 100644 index 0000000000..c211f174fc --- /dev/null +++ b/vendor/github.com/docker/docker/errdefs/doc.go @@ -0,0 +1,8 @@ +// Package errdefs defines a set of error interfaces that packages should use for communicating classes of errors. +// Errors that cross the package boundary should implement one (and only one) of these interfaces. +// +// Packages should not reference these interfaces directly, only implement them. +// To check if a particular error implements one of these interfaces, there are helper +// functions provided (e.g. `Is`) which can be used rather than asserting the interfaces directly. +// If you must assert on these interfaces, be sure to check the causal chain (`err.Cause()`). +package errdefs // import "github.com/docker/docker/errdefs" diff --git a/vendor/github.com/docker/docker/errdefs/helpers.go b/vendor/github.com/docker/docker/errdefs/helpers.go new file mode 100644 index 0000000000..fe06fb6f70 --- /dev/null +++ b/vendor/github.com/docker/docker/errdefs/helpers.go @@ -0,0 +1,279 @@ +package errdefs // import "github.com/docker/docker/errdefs" + +import "context" + +type errNotFound struct{ error } + +func (errNotFound) NotFound() {} + +func (e errNotFound) Cause() error { + return e.error +} + +func (e errNotFound) Unwrap() error { + return e.error +} + +// NotFound is a helper to create an error of the class with the same name from any error type +func NotFound(err error) error { + if err == nil || IsNotFound(err) { + return err + } + return errNotFound{err} +} + +type errInvalidParameter struct{ error } + +func (errInvalidParameter) InvalidParameter() {} + +func (e errInvalidParameter) Cause() error { + return e.error +} + +func (e errInvalidParameter) Unwrap() error { + return e.error +} + +// InvalidParameter is a helper to create an error of the class with the same name from any error type +func InvalidParameter(err error) error { + if err == nil || IsInvalidParameter(err) { + return err + } + return errInvalidParameter{err} +} + +type errConflict struct{ error } + +func (errConflict) Conflict() {} + +func (e errConflict) Cause() error { + return e.error +} + +func (e errConflict) Unwrap() error { + return e.error +} + +// Conflict is a helper to create an error of the class with the same name from any error type +func Conflict(err error) error { + if err == nil || IsConflict(err) { + return err + } + return errConflict{err} +} + +type errUnauthorized struct{ error } + +func (errUnauthorized) Unauthorized() {} + +func (e errUnauthorized) Cause() error { + return e.error +} + +func (e errUnauthorized) Unwrap() error { + return e.error +} + +// Unauthorized is a helper to create an error of the class with the same name from any error type +func Unauthorized(err error) error { + if err == nil || IsUnauthorized(err) { + return err + } + return errUnauthorized{err} +} + +type errUnavailable struct{ error } + +func (errUnavailable) Unavailable() {} + +func (e errUnavailable) Cause() error { + return e.error +} + +func (e errUnavailable) Unwrap() error { + return e.error +} + +// Unavailable is a helper to create an error of the class with the same name from any error type +func Unavailable(err error) error { + if err == nil || IsUnavailable(err) { + return err + } + return errUnavailable{err} +} + +type errForbidden struct{ error } + +func (errForbidden) Forbidden() {} + +func (e errForbidden) Cause() error { + return e.error +} + +func (e errForbidden) Unwrap() error { + return e.error +} + +// Forbidden is a helper to create an error of the class with the same name from any error type +func Forbidden(err error) error { + if err == nil || IsForbidden(err) { + return err + } + return errForbidden{err} +} + +type errSystem struct{ error } + +func (errSystem) System() {} + +func (e errSystem) Cause() error { + return e.error +} + +func (e errSystem) Unwrap() error { + return e.error +} + +// System is a helper to create an error of the class with the same name from any error type +func System(err error) error { + if err == nil || IsSystem(err) { + return err + } + return errSystem{err} +} + +type errNotModified struct{ error } + +func (errNotModified) NotModified() {} + +func (e errNotModified) Cause() error { + return e.error +} + +func (e errNotModified) Unwrap() error { + return e.error +} + +// NotModified is a helper to create an error of the class with the same name from any error type +func NotModified(err error) error { + if err == nil || IsNotModified(err) { + return err + } + return errNotModified{err} +} + +type errNotImplemented struct{ error } + +func (errNotImplemented) NotImplemented() {} + +func (e errNotImplemented) Cause() error { + return e.error +} + +func (e errNotImplemented) Unwrap() error { + return e.error +} + +// NotImplemented is a helper to create an error of the class with the same name from any error type +func NotImplemented(err error) error { + if err == nil || IsNotImplemented(err) { + return err + } + return errNotImplemented{err} +} + +type errUnknown struct{ error } + +func (errUnknown) Unknown() {} + +func (e errUnknown) Cause() error { + return e.error +} + +func (e errUnknown) Unwrap() error { + return e.error +} + +// Unknown is a helper to create an error of the class with the same name from any error type +func Unknown(err error) error { + if err == nil || IsUnknown(err) { + return err + } + return errUnknown{err} +} + +type errCancelled struct{ error } + +func (errCancelled) Cancelled() {} + +func (e errCancelled) Cause() error { + return e.error +} + +func (e errCancelled) Unwrap() error { + return e.error +} + +// Cancelled is a helper to create an error of the class with the same name from any error type +func Cancelled(err error) error { + if err == nil || IsCancelled(err) { + return err + } + return errCancelled{err} +} + +type errDeadline struct{ error } + +func (errDeadline) DeadlineExceeded() {} + +func (e errDeadline) Cause() error { + return e.error +} + +func (e errDeadline) Unwrap() error { + return e.error +} + +// Deadline is a helper to create an error of the class with the same name from any error type +func Deadline(err error) error { + if err == nil || IsDeadline(err) { + return err + } + return errDeadline{err} +} + +type errDataLoss struct{ error } + +func (errDataLoss) DataLoss() {} + +func (e errDataLoss) Cause() error { + return e.error +} + +func (e errDataLoss) Unwrap() error { + return e.error +} + +// DataLoss is a helper to create an error of the class with the same name from any error type +func DataLoss(err error) error { + if err == nil || IsDataLoss(err) { + return err + } + return errDataLoss{err} +} + +// FromContext returns the error class from the passed in context +func FromContext(ctx context.Context) error { + e := ctx.Err() + if e == nil { + return nil + } + + if e == context.Canceled { + return Cancelled(e) + } + if e == context.DeadlineExceeded { + return Deadline(e) + } + return Unknown(e) +} diff --git a/vendor/github.com/docker/docker/errdefs/http_helpers.go b/vendor/github.com/docker/docker/errdefs/http_helpers.go new file mode 100644 index 0000000000..77bda389d1 --- /dev/null +++ b/vendor/github.com/docker/docker/errdefs/http_helpers.go @@ -0,0 +1,46 @@ +package errdefs // import "github.com/docker/docker/errdefs" + +import ( + "net/http" +) + +// FromStatusCode creates an errdef error, based on the provided HTTP status-code +func FromStatusCode(err error, statusCode int) error { + if err == nil { + return nil + } + switch statusCode { + case http.StatusNotFound: + err = NotFound(err) + case http.StatusBadRequest: + err = InvalidParameter(err) + case http.StatusConflict: + err = Conflict(err) + case http.StatusUnauthorized: + err = Unauthorized(err) + case http.StatusServiceUnavailable: + err = Unavailable(err) + case http.StatusForbidden: + err = Forbidden(err) + case http.StatusNotModified: + err = NotModified(err) + case http.StatusNotImplemented: + err = NotImplemented(err) + case http.StatusInternalServerError: + if !IsSystem(err) && !IsUnknown(err) && !IsDataLoss(err) && !IsDeadline(err) && !IsCancelled(err) { + err = System(err) + } + default: + switch { + case statusCode >= 200 && statusCode < 400: + // it's a client error + case statusCode >= 400 && statusCode < 500: + err = InvalidParameter(err) + case statusCode >= 500 && statusCode < 600: + err = System(err) + default: + err = Unknown(err) + } + } + return err +} diff --git a/vendor/github.com/docker/docker/errdefs/is.go b/vendor/github.com/docker/docker/errdefs/is.go new file mode 100644 index 0000000000..3abf07d0c3 --- /dev/null +++ b/vendor/github.com/docker/docker/errdefs/is.go @@ -0,0 +1,107 @@ +package errdefs // import "github.com/docker/docker/errdefs" + +type causer interface { + Cause() error +} + +func getImplementer(err error) error { + switch e := err.(type) { + case + ErrNotFound, + ErrInvalidParameter, + ErrConflict, + ErrUnauthorized, + ErrUnavailable, + ErrForbidden, + ErrSystem, + ErrNotModified, + ErrNotImplemented, + ErrCancelled, + ErrDeadline, + ErrDataLoss, + ErrUnknown: + return err + case causer: + return getImplementer(e.Cause()) + default: + return err + } +} + +// IsNotFound returns if the passed in error is an ErrNotFound +func IsNotFound(err error) bool { + _, ok := getImplementer(err).(ErrNotFound) + return ok +} + +// IsInvalidParameter returns if the passed in error is an ErrInvalidParameter +func IsInvalidParameter(err error) bool { + _, ok := getImplementer(err).(ErrInvalidParameter) + return ok +} + +// IsConflict returns if the passed in error is an ErrConflict +func IsConflict(err error) bool { + _, ok := getImplementer(err).(ErrConflict) + return ok +} + +// IsUnauthorized returns if the passed in error is an ErrUnauthorized +func IsUnauthorized(err error) bool { + _, ok := getImplementer(err).(ErrUnauthorized) + return ok +} + +// IsUnavailable returns if the passed in error is an ErrUnavailable +func IsUnavailable(err error) bool { + _, ok := getImplementer(err).(ErrUnavailable) + return ok +} + +// IsForbidden returns if the passed in error is an ErrForbidden +func IsForbidden(err error) bool { + _, ok := getImplementer(err).(ErrForbidden) + return ok +} + +// IsSystem returns if the passed in error is an ErrSystem +func IsSystem(err error) bool { + _, ok := getImplementer(err).(ErrSystem) + return ok +} + +// IsNotModified returns if the passed in error is a NotModified error +func IsNotModified(err error) bool { + _, ok := getImplementer(err).(ErrNotModified) + return ok +} + +// IsNotImplemented returns if the passed in error is an ErrNotImplemented +func IsNotImplemented(err error) bool { + _, ok := getImplementer(err).(ErrNotImplemented) + return ok +} + +// IsUnknown returns if the passed in error is an ErrUnknown +func IsUnknown(err error) bool { + _, ok := getImplementer(err).(ErrUnknown) + return ok +} + +// IsCancelled returns if the passed in error is an ErrCancelled +func IsCancelled(err error) bool { + _, ok := getImplementer(err).(ErrCancelled) + return ok +} + +// IsDeadline returns if the passed in error is an ErrDeadline +func IsDeadline(err error) bool { + _, ok := getImplementer(err).(ErrDeadline) + return ok +} + +// IsDataLoss returns if the passed in error is an ErrDataLoss +func IsDataLoss(err error) bool { + _, ok := getImplementer(err).(ErrDataLoss) + return ok +} diff --git a/vendor/github.com/docker/go-connections/LICENSE b/vendor/github.com/docker/go-connections/LICENSE new file mode 100644 index 0000000000..b55b37bc31 --- /dev/null +++ b/vendor/github.com/docker/go-connections/LICENSE @@ -0,0 +1,191 @@ + + Apache License + Version 2.0, January 2004 + https://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + Copyright 2015 Docker, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/docker/go-connections/nat/nat.go b/vendor/github.com/docker/go-connections/nat/nat.go new file mode 100644 index 0000000000..bb7e4e3369 --- /dev/null +++ b/vendor/github.com/docker/go-connections/nat/nat.go @@ -0,0 +1,242 @@ +// Package nat is a convenience package for manipulation of strings describing network ports. +package nat + +import ( + "fmt" + "net" + "strconv" + "strings" +) + +const ( + // portSpecTemplate is the expected format for port specifications + portSpecTemplate = "ip:hostPort:containerPort" +) + +// PortBinding represents a binding between a Host IP address and a Host Port +type PortBinding struct { + // HostIP is the host IP Address + HostIP string `json:"HostIp"` + // HostPort is the host port number + HostPort string +} + +// PortMap is a collection of PortBinding indexed by Port +type PortMap map[Port][]PortBinding + +// PortSet is a collection of structs indexed by Port +type PortSet map[Port]struct{} + +// Port is a string containing port number and protocol in the format "80/tcp" +type Port string + +// NewPort creates a new instance of a Port given a protocol and port number or port range +func NewPort(proto, port string) (Port, error) { + // Check for parsing issues on "port" now so we can avoid having + // to check it later on. + + portStartInt, portEndInt, err := ParsePortRangeToInt(port) + if err != nil { + return "", err + } + + if portStartInt == portEndInt { + return Port(fmt.Sprintf("%d/%s", portStartInt, proto)), nil + } + return Port(fmt.Sprintf("%d-%d/%s", portStartInt, portEndInt, proto)), nil +} + +// ParsePort parses the port number string and returns an int +func ParsePort(rawPort string) (int, error) { + if len(rawPort) == 0 { + return 0, nil + } + port, err := strconv.ParseUint(rawPort, 10, 16) + if err != nil { + return 0, err + } + return int(port), nil +} + +// ParsePortRangeToInt parses the port range string and returns start/end ints +func ParsePortRangeToInt(rawPort string) (int, int, error) { + if len(rawPort) == 0 { + return 0, 0, nil + } + start, end, err := ParsePortRange(rawPort) + if err != nil { + return 0, 0, err + } + return int(start), int(end), nil +} + +// Proto returns the protocol of a Port +func (p Port) Proto() string { + proto, _ := SplitProtoPort(string(p)) + return proto +} + +// Port returns the port number of a Port +func (p Port) Port() string { + _, port := SplitProtoPort(string(p)) + return port +} + +// Int returns the port number of a Port as an int +func (p Port) Int() int { + portStr := p.Port() + // We don't need to check for an error because we're going to + // assume that any error would have been found, and reported, in NewPort() + port, _ := ParsePort(portStr) + return port +} + +// Range returns the start/end port numbers of a Port range as ints +func (p Port) Range() (int, int, error) { + return ParsePortRangeToInt(p.Port()) +} + +// SplitProtoPort splits a port in the format of proto/port +func SplitProtoPort(rawPort string) (string, string) { + parts := strings.Split(rawPort, "/") + l := len(parts) + if len(rawPort) == 0 || l == 0 || len(parts[0]) == 0 { + return "", "" + } + if l == 1 { + return "tcp", rawPort + } + if len(parts[1]) == 0 { + return "tcp", parts[0] + } + return parts[1], parts[0] +} + +func validateProto(proto string) bool { + for _, availableProto := range []string{"tcp", "udp", "sctp"} { + if availableProto == proto { + return true + } + } + return false +} + +// ParsePortSpecs receives port specs in the format of ip:public:private/proto and parses +// these in to the internal types +func ParsePortSpecs(ports []string) (map[Port]struct{}, map[Port][]PortBinding, error) { + var ( + exposedPorts = make(map[Port]struct{}, len(ports)) + bindings = make(map[Port][]PortBinding) + ) + for _, rawPort := range ports { + portMappings, err := ParsePortSpec(rawPort) + if err != nil { + return nil, nil, err + } + + for _, portMapping := range portMappings { + port := portMapping.Port + if _, exists := exposedPorts[port]; !exists { + exposedPorts[port] = struct{}{} + } + bslice, exists := bindings[port] + if !exists { + bslice = []PortBinding{} + } + bindings[port] = append(bslice, portMapping.Binding) + } + } + return exposedPorts, bindings, nil +} + +// PortMapping is a data object mapping a Port to a PortBinding +type PortMapping struct { + Port Port + Binding PortBinding +} + +func splitParts(rawport string) (string, string, string) { + parts := strings.Split(rawport, ":") + n := len(parts) + containerport := parts[n-1] + + switch n { + case 1: + return "", "", containerport + case 2: + return "", parts[0], containerport + case 3: + return parts[0], parts[1], containerport + default: + return strings.Join(parts[:n-2], ":"), parts[n-2], containerport + } +} + +// ParsePortSpec parses a port specification string into a slice of PortMappings +func ParsePortSpec(rawPort string) ([]PortMapping, error) { + var proto string + rawIP, hostPort, containerPort := splitParts(rawPort) + proto, containerPort = SplitProtoPort(containerPort) + + // Strip [] from IPV6 addresses + ip, _, err := net.SplitHostPort(rawIP + ":") + if err != nil { + return nil, fmt.Errorf("Invalid ip address %v: %s", rawIP, err) + } + if ip != "" && net.ParseIP(ip) == nil { + return nil, fmt.Errorf("Invalid ip address: %s", ip) + } + if containerPort == "" { + return nil, fmt.Errorf("No port specified: %s", rawPort) + } + + startPort, endPort, err := ParsePortRange(containerPort) + if err != nil { + return nil, fmt.Errorf("Invalid containerPort: %s", containerPort) + } + + var startHostPort, endHostPort uint64 = 0, 0 + if len(hostPort) > 0 { + startHostPort, endHostPort, err = ParsePortRange(hostPort) + if err != nil { + return nil, fmt.Errorf("Invalid hostPort: %s", hostPort) + } + } + + if hostPort != "" && (endPort-startPort) != (endHostPort-startHostPort) { + // Allow host port range iff containerPort is not a range. + // In this case, use the host port range as the dynamic + // host port range to allocate into. + if endPort != startPort { + return nil, fmt.Errorf("Invalid ranges specified for container and host Ports: %s and %s", containerPort, hostPort) + } + } + + if !validateProto(strings.ToLower(proto)) { + return nil, fmt.Errorf("Invalid proto: %s", proto) + } + + ports := []PortMapping{} + for i := uint64(0); i <= (endPort - startPort); i++ { + containerPort = strconv.FormatUint(startPort+i, 10) + if len(hostPort) > 0 { + hostPort = strconv.FormatUint(startHostPort+i, 10) + } + // Set hostPort to a range only if there is a single container port + // and a dynamic host port. + if startPort == endPort && startHostPort != endHostPort { + hostPort = fmt.Sprintf("%s-%s", hostPort, strconv.FormatUint(endHostPort, 10)) + } + port, err := NewPort(strings.ToLower(proto), containerPort) + if err != nil { + return nil, err + } + + binding := PortBinding{ + HostIP: ip, + HostPort: hostPort, + } + ports = append(ports, PortMapping{Port: port, Binding: binding}) + } + return ports, nil +} diff --git a/vendor/github.com/docker/go-connections/nat/parse.go b/vendor/github.com/docker/go-connections/nat/parse.go new file mode 100644 index 0000000000..892adf8c66 --- /dev/null +++ b/vendor/github.com/docker/go-connections/nat/parse.go @@ -0,0 +1,57 @@ +package nat + +import ( + "fmt" + "strconv" + "strings" +) + +// PartParser parses and validates the specified string (data) using the specified template +// e.g. ip:public:private -> 192.168.0.1:80:8000 +// DEPRECATED: do not use, this function may be removed in a future version +func PartParser(template, data string) (map[string]string, error) { + // ip:public:private + var ( + templateParts = strings.Split(template, ":") + parts = strings.Split(data, ":") + out = make(map[string]string, len(templateParts)) + ) + if len(parts) != len(templateParts) { + return nil, fmt.Errorf("Invalid format to parse. %s should match template %s", data, template) + } + + for i, t := range templateParts { + value := "" + if len(parts) > i { + value = parts[i] + } + out[t] = value + } + return out, nil +} + +// ParsePortRange parses and validates the specified string as a port-range (8000-9000) +func ParsePortRange(ports string) (uint64, uint64, error) { + if ports == "" { + return 0, 0, fmt.Errorf("Empty string specified for ports.") + } + if !strings.Contains(ports, "-") { + start, err := strconv.ParseUint(ports, 10, 16) + end := start + return start, end, err + } + + parts := strings.Split(ports, "-") + start, err := strconv.ParseUint(parts[0], 10, 16) + if err != nil { + return 0, 0, err + } + end, err := strconv.ParseUint(parts[1], 10, 16) + if err != nil { + return 0, 0, err + } + if end < start { + return 0, 0, fmt.Errorf("Invalid range specified for the Port: %s", ports) + } + return start, end, nil +} diff --git a/vendor/github.com/docker/go-connections/nat/sort.go b/vendor/github.com/docker/go-connections/nat/sort.go new file mode 100644 index 0000000000..ce950171e3 --- /dev/null +++ b/vendor/github.com/docker/go-connections/nat/sort.go @@ -0,0 +1,96 @@ +package nat + +import ( + "sort" + "strings" +) + +type portSorter struct { + ports []Port + by func(i, j Port) bool +} + +func (s *portSorter) Len() int { + return len(s.ports) +} + +func (s *portSorter) Swap(i, j int) { + s.ports[i], s.ports[j] = s.ports[j], s.ports[i] +} + +func (s *portSorter) Less(i, j int) bool { + ip := s.ports[i] + jp := s.ports[j] + + return s.by(ip, jp) +} + +// Sort sorts a list of ports using the provided predicate +// This function should compare `i` and `j`, returning true if `i` is +// considered to be less than `j` +func Sort(ports []Port, predicate func(i, j Port) bool) { + s := &portSorter{ports, predicate} + sort.Sort(s) +} + +type portMapEntry struct { + port Port + binding PortBinding +} + +type portMapSorter []portMapEntry + +func (s portMapSorter) Len() int { return len(s) } +func (s portMapSorter) Swap(i, j int) { s[i], s[j] = s[j], s[i] } + +// sort the port so that the order is: +// 1. port with larger specified bindings +// 2. larger port +// 3. port with tcp protocol +func (s portMapSorter) Less(i, j int) bool { + pi, pj := s[i].port, s[j].port + hpi, hpj := toInt(s[i].binding.HostPort), toInt(s[j].binding.HostPort) + return hpi > hpj || pi.Int() > pj.Int() || (pi.Int() == pj.Int() && strings.ToLower(pi.Proto()) == "tcp") +} + +// SortPortMap sorts the list of ports and their respected mapping. The ports +// will explicit HostPort will be placed first. +func SortPortMap(ports []Port, bindings PortMap) { + s := portMapSorter{} + for _, p := range ports { + if binding, ok := bindings[p]; ok { + for _, b := range binding { + s = append(s, portMapEntry{port: p, binding: b}) + } + bindings[p] = []PortBinding{} + } else { + s = append(s, portMapEntry{port: p}) + } + } + + sort.Sort(s) + var ( + i int + pm = make(map[Port]struct{}) + ) + // reorder ports + for _, entry := range s { + if _, ok := pm[entry.port]; !ok { + ports[i] = entry.port + pm[entry.port] = struct{}{} + i++ + } + // reorder bindings for this port + if _, ok := bindings[entry.port]; ok { + bindings[entry.port] = append(bindings[entry.port], entry.binding) + } + } +} + +func toInt(s string) uint64 { + i, _, err := ParsePortRange(s) + if err != nil { + i = 0 + } + return i +} diff --git a/vendor/github.com/docker/go-connections/sockets/README.md b/vendor/github.com/docker/go-connections/sockets/README.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/vendor/github.com/docker/go-connections/sockets/inmem_socket.go b/vendor/github.com/docker/go-connections/sockets/inmem_socket.go new file mode 100644 index 0000000000..99846ffddb --- /dev/null +++ b/vendor/github.com/docker/go-connections/sockets/inmem_socket.go @@ -0,0 +1,81 @@ +package sockets + +import ( + "errors" + "net" + "sync" +) + +var errClosed = errors.New("use of closed network connection") + +// InmemSocket implements net.Listener using in-memory only connections. +type InmemSocket struct { + chConn chan net.Conn + chClose chan struct{} + addr string + mu sync.Mutex +} + +// dummyAddr is used to satisfy net.Addr for the in-mem socket +// it is just stored as a string and returns the string for all calls +type dummyAddr string + +// NewInmemSocket creates an in-memory only net.Listener +// The addr argument can be any string, but is used to satisfy the `Addr()` part +// of the net.Listener interface +func NewInmemSocket(addr string, bufSize int) *InmemSocket { + return &InmemSocket{ + chConn: make(chan net.Conn, bufSize), + chClose: make(chan struct{}), + addr: addr, + } +} + +// Addr returns the socket's addr string to satisfy net.Listener +func (s *InmemSocket) Addr() net.Addr { + return dummyAddr(s.addr) +} + +// Accept implements the Accept method in the Listener interface; it waits for the next call and returns a generic Conn. +func (s *InmemSocket) Accept() (net.Conn, error) { + select { + case conn := <-s.chConn: + return conn, nil + case <-s.chClose: + return nil, errClosed + } +} + +// Close closes the listener. It will be unavailable for use once closed. +func (s *InmemSocket) Close() error { + s.mu.Lock() + defer s.mu.Unlock() + select { + case <-s.chClose: + default: + close(s.chClose) + } + return nil +} + +// Dial is used to establish a connection with the in-mem server +func (s *InmemSocket) Dial(network, addr string) (net.Conn, error) { + srvConn, clientConn := net.Pipe() + select { + case s.chConn <- srvConn: + case <-s.chClose: + return nil, errClosed + } + + return clientConn, nil +} + +// Network returns the addr string, satisfies net.Addr +func (a dummyAddr) Network() string { + return string(a) +} + +// String returns the string form +func (a dummyAddr) String() string { + return string(a) +} diff --git a/vendor/github.com/docker/go-connections/sockets/proxy.go b/vendor/github.com/docker/go-connections/sockets/proxy.go new file mode 100644 index 0000000000..98e9a1dc61 --- /dev/null +++ b/vendor/github.com/docker/go-connections/sockets/proxy.go @@ -0,0 +1,51 @@ +package sockets + +import ( + "net" + "net/url" + "os" + "strings" + + "golang.org/x/net/proxy" +) + +// GetProxyEnv allows access to the uppercase and the lowercase forms of +// proxy-related variables. See the Go specification for details on these +// variables. https://golang.org/pkg/net/http/ +func GetProxyEnv(key string) string { + proxyValue := os.Getenv(strings.ToUpper(key)) + if proxyValue == "" { + return os.Getenv(strings.ToLower(key)) + } + return proxyValue +} + +// DialerFromEnvironment takes in a "direct" *net.Dialer and returns a +// proxy.Dialer which will route the connections through the proxy using the +// given dialer. +func DialerFromEnvironment(direct *net.Dialer) (proxy.Dialer, error) { + allProxy := GetProxyEnv("all_proxy") + if len(allProxy) == 0 { + return direct, nil + } + + proxyURL, err := url.Parse(allProxy) + if err != nil { + return direct, err + } + + proxyFromURL, err := proxy.FromURL(proxyURL, direct) + if err != nil { + return direct, err + } + + noProxy := GetProxyEnv("no_proxy") + if len(noProxy) == 0 { + return proxyFromURL, nil + } + + perHost := proxy.NewPerHost(proxyFromURL, direct) + perHost.AddFromString(noProxy) + + return perHost, nil +} diff --git a/vendor/github.com/docker/go-connections/sockets/sockets.go b/vendor/github.com/docker/go-connections/sockets/sockets.go new file mode 100644 index 0000000000..a1d7beb4d8 --- /dev/null +++ b/vendor/github.com/docker/go-connections/sockets/sockets.go @@ -0,0 +1,38 @@ +// Package sockets provides helper functions to create and configure Unix or TCP sockets. +package sockets + +import ( + "errors" + "net" + "net/http" + "time" +) + +// Why 32? See https://github.com/docker/docker/pull/8035. +const defaultTimeout = 32 * time.Second + +// ErrProtocolNotAvailable is returned when a given transport protocol is not provided by the operating system. +var ErrProtocolNotAvailable = errors.New("protocol not available") + +// ConfigureTransport configures the specified Transport according to the +// specified proto and addr. +// If the proto is unix (using a unix socket to communicate) or npipe the +// compression is disabled. +func ConfigureTransport(tr *http.Transport, proto, addr string) error { + switch proto { + case "unix": + return configureUnixTransport(tr, proto, addr) + case "npipe": + return configureNpipeTransport(tr, proto, addr) + default: + tr.Proxy = http.ProxyFromEnvironment + dialer, err := DialerFromEnvironment(&net.Dialer{ + Timeout: defaultTimeout, + }) + if err != nil { + return err + } + tr.Dial = dialer.Dial + } + return nil +} diff --git a/vendor/github.com/docker/go-connections/sockets/sockets_unix.go b/vendor/github.com/docker/go-connections/sockets/sockets_unix.go new file mode 100644 index 0000000000..386cf0dbbd --- /dev/null +++ b/vendor/github.com/docker/go-connections/sockets/sockets_unix.go @@ -0,0 +1,35 @@ +// +build !windows + +package sockets + +import ( + "fmt" + "net" + "net/http" + "syscall" + "time" +) + +const maxUnixSocketPathSize = len(syscall.RawSockaddrUnix{}.Path) + +func configureUnixTransport(tr *http.Transport, proto, addr string) error { + if len(addr) > maxUnixSocketPathSize { + return fmt.Errorf("Unix socket path %q is too long", addr) + } + // No need for compression in local communications. + tr.DisableCompression = true + tr.Dial = func(_, _ string) (net.Conn, error) { + return net.DialTimeout(proto, addr, defaultTimeout) + } + return nil +} + +func configureNpipeTransport(tr *http.Transport, proto, addr string) error { + return ErrProtocolNotAvailable +} + +// DialPipe connects to a Windows named pipe. +// This is not supported on other OSes. +func DialPipe(_ string, _ time.Duration) (net.Conn, error) { + return nil, syscall.EAFNOSUPPORT +} diff --git a/vendor/github.com/docker/go-connections/sockets/sockets_windows.go b/vendor/github.com/docker/go-connections/sockets/sockets_windows.go new file mode 100644 index 0000000000..5c21644e1f --- /dev/null +++ b/vendor/github.com/docker/go-connections/sockets/sockets_windows.go @@ -0,0 +1,27 @@ +package sockets + +import ( + "net" + "net/http" + "time" + + "github.com/Microsoft/go-winio" +) + +func configureUnixTransport(tr *http.Transport, proto, addr string) error { + return ErrProtocolNotAvailable +} + +func configureNpipeTransport(tr *http.Transport, proto, addr string) error { + // No need for compression in local communications. + tr.DisableCompression = true + tr.Dial = func(_, _ string) (net.Conn, error) { + return DialPipe(addr, defaultTimeout) + } + return nil +} + +// DialPipe connects to a Windows named pipe. +func DialPipe(addr string, timeout time.Duration) (net.Conn, error) { + return winio.DialPipe(addr, &timeout) +} diff --git a/vendor/github.com/docker/go-connections/sockets/tcp_socket.go b/vendor/github.com/docker/go-connections/sockets/tcp_socket.go new file mode 100644 index 0000000000..53cbb6c79e --- /dev/null +++ b/vendor/github.com/docker/go-connections/sockets/tcp_socket.go @@ -0,0 +1,22 @@ +// Package sockets provides helper functions to create and configure Unix or TCP sockets. +package sockets + +import ( + "crypto/tls" + "net" +) + +// NewTCPSocket creates a TCP socket listener with the specified address and +// the specified tls configuration. If TLSConfig is set, will encapsulate the +// TCP listener inside a TLS one. +func NewTCPSocket(addr string, tlsConfig *tls.Config) (net.Listener, error) { + l, err := net.Listen("tcp", addr) + if err != nil { + return nil, err + } + if tlsConfig != nil { + tlsConfig.NextProtos = []string{"http/1.1"} + l = tls.NewListener(l, tlsConfig) + } + return l, nil +} diff --git a/vendor/github.com/docker/go-connections/sockets/unix_socket.go b/vendor/github.com/docker/go-connections/sockets/unix_socket.go new file mode 100644 index 0000000000..a8b5dbb6fd --- /dev/null +++ b/vendor/github.com/docker/go-connections/sockets/unix_socket.go @@ -0,0 +1,32 @@ +// +build !windows + +package sockets + +import ( + "net" + "os" + "syscall" +) + +// NewUnixSocket creates a unix socket with the specified path and group. +func NewUnixSocket(path string, gid int) (net.Listener, error) { + if err := syscall.Unlink(path); err != nil && !os.IsNotExist(err) { + return nil, err + } + mask := syscall.Umask(0777) + defer syscall.Umask(mask) + + l, err := net.Listen("unix", path) + if err != nil { + return nil, err + } + if err := os.Chown(path, 0, gid); err != nil { + l.Close() + return nil, err + } + if err := os.Chmod(path, 0660); err != nil { + l.Close() + return nil, err + } + return l, nil +} diff --git a/vendor/github.com/docker/go-connections/tlsconfig/certpool_go17.go b/vendor/github.com/docker/go-connections/tlsconfig/certpool_go17.go new file mode 100644 index 0000000000..1ca0965e06 --- /dev/null +++ b/vendor/github.com/docker/go-connections/tlsconfig/certpool_go17.go @@ -0,0 +1,18 @@ +// +build go1.7 + +package tlsconfig + +import ( + "crypto/x509" + "runtime" +) + +// SystemCertPool returns a copy of the system cert pool, +// returns an error if failed to load or empty pool on windows. +func SystemCertPool() (*x509.CertPool, error) { + certpool, err := x509.SystemCertPool() + if err != nil && runtime.GOOS == "windows" { + return x509.NewCertPool(), nil + } + return certpool, err +} diff --git a/vendor/github.com/docker/go-connections/tlsconfig/certpool_other.go b/vendor/github.com/docker/go-connections/tlsconfig/certpool_other.go new file mode 100644 index 0000000000..1ff81c333c --- /dev/null +++ b/vendor/github.com/docker/go-connections/tlsconfig/certpool_other.go @@ -0,0 +1,13 @@ +// +build !go1.7 + +package tlsconfig + +import ( + "crypto/x509" +) + +// SystemCertPool returns an new empty cert pool, +// accessing system cert pool is supported in go 1.7 +func SystemCertPool() (*x509.CertPool, error) { + return x509.NewCertPool(), nil +} diff --git a/vendor/github.com/docker/go-connections/tlsconfig/config.go b/vendor/github.com/docker/go-connections/tlsconfig/config.go new file mode 100644 index 0000000000..0ef3fdcb46 --- /dev/null +++ b/vendor/github.com/docker/go-connections/tlsconfig/config.go @@ -0,0 +1,254 @@ +// Package tlsconfig provides primitives to retrieve secure-enough TLS configurations for both clients and servers. +// +// As a reminder from https://golang.org/pkg/crypto/tls/#Config: +// A Config structure is used to configure a TLS client or server. After one has been passed to a TLS function it must not be modified. +// A Config may be reused; the tls package will also not modify it. +package tlsconfig + +import ( + "crypto/tls" + "crypto/x509" + "encoding/pem" + "fmt" + "io/ioutil" + "os" + + "github.com/pkg/errors" +) + +// Options represents the information needed to create client and server TLS configurations. +type Options struct { + CAFile string + + // If either CertFile or KeyFile is empty, Client() will not load them + // preventing the client from authenticating to the server. + // However, Server() requires them and will error out if they are empty. + CertFile string + KeyFile string + + // client-only option + InsecureSkipVerify bool + // server-only option + ClientAuth tls.ClientAuthType + // If ExclusiveRootPools is set, then if a CA file is provided, the root pool used for TLS + // creds will include exclusively the roots in that CA file. If no CA file is provided, + // the system pool will be used. + ExclusiveRootPools bool + MinVersion uint16 + // If Passphrase is set, it will be used to decrypt a TLS private key + // if the key is encrypted + Passphrase string +} + +// Extra (server-side) accepted CBC cipher suites - will phase out in the future +var acceptedCBCCiphers = []uint16{ + tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, + tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, + tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, + tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, +} + +// DefaultServerAcceptedCiphers should be uses by code which already has a crypto/tls +// options struct but wants to use a commonly accepted set of TLS cipher suites, with +// known weak algorithms removed. +var DefaultServerAcceptedCiphers = append(clientCipherSuites, acceptedCBCCiphers...) + +// allTLSVersions lists all the TLS versions and is used by the code that validates +// a uint16 value as a TLS version. +var allTLSVersions = map[uint16]struct{}{ + tls.VersionSSL30: {}, + tls.VersionTLS10: {}, + tls.VersionTLS11: {}, + tls.VersionTLS12: {}, +} + +// ServerDefault returns a secure-enough TLS configuration for the server TLS configuration. +func ServerDefault(ops ...func(*tls.Config)) *tls.Config { + tlsconfig := &tls.Config{ + // Avoid fallback by default to SSL protocols < TLS1.2 + MinVersion: tls.VersionTLS12, + PreferServerCipherSuites: true, + CipherSuites: DefaultServerAcceptedCiphers, + } + + for _, op := range ops { + op(tlsconfig) + } + + return tlsconfig +} + +// ClientDefault returns a secure-enough TLS configuration for the client TLS configuration. +func ClientDefault(ops ...func(*tls.Config)) *tls.Config { + tlsconfig := &tls.Config{ + // Prefer TLS1.2 as the client minimum + MinVersion: tls.VersionTLS12, + CipherSuites: clientCipherSuites, + } + + for _, op := range ops { + op(tlsconfig) + } + + return tlsconfig +} + +// certPool returns an X.509 certificate pool from `caFile`, the certificate file. +func certPool(caFile string, exclusivePool bool) (*x509.CertPool, error) { + // If we should verify the server, we need to load a trusted ca + var ( + certPool *x509.CertPool + err error + ) + if exclusivePool { + certPool = x509.NewCertPool() + } else { + certPool, err = SystemCertPool() + if err != nil { + return nil, fmt.Errorf("failed to read system certificates: %v", err) + } + } + pem, err := ioutil.ReadFile(caFile) + if err != nil { + return nil, fmt.Errorf("could not read CA certificate %q: %v", caFile, err) + } + if !certPool.AppendCertsFromPEM(pem) { + return nil, fmt.Errorf("failed to append certificates from PEM file: %q", caFile) + } + return certPool, nil +} + +// isValidMinVersion checks that the input value is a valid tls minimum version +func isValidMinVersion(version uint16) bool { + _, ok := allTLSVersions[version] + return ok +} + +// adjustMinVersion sets the MinVersion on `config`, the input configuration. +// It assumes the current MinVersion on the `config` is the lowest allowed. +func adjustMinVersion(options Options, config *tls.Config) error { + if options.MinVersion > 0 { + if !isValidMinVersion(options.MinVersion) { + return fmt.Errorf("Invalid minimum TLS version: %x", options.MinVersion) + } + if options.MinVersion < config.MinVersion { + return fmt.Errorf("Requested minimum TLS version is too low. Should be at-least: %x", config.MinVersion) + } + config.MinVersion = options.MinVersion + } + + return nil +} + +// IsErrEncryptedKey returns true if the 'err' is an error of incorrect +// password when tryin to decrypt a TLS private key +func IsErrEncryptedKey(err error) bool { + return errors.Cause(err) == x509.IncorrectPasswordError +} + +// getPrivateKey returns the private key in 'keyBytes', in PEM-encoded format. +// If the private key is encrypted, 'passphrase' is used to decrypted the +// private key. +func getPrivateKey(keyBytes []byte, passphrase string) ([]byte, error) { + // this section makes some small changes to code from notary/tuf/utils/x509.go + pemBlock, _ := pem.Decode(keyBytes) + if pemBlock == nil { + return nil, fmt.Errorf("no valid private key found") + } + + var err error + if x509.IsEncryptedPEMBlock(pemBlock) { + keyBytes, err = x509.DecryptPEMBlock(pemBlock, []byte(passphrase)) + if err != nil { + return nil, errors.Wrap(err, "private key is encrypted, but could not decrypt it") + } + keyBytes = pem.EncodeToMemory(&pem.Block{Type: pemBlock.Type, Bytes: keyBytes}) + } + + return keyBytes, nil +} + +// getCert returns a Certificate from the CertFile and KeyFile in 'options', +// if the key is encrypted, the Passphrase in 'options' will be used to +// decrypt it. +func getCert(options Options) ([]tls.Certificate, error) { + if options.CertFile == "" && options.KeyFile == "" { + return nil, nil + } + + errMessage := "Could not load X509 key pair" + + cert, err := ioutil.ReadFile(options.CertFile) + if err != nil { + return nil, errors.Wrap(err, errMessage) + } + + prKeyBytes, err := ioutil.ReadFile(options.KeyFile) + if err != nil { + return nil, errors.Wrap(err, errMessage) + } + + prKeyBytes, err = getPrivateKey(prKeyBytes, options.Passphrase) + if err != nil { + return nil, errors.Wrap(err, errMessage) + } + + tlsCert, err := tls.X509KeyPair(cert, prKeyBytes) + if err != nil { + return nil, errors.Wrap(err, errMessage) + } + + return []tls.Certificate{tlsCert}, nil +} + +// Client returns a TLS configuration meant to be used by a client. +func Client(options Options) (*tls.Config, error) { + tlsConfig := ClientDefault() + tlsConfig.InsecureSkipVerify = options.InsecureSkipVerify + if !options.InsecureSkipVerify && options.CAFile != "" { + CAs, err := certPool(options.CAFile, options.ExclusiveRootPools) + if err != nil { + return nil, err + } + tlsConfig.RootCAs = CAs + } + + tlsCerts, err := getCert(options) + if err != nil { + return nil, err + } + tlsConfig.Certificates = tlsCerts + + if err := adjustMinVersion(options, tlsConfig); err != nil { + return nil, err + } + + return tlsConfig, nil +} + +// Server returns a TLS configuration meant to be used by a server. +func Server(options Options) (*tls.Config, error) { + tlsConfig := ServerDefault() + tlsConfig.ClientAuth = options.ClientAuth + tlsCert, err := tls.LoadX509KeyPair(options.CertFile, options.KeyFile) + if err != nil { + if os.IsNotExist(err) { + return nil, fmt.Errorf("Could not load X509 key pair (cert: %q, key: %q): %v", options.CertFile, options.KeyFile, err) + } + return nil, fmt.Errorf("Error reading X509 key pair (cert: %q, key: %q): %v. Make sure the key is not encrypted.", options.CertFile, options.KeyFile, err) + } + tlsConfig.Certificates = []tls.Certificate{tlsCert} + if options.ClientAuth >= tls.VerifyClientCertIfGiven && options.CAFile != "" { + CAs, err := certPool(options.CAFile, options.ExclusiveRootPools) + if err != nil { + return nil, err + } + tlsConfig.ClientCAs = CAs + } + + if err := adjustMinVersion(options, tlsConfig); err != nil { + return nil, err + } + + return tlsConfig, nil +} diff --git a/vendor/github.com/docker/go-connections/tlsconfig/config_client_ciphers.go b/vendor/github.com/docker/go-connections/tlsconfig/config_client_ciphers.go new file mode 100644 index 0000000000..6b4c6a7c0d --- /dev/null +++ b/vendor/github.com/docker/go-connections/tlsconfig/config_client_ciphers.go @@ -0,0 +1,17 @@ +// +build go1.5 + +// Package tlsconfig provides primitives to retrieve secure-enough TLS configurations for both clients and servers. +// +package tlsconfig + +import ( + "crypto/tls" +) + +// Client TLS cipher suites (dropping CBC ciphers for client preferred suite set) +var clientCipherSuites = []uint16{ + tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, +} diff --git a/vendor/github.com/docker/go-connections/tlsconfig/config_legacy_client_ciphers.go b/vendor/github.com/docker/go-connections/tlsconfig/config_legacy_client_ciphers.go new file mode 100644 index 0000000000..ee22df47cb --- /dev/null +++ b/vendor/github.com/docker/go-connections/tlsconfig/config_legacy_client_ciphers.go @@ -0,0 +1,15 @@ +// +build !go1.5 + +// Package tlsconfig provides primitives to retrieve secure-enough TLS configurations for both clients and servers. +// +package tlsconfig + +import ( + "crypto/tls" +) + +// Client TLS cipher suites (dropping CBC ciphers for client preferred suite set) +var clientCipherSuites = []uint16{ + tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, +} diff --git a/vendor/github.com/docker/go-units/CONTRIBUTING.md b/vendor/github.com/docker/go-units/CONTRIBUTING.md new file mode 100644 index 0000000000..9ea86d784e --- /dev/null +++ b/vendor/github.com/docker/go-units/CONTRIBUTING.md @@ -0,0 +1,67 @@ +# Contributing to go-units + +Want to hack on go-units? Awesome! Here are instructions to get you started. + +go-units is a part of the [Docker](https://www.docker.com) project, and follows +the same rules and principles. If you're already familiar with the way +Docker does things, you'll feel right at home. + +Otherwise, go read Docker's +[contributions guidelines](https://github.com/docker/docker/blob/master/CONTRIBUTING.md), +[issue triaging](https://github.com/docker/docker/blob/master/project/ISSUE-TRIAGE.md), +[review process](https://github.com/docker/docker/blob/master/project/REVIEWING.md) and +[branches and tags](https://github.com/docker/docker/blob/master/project/BRANCHES-AND-TAGS.md). + +### Sign your work + +The sign-off is a simple line at the end of the explanation for the patch. Your +signature certifies that you wrote the patch or otherwise have the right to pass +it on as an open-source patch. The rules are pretty simple: if you can certify +the below (from [developercertificate.org](http://developercertificate.org/)): + +``` +Developer Certificate of Origin +Version 1.1 + +Copyright (C) 2004, 2006 The Linux Foundation and its contributors. +660 York Street, Suite 102, +San Francisco, CA 94110 USA + +Everyone is permitted to copy and distribute verbatim copies of this +license document, but changing it is not allowed. + +Developer's Certificate of Origin 1.1 + +By making a contribution to this project, I certify that: + +(a) The contribution was created in whole or in part by me and I + have the right to submit it under the open source license + indicated in the file; or + +(b) The contribution is based upon previous work that, to the best + of my knowledge, is covered under an appropriate open source + license and I have the right under that license to submit that + work with modifications, whether created in whole or in part + by me, under the same open source license (unless I am + permitted to submit under a different license), as indicated + in the file; or + +(c) The contribution was provided directly to me by some other + person who certified (a), (b) or (c) and I have not modified + it. + +(d) I understand and agree that this project and the contribution + are public and that a record of the contribution (including all + personal information I submit with it, including my sign-off) is + maintained indefinitely and may be redistributed consistent with + this project or the open source license(s) involved. +``` + +Then you just add a line to every git commit message: + + Signed-off-by: Joe Smith + +Use your real name (sorry, no pseudonyms or anonymous contributions.) + +If you set your `user.name` and `user.email` git configs, you can sign your +commit automatically with `git commit -s`. diff --git a/vendor/github.com/docker/go-units/LICENSE b/vendor/github.com/docker/go-units/LICENSE new file mode 100644 index 0000000000..b55b37bc31 --- /dev/null +++ b/vendor/github.com/docker/go-units/LICENSE @@ -0,0 +1,191 @@ + + Apache License + Version 2.0, January 2004 + https://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + Copyright 2015 Docker, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/docker/go-units/MAINTAINERS b/vendor/github.com/docker/go-units/MAINTAINERS new file mode 100644 index 0000000000..4aac7c7411 --- /dev/null +++ b/vendor/github.com/docker/go-units/MAINTAINERS @@ -0,0 +1,46 @@ +# go-units maintainers file +# +# This file describes who runs the docker/go-units project and how. +# This is a living document - if you see something out of date or missing, speak up! +# +# It is structured to be consumable by both humans and programs. +# To extract its contents programmatically, use any TOML-compliant parser. +# +# This file is compiled into the MAINTAINERS file in docker/opensource. +# +[Org] + [Org."Core maintainers"] + people = [ + "akihirosuda", + "dnephin", + "thajeztah", + "vdemeester", + ] + +[people] + +# A reference list of all people associated with the project. +# All other sections should refer to people by their canonical key +# in the people section. + + # ADD YOURSELF HERE IN ALPHABETICAL ORDER + + [people.akihirosuda] + Name = "Akihiro Suda" + Email = "akihiro.suda.cz@hco.ntt.co.jp" + GitHub = "AkihiroSuda" + + [people.dnephin] + Name = "Daniel Nephin" + Email = "dnephin@gmail.com" + GitHub = "dnephin" + + [people.thajeztah] + Name = "Sebastiaan van Stijn" + Email = "github@gone.nl" + GitHub = "thaJeztah" + + [people.vdemeester] + Name = "Vincent Demeester" + Email = "vincent@sbr.pm" + GitHub = "vdemeester" \ No newline at end of file diff --git a/vendor/github.com/docker/go-units/README.md b/vendor/github.com/docker/go-units/README.md new file mode 100644 index 0000000000..4f70a4e134 --- /dev/null +++ b/vendor/github.com/docker/go-units/README.md @@ -0,0 +1,16 @@ +[![GoDoc](https://godoc.org/github.com/docker/go-units?status.svg)](https://godoc.org/github.com/docker/go-units) + +# Introduction + +go-units is a library to transform human friendly measurements into machine friendly values. + +## Usage + +See the [docs in godoc](https://godoc.org/github.com/docker/go-units) for examples and documentation. + +## Copyright and license + +Copyright © 2015 Docker, Inc. + +go-units is licensed under the Apache License, Version 2.0. +See [LICENSE](LICENSE) for the full text of the license. diff --git a/vendor/github.com/docker/go-units/circle.yml b/vendor/github.com/docker/go-units/circle.yml new file mode 100644 index 0000000000..af9d605529 --- /dev/null +++ b/vendor/github.com/docker/go-units/circle.yml @@ -0,0 +1,11 @@ +dependencies: + post: + # install golint + - go get golang.org/x/lint/golint + +test: + pre: + # run analysis before tests + - go vet ./... + - test -z "$(golint ./... | tee /dev/stderr)" + - test -z "$(gofmt -s -l . | tee /dev/stderr)" diff --git a/vendor/github.com/docker/go-units/duration.go b/vendor/github.com/docker/go-units/duration.go new file mode 100644 index 0000000000..48dd8744d4 --- /dev/null +++ b/vendor/github.com/docker/go-units/duration.go @@ -0,0 +1,35 @@ +// Package units provides helper function to parse and print size and time units +// in human-readable format. +package units + +import ( + "fmt" + "time" +) + +// HumanDuration returns a human-readable approximation of a duration +// (eg. "About a minute", "4 hours ago", etc.). +func HumanDuration(d time.Duration) string { + if seconds := int(d.Seconds()); seconds < 1 { + return "Less than a second" + } else if seconds == 1 { + return "1 second" + } else if seconds < 60 { + return fmt.Sprintf("%d seconds", seconds) + } else if minutes := int(d.Minutes()); minutes == 1 { + return "About a minute" + } else if minutes < 60 { + return fmt.Sprintf("%d minutes", minutes) + } else if hours := int(d.Hours() + 0.5); hours == 1 { + return "About an hour" + } else if hours < 48 { + return fmt.Sprintf("%d hours", hours) + } else if hours < 24*7*2 { + return fmt.Sprintf("%d days", hours/24) + } else if hours < 24*30*2 { + return fmt.Sprintf("%d weeks", hours/24/7) + } else if hours < 24*365*2 { + return fmt.Sprintf("%d months", hours/24/30) + } + return fmt.Sprintf("%d years", int(d.Hours())/24/365) +} diff --git a/vendor/github.com/docker/go-units/size.go b/vendor/github.com/docker/go-units/size.go new file mode 100644 index 0000000000..c245a89513 --- /dev/null +++ b/vendor/github.com/docker/go-units/size.go @@ -0,0 +1,154 @@ +package units + +import ( + "fmt" + "strconv" + "strings" +) + +// See: http://en.wikipedia.org/wiki/Binary_prefix +const ( + // Decimal + + KB = 1000 + MB = 1000 * KB + GB = 1000 * MB + TB = 1000 * GB + PB = 1000 * TB + + // Binary + + KiB = 1024 + MiB = 1024 * KiB + GiB = 1024 * MiB + TiB = 1024 * GiB + PiB = 1024 * TiB +) + +type unitMap map[byte]int64 + +var ( + decimalMap = unitMap{'k': KB, 'm': MB, 'g': GB, 't': TB, 'p': PB} + binaryMap = unitMap{'k': KiB, 'm': MiB, 'g': GiB, 't': TiB, 'p': PiB} +) + +var ( + decimapAbbrs = []string{"B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"} + binaryAbbrs = []string{"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"} +) + +func getSizeAndUnit(size float64, base float64, _map []string) (float64, string) { + i := 0 + unitsLimit := len(_map) - 1 + for size >= base && i < unitsLimit { + size = size / base + i++ + } + return size, _map[i] +} + +// CustomSize returns a human-readable approximation of a size +// using custom format. +func CustomSize(format string, size float64, base float64, _map []string) string { + size, unit := getSizeAndUnit(size, base, _map) + return fmt.Sprintf(format, size, unit) +} + +// HumanSizeWithPrecision allows the size to be in any precision, +// instead of 4 digit precision used in units.HumanSize. +func HumanSizeWithPrecision(size float64, precision int) string { + size, unit := getSizeAndUnit(size, 1000.0, decimapAbbrs) + return fmt.Sprintf("%.*g%s", precision, size, unit) +} + +// HumanSize returns a human-readable approximation of a size +// capped at 4 valid numbers (eg. "2.746 MB", "796 KB"). +func HumanSize(size float64) string { + return HumanSizeWithPrecision(size, 4) +} + +// BytesSize returns a human-readable size in bytes, kibibytes, +// mebibytes, gibibytes, or tebibytes (eg. "44kiB", "17MiB"). +func BytesSize(size float64) string { + return CustomSize("%.4g%s", size, 1024.0, binaryAbbrs) +} + +// FromHumanSize returns an integer from a human-readable specification of a +// size using SI standard (eg. "44kB", "17MB"). +func FromHumanSize(size string) (int64, error) { + return parseSize(size, decimalMap) +} + +// RAMInBytes parses a human-readable string representing an amount of RAM +// in bytes, kibibytes, mebibytes, gibibytes, or tebibytes and +// returns the number of bytes, or -1 if the string is unparseable. +// Units are case-insensitive, and the 'b' suffix is optional. +func RAMInBytes(size string) (int64, error) { + return parseSize(size, binaryMap) +} + +// Parses the human-readable size string into the amount it represents. +func parseSize(sizeStr string, uMap unitMap) (int64, error) { + // TODO: rewrite to use strings.Cut if there's a space + // once Go < 1.18 is deprecated. + sep := strings.LastIndexAny(sizeStr, "01234567890. ") + if sep == -1 { + // There should be at least a digit. + return -1, fmt.Errorf("invalid size: '%s'", sizeStr) + } + var num, sfx string + if sizeStr[sep] != ' ' { + num = sizeStr[:sep+1] + sfx = sizeStr[sep+1:] + } else { + // Omit the space separator. + num = sizeStr[:sep] + sfx = sizeStr[sep+1:] + } + + size, err := strconv.ParseFloat(num, 64) + if err != nil { + return -1, err + } + // Backward compatibility: reject negative sizes. + if size < 0 { + return -1, fmt.Errorf("invalid size: '%s'", sizeStr) + } + + if len(sfx) == 0 { + return int64(size), nil + } + + // Process the suffix. + + if len(sfx) > 3 { // Too long. + goto badSuffix + } + sfx = strings.ToLower(sfx) + // Trivial case: b suffix. + if sfx[0] == 'b' { + if len(sfx) > 1 { // no extra characters allowed after b. + goto badSuffix + } + return int64(size), nil + } + // A suffix from the map. + if mul, ok := uMap[sfx[0]]; ok { + size *= float64(mul) + } else { + goto badSuffix + } + + // The suffix may have extra "b" or "ib" (e.g. KiB or MB). + switch { + case len(sfx) == 2 && sfx[1] != 'b': + goto badSuffix + case len(sfx) == 3 && sfx[1:] != "ib": + goto badSuffix + } + + return int64(size), nil + +badSuffix: + return -1, fmt.Errorf("invalid suffix: '%s'", sfx) +} diff --git a/vendor/github.com/docker/go-units/ulimit.go b/vendor/github.com/docker/go-units/ulimit.go new file mode 100644 index 0000000000..fca0400cc8 --- /dev/null +++ b/vendor/github.com/docker/go-units/ulimit.go @@ -0,0 +1,123 @@ +package units + +import ( + "fmt" + "strconv" + "strings" +) + +// Ulimit is a human friendly version of Rlimit. +type Ulimit struct { + Name string + Hard int64 + Soft int64 +} + +// Rlimit specifies the resource limits, such as max open files. +type Rlimit struct { + Type int `json:"type,omitempty"` + Hard uint64 `json:"hard,omitempty"` + Soft uint64 `json:"soft,omitempty"` +} + +const ( + // magic numbers for making the syscall + // some of these are defined in the syscall package, but not all. + // Also since Windows client doesn't get access to the syscall package, need to + // define these here + rlimitAs = 9 + rlimitCore = 4 + rlimitCPU = 0 + rlimitData = 2 + rlimitFsize = 1 + rlimitLocks = 10 + rlimitMemlock = 8 + rlimitMsgqueue = 12 + rlimitNice = 13 + rlimitNofile = 7 + rlimitNproc = 6 + rlimitRss = 5 + rlimitRtprio = 14 + rlimitRttime = 15 + rlimitSigpending = 11 + rlimitStack = 3 +) + +var ulimitNameMapping = map[string]int{ + //"as": rlimitAs, // Disabled since this doesn't seem usable with the way Docker inits a container. + "core": rlimitCore, + "cpu": rlimitCPU, + "data": rlimitData, + "fsize": rlimitFsize, + "locks": rlimitLocks, + "memlock": rlimitMemlock, + "msgqueue": rlimitMsgqueue, + "nice": rlimitNice, + "nofile": rlimitNofile, + "nproc": rlimitNproc, + "rss": rlimitRss, + "rtprio": rlimitRtprio, + "rttime": rlimitRttime, + "sigpending": rlimitSigpending, + "stack": rlimitStack, +} + +// ParseUlimit parses and returns a Ulimit from the specified string. +func ParseUlimit(val string) (*Ulimit, error) { + parts := strings.SplitN(val, "=", 2) + if len(parts) != 2 { + return nil, fmt.Errorf("invalid ulimit argument: %s", val) + } + + if _, exists := ulimitNameMapping[parts[0]]; !exists { + return nil, fmt.Errorf("invalid ulimit type: %s", parts[0]) + } + + var ( + soft int64 + hard = &soft // default to soft in case no hard was set + temp int64 + err error + ) + switch limitVals := strings.Split(parts[1], ":"); len(limitVals) { + case 2: + temp, err = strconv.ParseInt(limitVals[1], 10, 64) + if err != nil { + return nil, err + } + hard = &temp + fallthrough + case 1: + soft, err = strconv.ParseInt(limitVals[0], 10, 64) + if err != nil { + return nil, err + } + default: + return nil, fmt.Errorf("too many limit value arguments - %s, can only have up to two, `soft[:hard]`", parts[1]) + } + + if *hard != -1 { + if soft == -1 { + return nil, fmt.Errorf("ulimit soft limit must be less than or equal to hard limit: soft: -1 (unlimited), hard: %d", *hard) + } + if soft > *hard { + return nil, fmt.Errorf("ulimit soft limit must be less than or equal to hard limit: %d > %d", soft, *hard) + } + } + + return &Ulimit{Name: parts[0], Soft: soft, Hard: *hard}, nil +} + +// GetRlimit returns the RLimit corresponding to Ulimit. +func (u *Ulimit) GetRlimit() (*Rlimit, error) { + t, exists := ulimitNameMapping[u.Name] + if !exists { + return nil, fmt.Errorf("invalid ulimit name %s", u.Name) + } + + return &Rlimit{Type: t, Soft: uint64(u.Soft), Hard: uint64(u.Hard)}, nil +} + +func (u *Ulimit) String() string { + return fmt.Sprintf("%s=%d:%d", u.Name, u.Soft, u.Hard) +} diff --git a/vendor/github.com/dprotaso/go-yit/.gitignore b/vendor/github.com/dprotaso/go-yit/.gitignore new file mode 100644 index 0000000000..21b201871f --- /dev/null +++ b/vendor/github.com/dprotaso/go-yit/.gitignore @@ -0,0 +1,15 @@ +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Dependency directories +vendor/ diff --git a/vendor/github.com/dprotaso/go-yit/LICENSE b/vendor/github.com/dprotaso/go-yit/LICENSE new file mode 100644 index 0000000000..7412f1c6d9 --- /dev/null +++ b/vendor/github.com/dprotaso/go-yit/LICENSE @@ -0,0 +1,19 @@ +Copyright 2019 David Protasowski + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/dprotaso/go-yit/README.md b/vendor/github.com/dprotaso/go-yit/README.md new file mode 100644 index 0000000000..28ebf14ec4 --- /dev/null +++ b/vendor/github.com/dprotaso/go-yit/README.md @@ -0,0 +1,54 @@ +# go-yit - YAML Iterator + +[![GoDoc](https://godoc.org/github.com/dprotaso/go-yit?status.svg)](https://godoc.org/github.com/dprotaso/go-yit) + +## Introduction + +This library compliments [go-yaml v3](https://github.com/go-yaml/yaml/tree/v3) by adding +functional style methods for iterating over YAML documents. + +## Usage + +Import the package +```go +import "github.com/dprotaso/go-yit" +``` + + +Query your YAML document +```go +package main + +import ( + "fmt" + "log" + + "github.com/dprotaso/go-yit" + "gopkg.in/yaml.v3" +) + +var data = ` +a: b +c: d +e: f +` + +func main() { + var doc yaml.Node + err := yaml.Unmarshal([]byte(data), &doc) + + if err != nil { + log.Fatalf("error: %v", err) + } + + it := yit.FromNode(&doc). + RecurseNodes(). + Filter(yit.WithKind(yaml.MappingNode)). + MapKeys() + + for node, ok := it(); ok; node, ok = it() { + fmt.Println(node.Value) + } +} +``` + diff --git a/vendor/github.com/dprotaso/go-yit/aggregates.go b/vendor/github.com/dprotaso/go-yit/aggregates.go new file mode 100644 index 0000000000..36de3cb321 --- /dev/null +++ b/vendor/github.com/dprotaso/go-yit/aggregates.go @@ -0,0 +1,25 @@ +package yit + +import "gopkg.in/yaml.v3" + +func (next Iterator) AnyMatch(p Predicate) bool { + iterator := next.Filter(p) + _, ok := iterator() + return ok +} + +func (next Iterator) AllMatch(p Predicate) bool { + result := true + for node, ok := next(); ok && result; node, ok = next() { + result = result && p(node) + } + + return result +} + +func (next Iterator) ToArray() (result []*yaml.Node) { + for node, ok := next(); ok; node, ok = next() { + result = append(result, node) + } + return +} diff --git a/vendor/github.com/dprotaso/go-yit/iterator.go b/vendor/github.com/dprotaso/go-yit/iterator.go new file mode 100644 index 0000000000..c117361864 --- /dev/null +++ b/vendor/github.com/dprotaso/go-yit/iterator.go @@ -0,0 +1,204 @@ +package yit + +import "gopkg.in/yaml.v3" + +type ( + Iterator func() (*yaml.Node, bool) + Predicate func(*yaml.Node) bool +) + +func FromNode(node *yaml.Node) Iterator { + return FromNodes(node) +} + +func FromNodes(nodes ...*yaml.Node) Iterator { + i := 0 + + return func() (node *yaml.Node, ok bool) { + ok = i < len(nodes) + if !ok { + return + } + + node = nodes[i] + i++ + + return + } +} + +func FromIterators(its ...Iterator) Iterator { + return func() (node *yaml.Node, ok bool) { + for { + if len(its) == 0 { + return + } + + next := its[0] + node, ok = next() + + if ok { + return + } + + its = its[1:] + } + } +} + +func (next Iterator) MapKeys() Iterator { + var content []*yaml.Node + + return func() (node *yaml.Node, ok bool) { + for { + if len(content) > 0 { + node = content[0] + content = content[2:] + ok = true + return + } + + var parent *yaml.Node + for parent, ok = next(); ok; parent, ok = next() { + if parent.Kind == yaml.MappingNode && len(parent.Content) > 0 { + break + } + } + + if !ok { + return + } + + content = parent.Content + } + } +} + +func (next Iterator) MapValues() Iterator { + var content []*yaml.Node + + return func() (node *yaml.Node, ok bool) { + for { + if len(content) > 0 { + node = content[1] + content = content[2:] + ok = true + return + } + + var parent *yaml.Node + for parent, ok = next(); ok; parent, ok = next() { + if parent.Kind == yaml.MappingNode && len(parent.Content) > 0 { + break + } + } + + if !ok { + return + } + + content = parent.Content + } + } +} + +func (next Iterator) ValuesForMap(keyPredicate, valuePredicate Predicate) Iterator { + var content []*yaml.Node + + return func() (node *yaml.Node, ok bool) { + for { + for len(content) > 0 { + key := content[0] + node = content[1] + content = content[2:] + + if ok = keyPredicate(key) && valuePredicate(node); ok { + return + } + } + + var parent *yaml.Node + for parent, ok = next(); ok; parent, ok = next() { + if parent.Kind == yaml.MappingNode && len(parent.Content) > 0 { + break + } + } + + if !ok { + return + } + + content = parent.Content + } + } +} + +func (next Iterator) RecurseNodes() Iterator { + var stack []*yaml.Node + + return func() (node *yaml.Node, ok bool) { + if len(stack) > 0 { + node = stack[len(stack)-1] + stack = stack[:len(stack)-1] + ok = true + } else { + node, ok = next() + if !ok { + return + } + } + + // iterate backwards so the iteration + // is predictable (for testing) + for i := len(node.Content) - 1; i >= 0; i-- { + stack = append(stack, node.Content[i]) + } + + return + } +} + +func (next Iterator) Filter(p Predicate) Iterator { + return func() (node *yaml.Node, ok bool) { + for node, ok = next(); ok; node, ok = next() { + if p(node) { + return + } + } + return + } +} + +func (next Iterator) Values() Iterator { + var content []*yaml.Node + + return func() (node *yaml.Node, ok bool) { + if len(content) > 0 { + node = content[0] + content = content[1:] + ok = true + return + } + + var parent *yaml.Node + for parent, ok = next(); ok; parent, ok = next() { + if len(parent.Content) > 0 { + break + } + } + + if !ok { + return + } + + content = parent.Content + node = content[0] + content = content[1:] + + return + } +} + +func (next Iterator) Iterate(op func(Iterator) Iterator) Iterator { + return op(next) +} diff --git a/vendor/github.com/dprotaso/go-yit/predicates.go b/vendor/github.com/dprotaso/go-yit/predicates.go new file mode 100644 index 0000000000..10589f27bc --- /dev/null +++ b/vendor/github.com/dprotaso/go-yit/predicates.go @@ -0,0 +1,117 @@ +package yit + +import ( + "strings" + + "gopkg.in/yaml.v3" +) + +var ( + All = func(node *yaml.Node) bool { + return true + } + + None = func(node *yaml.Node) bool { + return false + } + + StringValue = Intersect( + WithKind(yaml.ScalarNode), + WithShortTag("!!str"), + ) +) + +func Intersect(ps ...Predicate) Predicate { + return func(node *yaml.Node) bool { + for _, p := range ps { + if !p(node) { + return false + } + } + return true + } +} + +func Union(ps ...Predicate) Predicate { + return func(node *yaml.Node) bool { + for _, p := range ps { + if p(node) { + return true + } + } + return false + } +} + +func Negate(p Predicate) Predicate { + return func(node *yaml.Node) bool { + return !p(node) + } +} + +func WithStringValue(value string) Predicate { + return Intersect( + StringValue, + func(node *yaml.Node) bool { + return node.Value == value + }, + ) +} + +func WithShortTag(tag string) Predicate { + return func(node *yaml.Node) bool { + return node.ShortTag() == tag + } +} + +func WithValue(value string) Predicate { + return func(node *yaml.Node) bool { + return node.Value == value + } +} + +func WithKind(kind yaml.Kind) Predicate { + return func(node *yaml.Node) bool { + return node.Kind == kind + } +} + +func WithMapKey(key string) Predicate { + return func(node *yaml.Node) bool { + return FromNode(node).MapKeys().AnyMatch(WithValue(key)) + } +} + +func WithMapValue(value string) Predicate { + return func(node *yaml.Node) bool { + return FromNode(node).MapValues().AnyMatch(WithValue(value)) + } +} + +func WithMapKeyValue(keyPredicate, valuePredicate Predicate) Predicate { + return Intersect( + WithKind(yaml.MappingNode), + func(node *yaml.Node) bool { + for i := 0; i < len(node.Content); i += 2 { + key := node.Content[i] + value := node.Content[i+1] + if keyPredicate(key) && valuePredicate(value) { + return true + } + } + return false + }, + ) +} + +func WithPrefix(prefix string) Predicate { + return func(node *yaml.Node) bool { + return strings.HasPrefix(node.Value, prefix) + } +} + +func WithSuffix(suffix string) Predicate { + return func(node *yaml.Node) bool { + return strings.HasSuffix(node.Value, suffix) + } +} diff --git a/vendor/github.com/go-playground/locales/.gitignore b/vendor/github.com/go-playground/locales/.gitignore new file mode 100644 index 0000000000..daf913b1b3 --- /dev/null +++ b/vendor/github.com/go-playground/locales/.gitignore @@ -0,0 +1,24 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test +*.prof diff --git a/vendor/github.com/go-playground/locales/.travis.yml b/vendor/github.com/go-playground/locales/.travis.yml new file mode 100644 index 0000000000..d50237a608 --- /dev/null +++ b/vendor/github.com/go-playground/locales/.travis.yml @@ -0,0 +1,26 @@ +language: go +go: + - 1.13.1 + - tip +matrix: + allow_failures: + - go: tip + +notifications: + email: + recipients: dean.karn@gmail.com + on_success: change + on_failure: always + +before_install: + - go install github.com/mattn/goveralls + +# Only clone the most recent commit. +git: + depth: 1 + +script: + - go test -v -race -covermode=atomic -coverprofile=coverage.coverprofile ./... + +after_success: | + goveralls -coverprofile=coverage.coverprofile -service travis-ci -repotoken $COVERALLS_TOKEN \ No newline at end of file diff --git a/vendor/github.com/go-playground/locales/LICENSE b/vendor/github.com/go-playground/locales/LICENSE new file mode 100644 index 0000000000..75854ac4f0 --- /dev/null +++ b/vendor/github.com/go-playground/locales/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016 Go Playground + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/vendor/github.com/go-playground/locales/README.md b/vendor/github.com/go-playground/locales/README.md new file mode 100644 index 0000000000..5b0694fd19 --- /dev/null +++ b/vendor/github.com/go-playground/locales/README.md @@ -0,0 +1,172 @@ +## locales +![Project status](https://img.shields.io/badge/version-0.14.0-green.svg) +[![Build Status](https://travis-ci.org/go-playground/locales.svg?branch=master)](https://travis-ci.org/go-playground/locales) +[![Go Report Card](https://goreportcard.com/badge/github.com/go-playground/locales)](https://goreportcard.com/report/github.com/go-playground/locales) +[![GoDoc](https://godoc.org/github.com/go-playground/locales?status.svg)](https://godoc.org/github.com/go-playground/locales) +![License](https://img.shields.io/dub/l/vibe-d.svg) +[![Gitter](https://badges.gitter.im/go-playground/locales.svg)](https://gitter.im/go-playground/locales?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) + +Locales is a set of locales generated from the [Unicode CLDR Project](http://cldr.unicode.org/) which can be used independently or within +an i18n package; these were built for use with, but not exclusive to, [Universal Translator](https://github.com/go-playground/universal-translator). + +Features +-------- +- [x] Rules generated from the latest [CLDR](http://cldr.unicode.org/index/downloads) data, v36.0.1 +- [x] Contains Cardinal, Ordinal and Range Plural Rules +- [x] Contains Month, Weekday and Timezone translations built in +- [x] Contains Date & Time formatting functions +- [x] Contains Number, Currency, Accounting and Percent formatting functions +- [x] Supports the "Gregorian" calendar only ( my time isn't unlimited, had to draw the line somewhere ) + +Full Tests +-------------------- +I could sure use your help adding tests for every locale, it is a huge undertaking and I just don't have the free time to do it all at the moment; +any help would be **greatly appreciated!!!!** please see [issue](https://github.com/go-playground/locales/issues/1) for details. + +Installation +----------- + +Use go get + +```shell +go get github.com/go-playground/locales +``` + +NOTES +-------- +You'll notice most return types are []byte, this is because most of the time the results will be concatenated with a larger body +of text and can avoid some allocations if already appending to a byte array, otherwise just cast as string. + +Usage +------- +```go +package main + +import ( + "fmt" + "time" + + "github.com/go-playground/locales/currency" + "github.com/go-playground/locales/en_CA" +) + +func main() { + + loc, _ := time.LoadLocation("America/Toronto") + datetime := time.Date(2016, 02, 03, 9, 0, 1, 0, loc) + + l := en_CA.New() + + // Dates + fmt.Println(l.FmtDateFull(datetime)) + fmt.Println(l.FmtDateLong(datetime)) + fmt.Println(l.FmtDateMedium(datetime)) + fmt.Println(l.FmtDateShort(datetime)) + + // Times + fmt.Println(l.FmtTimeFull(datetime)) + fmt.Println(l.FmtTimeLong(datetime)) + fmt.Println(l.FmtTimeMedium(datetime)) + fmt.Println(l.FmtTimeShort(datetime)) + + // Months Wide + fmt.Println(l.MonthWide(time.January)) + fmt.Println(l.MonthWide(time.February)) + fmt.Println(l.MonthWide(time.March)) + // ... + + // Months Abbreviated + fmt.Println(l.MonthAbbreviated(time.January)) + fmt.Println(l.MonthAbbreviated(time.February)) + fmt.Println(l.MonthAbbreviated(time.March)) + // ... + + // Months Narrow + fmt.Println(l.MonthNarrow(time.January)) + fmt.Println(l.MonthNarrow(time.February)) + fmt.Println(l.MonthNarrow(time.March)) + // ... + + // Weekdays Wide + fmt.Println(l.WeekdayWide(time.Sunday)) + fmt.Println(l.WeekdayWide(time.Monday)) + fmt.Println(l.WeekdayWide(time.Tuesday)) + // ... + + // Weekdays Abbreviated + fmt.Println(l.WeekdayAbbreviated(time.Sunday)) + fmt.Println(l.WeekdayAbbreviated(time.Monday)) + fmt.Println(l.WeekdayAbbreviated(time.Tuesday)) + // ... + + // Weekdays Short + fmt.Println(l.WeekdayShort(time.Sunday)) + fmt.Println(l.WeekdayShort(time.Monday)) + fmt.Println(l.WeekdayShort(time.Tuesday)) + // ... + + // Weekdays Narrow + fmt.Println(l.WeekdayNarrow(time.Sunday)) + fmt.Println(l.WeekdayNarrow(time.Monday)) + fmt.Println(l.WeekdayNarrow(time.Tuesday)) + // ... + + var f64 float64 + + f64 = -10356.4523 + + // Number + fmt.Println(l.FmtNumber(f64, 2)) + + // Currency + fmt.Println(l.FmtCurrency(f64, 2, currency.CAD)) + fmt.Println(l.FmtCurrency(f64, 2, currency.USD)) + + // Accounting + fmt.Println(l.FmtAccounting(f64, 2, currency.CAD)) + fmt.Println(l.FmtAccounting(f64, 2, currency.USD)) + + f64 = 78.12 + + // Percent + fmt.Println(l.FmtPercent(f64, 0)) + + // Plural Rules for locale, so you know what rules you must cover + fmt.Println(l.PluralsCardinal()) + fmt.Println(l.PluralsOrdinal()) + + // Cardinal Plural Rules + fmt.Println(l.CardinalPluralRule(1, 0)) + fmt.Println(l.CardinalPluralRule(1.0, 0)) + fmt.Println(l.CardinalPluralRule(1.0, 1)) + fmt.Println(l.CardinalPluralRule(3, 0)) + + // Ordinal Plural Rules + fmt.Println(l.OrdinalPluralRule(21, 0)) // 21st + fmt.Println(l.OrdinalPluralRule(22, 0)) // 22nd + fmt.Println(l.OrdinalPluralRule(33, 0)) // 33rd + fmt.Println(l.OrdinalPluralRule(34, 0)) // 34th + + // Range Plural Rules + fmt.Println(l.RangePluralRule(1, 0, 1, 0)) // 1-1 + fmt.Println(l.RangePluralRule(1, 0, 2, 0)) // 1-2 + fmt.Println(l.RangePluralRule(5, 0, 8, 0)) // 5-8 +} +``` + +NOTES: +------- +These rules were generated from the [Unicode CLDR Project](http://cldr.unicode.org/), if you encounter any issues +I strongly encourage contributing to the CLDR project to get the locale information corrected and the next time +these locales are regenerated the fix will come with. + +I do however realize that time constraints are often important and so there are two options: + +1. Create your own locale, copy, paste and modify, and ensure it complies with the `Translator` interface. +2. Add an exception in the locale generation code directly and once regenerated, fix will be in place. + +Please to not make fixes inside the locale files, they WILL get overwritten when the locales are regenerated. + +License +------ +Distributed under MIT License, please see license file in code for more details. diff --git a/vendor/github.com/go-playground/locales/currency/currency.go b/vendor/github.com/go-playground/locales/currency/currency.go new file mode 100644 index 0000000000..b5a95fb074 --- /dev/null +++ b/vendor/github.com/go-playground/locales/currency/currency.go @@ -0,0 +1,311 @@ +package currency + +// Type is the currency type associated with the locales currency enum +type Type int + +// locale currencies +const ( + ADP Type = iota + AED + AFA + AFN + ALK + ALL + AMD + ANG + AOA + AOK + AON + AOR + ARA + ARL + ARM + ARP + ARS + ATS + AUD + AWG + AZM + AZN + BAD + BAM + BAN + BBD + BDT + BEC + BEF + BEL + BGL + BGM + BGN + BGO + BHD + BIF + BMD + BND + BOB + BOL + BOP + BOV + BRB + BRC + BRE + BRL + BRN + BRR + BRZ + BSD + BTN + BUK + BWP + BYB + BYN + BYR + BZD + CAD + CDF + CHE + CHF + CHW + CLE + CLF + CLP + CNH + CNX + CNY + COP + COU + CRC + CSD + CSK + CUC + CUP + CVE + CYP + CZK + DDM + DEM + DJF + DKK + DOP + DZD + ECS + ECV + EEK + EGP + ERN + ESA + ESB + ESP + ETB + EUR + FIM + FJD + FKP + FRF + GBP + GEK + GEL + GHC + GHS + GIP + GMD + GNF + GNS + GQE + GRD + GTQ + GWE + GWP + GYD + HKD + HNL + HRD + HRK + HTG + HUF + IDR + IEP + ILP + ILR + ILS + INR + IQD + IRR + ISJ + ISK + ITL + JMD + JOD + JPY + KES + KGS + KHR + KMF + KPW + KRH + KRO + KRW + KWD + KYD + KZT + LAK + LBP + LKR + LRD + LSL + LTL + LTT + LUC + LUF + LUL + LVL + LVR + LYD + MAD + MAF + MCF + MDC + MDL + MGA + MGF + MKD + MKN + MLF + MMK + MNT + MOP + MRO + MRU + MTL + MTP + MUR + MVP + MVR + MWK + MXN + MXP + MXV + MYR + MZE + MZM + MZN + NAD + NGN + NIC + NIO + NLG + NOK + NPR + NZD + OMR + PAB + PEI + PEN + PES + PGK + PHP + PKR + PLN + PLZ + PTE + PYG + QAR + RHD + ROL + RON + RSD + RUB + RUR + RWF + SAR + SBD + SCR + SDD + SDG + SDP + SEK + SGD + SHP + SIT + SKK + SLL + SOS + SRD + SRG + SSP + STD + STN + SUR + SVC + SYP + SZL + THB + TJR + TJS + TMM + TMT + TND + TOP + TPE + TRL + TRY + TTD + TWD + TZS + UAH + UAK + UGS + UGX + USD + USN + USS + UYI + UYP + UYU + UYW + UZS + VEB + VEF + VES + VND + VNN + VUV + WST + XAF + XAG + XAU + XBA + XBB + XBC + XBD + XCD + XDR + XEU + XFO + XFU + XOF + XPD + XPF + XPT + XRE + XSU + XTS + XUA + XXX + YDD + YER + YUD + YUM + YUN + YUR + ZAL + ZAR + ZMK + ZMW + ZRN + ZRZ + ZWD + ZWL + ZWR +) diff --git a/vendor/github.com/go-playground/locales/logo.png b/vendor/github.com/go-playground/locales/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..3038276e6873076ecd542099e95b25037b1c0c34 GIT binary patch literal 37360 zcmV(-K-|BHP)ysx*JK zMpBX=dbK}5gAy}y3R{{beYQe$t~_(EI9HY=983!yQ4BbH2t9fee6m7kr7b^x7%_4X zJ9`gfp(=T?K~s?>F>nbtbqz;?9&D*HLWLAVf)p1<2qIzzh`mlUaSo2aQfQ+xioj4u zi57RSK09+4J$n}=VG1>K6C+;`IdT#dKnQiRIYfOMa;!RRrZpi|42HT(K7kH5Z51D0 z2RV8bBU%zznI$e~3~;G9N{kpKWf73XRDQWdPL3KgZV)nR5J7tvJAVu-VG5JQScJDo zR+bL!Ta3IbT6ncoYNbC?j4!6pWoxTBl*n#=wPJ6nPG_V?T&y%kcr-zED1W(DRHZFT zhB7~qA6u3+V3JBCZ4gs{L}jKoF=`!luS|!&X@DUWZdUYba2WIU7L}XOvil!bU7wAXuO|PIN?OtwU_FF?ptGuGegAxjs8(G9yYG zg|%{%%2R#1JvUt~pwDwIP%5I+ft0_2vEYw`$yQ3QA)Db+A{7b_0054wNkl}YE}wrc9DS+rDCwcq-kLn z6*rr9Gievg)&9W#+|En4X(tdH=fj-$InQ~{3w3k;I<^V903k*-k%?L`+gy zD<80`%CcVCt7&b)>-AWo}M*k4L#h*SN=*WN=wOPGQCc(S19x{GH}}yZ*TGF ziK2LMaUoYPF2r$dT&q?u0Q}(MpEI#8)^7>wy*j~dU6yeGL|G)4Z!`D?6v$J?4GNiF zGNUM+N-|jqFSt^;^pX20u^KaC*wKL1)CJS$%Vk@iEmQRU!98y?czh5h263h#&UI8G~>;F&}3tQ$@xhmG@h5396##KW2c6&nD-->t* zzH&?cgu?c})WwUscng4f{a@;`oGHloVP3&K8 zYWaY-m3_Qz=Z77^NgMadOSSCt@E=Ps4GgQlTkY0kAe~EC|Lpg z0C`J&DPN2UyU7&Gu-tM7^CfvM>!_q$|F7zV-={;NRk*zX^&Xy|sN>Mfv~agPsrszZ zST{=H##(12j$1JtBfT5p%`HZ(R~kw8ecKQFg5WJ*x&2m`V}}Y*yZ+#L(7tQhrOc;? zl-q4QvB#(*`_Y3X_Vss0x8Fk3#a~Y$nt>$Qn2*D~V85{yB8iQ{r9&gU|I zev9S7uL8Gt)I|dF=Y>|QegWzPvP@{V3Nn!IR4VydvXh@BKI2xUMBh(6aBL~@%r!AuWVG?f=&mJDxzGOktCLsq`D9Be0N@V+ zw0ap7DLEZtMdX4AhRfVstkov-f;^PxlkxbXr%Y<&X1CewisGbJ`y`1>y^eD%RgLHX zYcVG7w{0ENyVVm($?-3NBx$ln5*EKMtyUbD4wv+JlvSVUD^3~+YL43}RqjpaZ>3ze_N$kOC+VOY{hW+5B@jP%seQ7^>9XbyLO_reD=`#sdf2i+$u9o?M zdc~#Q*=#JUW~0w|6Dzl8Ec<(uJGK{c1uP-ECFnFoEcE?p>b=X@zgJgrNs7N?y_(l62vH_2aOTu; zH1Wkuhrd?fG^jc{yVoI7S9+u_MCut_7!Id3v9PUUb&ldf@7>y_JFay%O|e@o7B~1R zR>f}jzhMAekSBme7+=8B<$4CP2M`qy9;PHYV6Jyi@gzzQxufnYeT4}(ia$$dqsPwU z5sO*J_umWFSAy&Qz_!oZ_MFx;KV|fIOpaJ^|IlRj`#mo`7L%L${sFWDr)GmSX15!x z-ju0rqgjo2_ERjgP*qK!X^q!LX;y>Hu?d|?f1KrU_f9eo=CJlH^$aSqrQQSef(+VI zC|ev?=iM66d@OdmUC?cIyVcDG)WLl$UUUh>iAb>R_igW2u?(N61L7?ic^SATn9E7n zNxqRMszu^JF zAl2kMNq7&8r$ZVW%4{j9Mn@?q+c73i$N&u<3-i9;kLlEE%cl5$T`V6CkTnyOJ+mDaOaDWQ*^ecn!U$EDGLmsW}B zARh3Q)rAo6JL!FggZ3F6jy>B;&&!jW5FMg-Pfri`&2I0*$r<%!@Z{{~#$u(6L5tIC z^ct$p<0cjz2bs`3+o&=gg zN0I9tG<<%Iswa`AOAJdUZZ^xs-z{*A5120pqimm1%e$$8lj2Rz-5n3_^+!xU`FD3; z?p{7vc6^8QYfHemZ=l>~d!hFs`#E}j$4Ogk{OLe2Q=08L;!#{n!QPLNUsaV8bX6T_ zoZeWG8?W;fL^?9qw}QvFOlz1NW~S4EBF|xQlOZ}B-97Er#?yIiJSVn3uGPB5yDgsX za>d8T9K^q@j<*wkQ>~J@2auzPFOmx}x0!EFdB9!yU9WwxvgjR&?#kfg)Re^ zU-wz6Z!-%j`#HxBkmxujd;G3VYpX;y0Xtz}E(t{V$~uW0lOc^)=|GS@GK+e7MHx=# z!*RE|?AE3ejI;Sv?ZxLMm2b0E0P-M#%6ch}d~Pk7{t#OF7gYEvW_6V_EC`1%sm z;p`;DqvO$3nU9KswqGY#rE*CRhZCi6Vg+4BzY4?O1Z^=|F|5~1w-IQ|ecyr0B;3%> z6NBS&$4u{pLhhSaJ04eT@6<#cQlX#RA=lns%xy$Iav8;|8b2CeW=l2{s^~`vfxD{}nt5yRf<*f`crJol5KDpU+ooq#9&8 zolytKS$vp#7S*yGSBhp|TzSfi1;>|pT8b=!z8&|j&*(e&+8TUqFrCtl8|%?a$FBL@ z{y>@BXE$djM^uFJTU_rioz{q{e5Fbf#|)xZ>^Gwk$Huc-c9m^sKiA@Euns4o_3#?h z5i=0rkge;=Umc~s?o7dWGHh16c;nOB7RtO!P^{%PB)h}wuHU|SgU1_E^|#l+Q}qdS zH#zt}!9}+!7OMbK0D7Km3rMzut~&X`M`exqrYM-~VVJwhgjJnk7U?*AzI_a9V$zJD zYHhE&WAk}!5pOwiZ;S039$dytin18|FPwW+$P$X}!sSCocO(=%2_8{qAMNLT)*Y5M ztEsG{FE zcd6Zz*ty+c+4me7W7MhL5el9=Tt?^XuMb_;vSwBV%E_{HLRF>yV3AH_j|HcTm^;>a zvC_jO>{*oxChK<3CbtTePO|dXP!_ATF7#edCex`hO``srW-Zsv6_-_5+@v|i8We%Y zyMIuG>bHs?7YPXYC-gp6qnLxi$pt8CqEy8~wN7FkrU^!Uudp5tkYr|StbYSr7gfDV zsM%*}B(Tv6Atx0*<3}nIIDfx$@1=y-X3vRdKeE41dk)V6r>|lW>)}zv|MC*Fy`WVDgB%|{yeSf>k=9~(Lk%M*Vv}w0f(3C@}$xW z=X;gp5Q-lcaybmN2}XLiG@bn1#U(Pt?#M*{@CI`K@ZrY~KmPdP15Q4?y(75}eD891 zC_7n)=49M0h?tLJO|BA$D3Dz}f!wJx7^$#1Y~R+{IWt^h(BQN*7k{Rg64=2xqpssD zn`W{H_xI(6YZSCPV+TC8tNs^9A%it&I(jN+PxAE94F2TRn(Smgm^H4&{6j33fOh zZjjt+-FdS%$#sj9&A8U=j_334usFvB82#hjhsQtOJig5p-xephIDsOb#>Knora0d; z5&SmI<#x`^b0pP@Q&HaT3K3^9*D>9aop88;9J?Or>4dJ6EzBUTMqjBY_GmR4Fe6FO z3~ldwf$o=IUERAW(~Wh{VsiKmmaF?;oDlu_3w%;_Zb7fRgLaG6Y~wF^?Tgs-~d>j&DCZN@>`>j_xTR{}t_f9U)W2S+R648V8hb{3Dmp813n?7e z6LF4tmd&OUt5Qilew8{x$Uy@An?-AlX{&(3EiElA<#AhfOL=T557!owu4yP~DebPa ztx)PswzAR!84X=8C4fe0x=1Ru)JJIjfz$+3Ov@v(L?jKOMvF@vC=8ABl}ra>#Kgob zYE1lL)E|Bqy)c%ACEK~@obP-O%4%vKqpYuMEaDb% z>Xe*wLNU)%FK*z7Jri6>qYAqoQ~6u3ywE}DD8MH{89OM0G^)dF;hsksFBVOkXtT0L zA)0_y?A`NfeW$BFX`cjk;gmBhQ?bvFCP#gkc*f;o0ClWv2_(_=U@$V0blZKCc3>Z- zBH*?Mrjtn*NIp28+w$lrc+K<-%I$&t#c9`?SWEITs|_o5YRdX)Clyr@1azy>;plKs zILBxE2xv?d84A5>{!r^s^r5BjTb85%_(J2Zgm{-@VQR0h$oiG zruagSqDUa91*Hjf5jbT!=~D(dN$Ax^u%=i_N2ScHLF4s8w)Nt}WP($HD+eob4+B3P z2EH?PEIFp0@qxWyt=$peI9dq>gRu@o0?Cm`BpwOQCWH9i=%n2qna56ySnw)tT9SZx z7W;3W%9&~C7}KMVF^|Hnz%@C&C$MdCP+=BOb8{&*LJl6^&o&ZZ4|lRKcdWUR5qED&dJGwX)i)6B?n$ zOosG;3l-6!Kd&dR7|)UkH5H9Iqee`1;=ypJmBx9KQkSgDkU6M&@Vi>>Nx#3cdf>G)y~J z&y#G)I3rK8{v8dNM(U#AD~htsQ86ORxE5|0tFhji;NKFrW=+J=$c#L1JJ;M3Mo_yeqOj zI*IXjLAHKtzljb9u;77UFc6Gj1l&oB<)$6oo{t240gG#7-W|uHxO+xnbWFQPvFn(8 z06vU5$U{urHQalQn-%>gb9(cFpCbKaOy_`aLnc}uni3iZLGy;BwGx#%B&?Pz`TT~< zFIEW7G%Cug1j7}YPEPZslA;&+91*slk5kMm7b`V6lCvX`*`#a40zeNW<2d^Ek(+jmJ02821OEzy2yukV2AJ!GIcxE4Ry$&BNVa08W#W3>t(6_>z^&514EIOeh48)L8Is~0v&gIH(NED?41y597-PtVe ztf&wb7hftBovGq@#uW{fb@gJ6a7rT=iAw}xLt+TXNf>nJ_2#p+1oW!jxIpLhY~ImD z)3g=0m8H?JDzsiy-{OUD>}momhezG8Bi!@ho?h3ew`JS6?XyoO?MX`{Ih#D(y!*>9 z+lTvccHUpd#|p+Dy$89$(8o`yZD0gi7RQifvXf1ZYH!*`dtl5$w6P=Kgt*4kqBS`k zZ87L|XlFX4PEgbw;V@nSjrSXf1d#yj8;QQY>e`_$saY=MD$1%SN@bU1&CUD<4__hV z);A6)J(s#KahiuakvBoOl!z)MwHkBvl!nWJ!}XfO2yB<)O8EN?dLu~@C>lNY(lkk7 z%>nDC$81b5fCsm>ZD!Jk+96JX>F(s=w?{|5h$UdRj7(eX(}C@~J3Bka`S;#<@4-$0 zs&(!CIG#W-fb9;T-S`X!lEL|TOC(^QwOb;}TLyyISCYV#&QNUdD#Y z8cn6pZ6c?m`rBi=tFajL1t5>Cl`71}b}+o5E}^8lt4sD`?W>%+@rl6-nShT&4y3zu z8==dP>3Wy1BO2Ja{(tAGGVi5@LkIAJwZ<;7?X>ZyThF6J~`Y z)dCX%APghL<^pjCuKBRackk|hcl*w*Z@=B1Y#ROVdfolx?VXeNj^BImX<_HkJrc05 zj6_zF$ys;A9uG$1zIf2h-uU^X9kUJ%=Y~_m(xIEDwiTcqN6i|B)e9EEdXumwL8`1& zMpfH^;0e_3JWWwVDArE2OAW1aF%rh2G&ZEFl#M;DktuGJb$6dB@|-KL@Kn@^M9re{ zhQ2{g5qM3txY(o6C^cf4CS(u*89P+chm7aXN)cmGdP*JDJM<|%kEnDhfBfDX$0tW? zAoA>p2jW0=7V%I26rcSc=fUTpc+l`3#xgzGV?*%LG};1-3g@H=8*c-DhDDXIB6tJT zr5tkcWhiB#^XZIIm1NVpA^G9I5_BDio#spM7E7oU-V+LUlO z4fsyEh|j4W6I6>PM6!tv%1n_lIQmi&c7>6|9Ca9}s2ai{ipE?0aO7Z*GreB;q7}Kubavrj@AubsZ=XzW9AwkkEC&9KH}c1afW4b6*s)YD zhzARg)~`io0r_Y>i}1b~@L*74Bok~L#RinfAsDTdZgXPfuCWdqal^+`jaeh0fc2EuRfs}21N(Wucufk-eWo4VJO@TRbITCj|;iwPI3 z1%1Yu%S>+Uj_#b?-A|{dJj<)ku0H$4Zl-X1=iueT&4a0Qb}4_nxpU{>zRwbAdjF<< z#WKHQ58~KI;_j8Wdln22EEd`Ybk;qCgE(Vx2Uwi%VY4XQ&o){M|Jww}ga41D8AfPS z?I8TRJ~BpuZRphiB&omMIA}Ds8;H;i5Lu+{;Ka8 zjzHW{*EtRfFB|KtmGEwu`yh75Nb^Gp74AB28zK&*j9pPZ%7bJ@@?b*5*6VF)Q!{j1 zrjWUp$=qZ1!h0^)^ufu4^won0X|z54$mY8{yE~t}a_9bsZ|~g7ZebR_Iyzcgiv%od zcaKu8;0m!87n4#^Z#FKMQfWtRskx*I$t7X%HQl4ee4k?0&e z=jqeVA`sR->zDR%cc6xa!o83J4WaIv= z{lK4_CvT$6wfO%!W{v%f2UphcLfC<~!^gFQ9AVd4mlB>&3+5|)&BSD)pGK6meIzMVeKuIEwv`uggJnf^Ohf13E{t)+ba?R@_D_&E3A)6YNu z^ysf&e*Ja-@XcUwWn?A(=IqFdeFdLEh?*oT)+27;G<=(x86f;=BnSLtv>3QV8w%H+ zhS|tl;Y{Msbd=PO>4$0_A}KXqfjUNz{&tn>s+15Cp{^G>!m)|2nu!<7#v7h~y1t}@ zgIzBwI#=H~F)+Ys7}xN)-P~#cU(A**htCpJGhxb^JvD-(;$%ZrQ4 zi_7cl>)HI$`X`4=U*>N^qOQ$Dy{)kpWn>KxJM1GEe0*giNtE0(ZFeEBvuW|dZB{1S zW`j3ysvg*c4_${NONQp=q;SVCrocl~p^!?alU})qyDl}io8dRr+z@k1U*ai;i_cUP z^AwGB^^GNEobK*tlurZUmG#XR_`C|vm|Q9y>{6A14n9m0=hcMKK^sxOns(03MF}Iq zCMOMp4C2KG-N<-p#u3eAavO!rwM?N<$lUt=+uM7)Ki#_XRXV-y`QejyKYM<4@fDQ4 zwY8OAPN&n^d_JGu-vG|<2iPmdmdS267~Rpz>8>BHS?qyP-@MB`13y#S(*oK69Tdic zFQ%}~i_5OH0`Gu&=sK-tX{?HN_#Gr9y2{)N8QX3oC>g| zXU$OB6#RcscMw^Kv*~O17!*%$4sSn5uWzm2`tIvzpMB-o)yEfC zS5f@(@_KrG=}X+UU-EC{ckGr~cYMSi4bSp6msiLj;2dNjDu$sapwhfG|r#9TaG%npBZ&Y*wR__7PL^>hj{! zhSJLC#F_~K`?Cb1649CKGA>W^Dn~F;<|(Z&;_&32b|L?&+{`hD&N})jI)!MX7MB9v zR3?{!M5FiFNgC)>ByvrE|@PjEy=b-Tkq=Zw-B>wiqn3eAY9GuJ=o(q0QQg?kxmfzA}X_tOpOcW>u!zq_>b<9Ej= z7Z0|+$A+(>7``SsB%8%S6Mug<@ z_U9@EFYy)QV*D)4_2>9iMUC~B&+v=OMM{oLSrRVcs=E3IjZ#=mB^Nc-+X^+f;%C7}i4*&k=@UQ!y7VZb!M;2H&tOT;d zwMPWun}j;R#Ggt87z6!nY_{I(@M>WRTQTe@u-SzaITqDjA+8{EBM`W%DN03v>$DGP zifYEMOpS9C7rKjh`~gKV3WZ=99;hm+;*^x*qhU-bn;N?!mlV~6Zs_}U3u*{Kf1g8Y zq;pmr5gNr)>`zieO;)XyO@7pLKdsJWG8;hn%*Izge3X0b?caV#FMsq00PWqomS2C} z+xbGXzP069U*BTez78Ubw&$~7qI4v2kSKQh2nIe7S-E>}XXCHKjeQ^%@n(GN~bst8Gk zv^}ON<(3z7J={vqAV(uB?<{{+R54s!RD8MnOgX1iQzkA`@I1V+=7(idax=-rt|zDj zJh*yJoj9WS#cr^YO)|G@n$Hd23R`dQppMU!KCx7lAjU0~Lv><~( zR)y4#fw}FPoUC%e?Fg^z+?p<}J=66#)ITdnb`Ybn|1SX6^|F z&1eSc=uzx}EzriYEwckj;no(|Elv)0PS#iq2J7g)*=n=vW(p~)kVGnWb#Wv6F%bd$ zL69v(G6ly$BNz&S4>b;g4Vqg3OqO|ZVwhnD1^PIVIbg8Uq%2<6ESr_LUMzQMhA&<; z)Xpoq+9Ao|YQF{-9GKxzyYJk1xGO0Q07&TG`2bdNVU1f_U+P?6`l_Kd79t@Yc&Icu zD7M*H4$R%_dFry)->(J86Uv+rQ1}ReP!JKs1Vzhn;K0ctArSPA36XVd#!f=APZ%wj z%%U>@qpM>uf?baWM&Yunu|TzziGgJ`PGTbb~05fO#S>Cx;DFzWV-e>SdLCJx8S}7zx{Zv{UQYY#S7-kNwt?-Tcxc@T!3r2Qs8377nzGH zE}xqZ#SaEJ2zbD;fq{At;{A10mGp5?Z9qgk;6j`a(4G!`4L**?F`=2EkOD&gjF6d1 zW`s0>XgGus$)eK=pj;(0QbdemLap=wn;Qu>uAAbmzLy_ODPtXjj z2lIsT1+B1C|4=caxpjATJ>o-Cd)I{@Z~f=>c3535La-0az;#tS-t&?Vg}s4`f>aV2 zd~A%bk3-})yi(XCC7~Q7%2Jodmx16euPg}I*0LZ7`~Xx?0dfXF$38%nb7a3LpWMP^ zeB6lw@^Q%e$T~k_fe$S*B!n1=_uI3V;ep#^>w>p;am3nStT65XKSz7)b)sUeQyi%n zM^f@$yq6``$>bqgGPJ9KL|34T?Z$8jBLp*nNlsvcCK5J+gph;~IzmMJ{MeBRad|LE z!NN;c9ut|O7`J%~u;~JdyF4XJjCU*y*3OG0J z44B5#e#xn9h)t8kN?T>XNz^XQgVUuFAf?cmJ|FnF%CDf@)h0n#Q%~z^UoXpp?p_-Z zP%D707NPw5p*%#a;bN; z2Tsue6a{-7FwR?TtZWWYx42_0tSDRdkQ{+w##p!(6xK!hve^fjG#WdM+!PnVgdhhk zE=Lr~q0>U?en>>X#|e2bO~URRFlKtNYSac9mSf{P7ss_P=3XqkP|n?6n=%HdYv)Zc z&p^Q6ZHIa0;dZ(b>F&mOZZkQrn$Z-#l9Fvq2PU7!x+xN z082&|oIuENO)P{(rW2Z=)FT`=B80IHA_2-CCn16W%4A_)xoJ-QXPa?;_K{9#?C&2m zDM!@mGPQ9eZR}C}eWSu)FkQRVbqgB%H7IizFW!Km2Cj833PATr_zk0A?x>V21vnaI zX29pL$w0}^IW&LhP-|XVUfKK$W4lf+hg}`+k89ugEl9nn))s$_y<2~7QXfN)D&!Qh zXe)_?( z<V}u8invj{s)^GKhDyeJdBx z15F*R@B2SBSw0!c}C!c-R)*O|2u#nh76OfxS zKncajV1S;c7*9$8B{bE^!`ssX>tt1eLQEk(^&sYU^*>3Jn61DZ}9 zP+MlWV3OwvBg8BO5{{W5H1~EDUAlDFtK*V)J@2HFUV8Z0;ZK{7eH#1H_liA`2kj*$5(lN6!%o1&CjZsBdUisW9tJ3Sp4k zJZLTtFqx-;cbK0q4;ULe0u0&5dAgv5T-4`x1_sbbpMimOVBqg*zN`mwy&+%Hlk=6V zb=PR6Od?gG7vwr9OQD^k;@a}Xua_a%KN#$kqet9n)=YU<)x*xs%jTV|xqZDQ{a8%Q zCvDdcx3#n!ON?obilGq;X{^FTRn zt*g9KFk9?NR*s%nU#f4lH6WONb#9R-SSOGs;93aq5a=9)AZGgsLy=H2!Uj|_4i+_3 zyCgg=pDpgXq*R;`Bjw^w+2g_?kHdOY!tmEXg}xjM^zGuOvUF*xKQACC4rpu(2*p=)S?{h?nJ~wwmd|x&@A_M z@h$~=dKMMce>XHYH`m|acDR4I?|O?*>0w&iXKlw~XrC6x96MZ?OLQTVLDwBd!5_{2 z+{MNx%_6!G>F=ojwEixyKK!m{RsG44{)(Ch=O^c;e)j)<>a)Yw zzwj%LE=?uwtWIVGlM16^aG8uuP_*x1WRP5O7^-b<(Wlu(MbUPE+1OfJVh&h=JQzo! zI1_Q3DVsLgSl}66j7WD;=s}?$S-cy80-8+ch&XVIL_$si1Og)D2z>-dZ~}Q}gudOS z{YC!;=wbbGwMO6f$MWLF!zUv*^b3aRq_o%5)MaV%TD9TEjVBK$z}XWMPr&V3fMaC& zNitQXET?ibsZw%?4@3kXjd%$<&8M|WVQ~XgB2I0b)j^zh4yp}Cn*GdE&~LRUd`SPow+4*`|gHqVR$=w@X_Oi6YY;hr3xNXL}?J20+TtEm8CF9r}LIQyWdSD+i^Z0Ip zh{57;(m5glB7lk?3Fx~R+MNDz;B949efHFprWaApu8fS_U!ttNxUgoJrH{9M1;ASD zduj0_7w$Zqm;tX(47^(0))&SvOY1*=Z`|{2R?cLsS~_jt?qF?+-R!Z|0fR}gx3Tnc zv87N*pfJV|8L6R7VJ8w`M@6-1AqdnqA5mgd-(kJEH(eAeM1&%=u?g60(a-&6^KyOk zvHF!+Jx8Hgm^IFuW(^O~QGMDlAOCJ6=x5$BXu;plC*bR0+`z=ZlZ7YaGPJ6rxjmZC zg^y84dQ~MLRg%$GZi9qd2@F*HSnc%MoI)o?Ezg(8%F04K_N|aa|M~KJ;lYU8V4JjbM8Sq z+i-V}Dy#5p=V&UZrl|I|7%I-5LUE!{d~p=Q9yTDmO$F#{B_~d>VUUdo>J$k2MkeRx z^u5xZ@*Ti3&@*a zn0|s*Hz;#Z-Pz+y@BS^7E?wsLr1b!umQ>jQaC919C6Tp$wXyM6Qa-4pK`sgFTAyxM zqf20m&9gk7VRCZy%%A&tHDB(p0JF3FOWr6c>4vkdySt?1_n%I`QF1yftK0uf$-UdR z=lW8EiK&q5(AbaeVK` zwXdsdVu25fLlEv3!bS}1Famw8RI$8r?%cUajY6R?r^6g4>>GO8JEdRg{rTtBOT2Hx zr(Q%1z9>|xwZ^rzsc|JBuWREV2~r;#n;+LgVMjy$`OMWDzb$QyFC=lf@4+bZOa}gj zI9Ewqfp<}D{GooN|4X{7^<_Rlv6ti1?rV*Z>|(`QJ#Tf2cmCA9Q~OV!^4||9YoGrc zZ)}5m8$5xMH_mP=DLGqm<;vOan>YP$-aOM`rqL69`byK&n~RGB1E~&FFDlj1+SwO4 zCwLjc*4fU%5>OkAGsa@eQ5$Q##byegQHLj!@u6fIA(Vx#f=3YsEkV$Su=M(>qAFh1 z$#ds;9V`6`p+dR5I<>qyq*U}j=(yC;vGREJk-}is=+flI1%pw$b_ckIrKEQcjlHim zY@q&zA_snlxPLe@`Vv~2tS5(is3Ephs)F!GOZ?LGqx&;6kH#h3*tFK##@ct@7Iz8} zv(l^>=GClroUAzo4nJSI4N0@-~&5Ot|!i)Me4|u$jypwSAfLEA;UFEiy=YwO-ZFZ3YBk9c=WLC0w5Qrp z9lX7>v#C|#ftXycz})6&-*6Ho5I}3+OgfH32qyRiGt!d_qkf+3Eln?NnLBm<`h(Sb3;XDv?N%%BAI%5@_-83ebk~>T@RGwG$Vw-qJSiT3FEP z{#Y<5hu1E7dCh&>aqq#?@6i9~pM^Sj+nZ<4g5Ccg_z|o=y92(TJqw=i2It?*I&<^P znKL)De(3)+)xtKnnOfxJbk4IV+Z$w(ILqzO-0d*dHh60W-qj6{PjPh2ZT=|g)2No_ z^y@M7QXjDS%8>m&PR7_^Yku>hp;K?Z#+B&Ms9CEa_iee(l||{MSG&#gBc) z?-{>y_2I<8KzsWPkhJTy+Tq2qmHK~~xc0Cn>nJ?#7ZE`q!4v^?6v3Kgk&i_*77q~? z1414GvI#^YY($PGd!~aJw}%aJlb914EH26#A><%Q0^=HD$W1U*KoLO!#qe6a-xk%` zw+s7&Z|`@`dC%o{eqVjQl*OV7cpP5yjq4%?557+E6f-?NJ)m?T)vEp5Z=w3_+wsI_ zToWg!k|OB-B;dRog z^%m>bS-ks6tc8~)3IV!0fnG>g(}z4yitqQPoLion17apFIR(%OA+ABPNDSN}9#5*| zm7x*SpFJ+QIl6TGvj5r9{@RAl+B**)jOE5OE;gcEJJoaIX=SKiT>8Vyqn(`#8SyW7 zd>q*E#es;7^!8n?Wp60POO>Xl>gDsJrMG^6dQc!AJg8(j7c)34*--N}c$g=X$t2jk z#K{BLR@_{Ncm+B%|IgP&S}94Me!a+JNK>6d02lK4QMLj48#W@wZQZ+-MCC(rl6=!_ z;Ok+uFmh5fndTmy6&)Q`m@t29h%(iCZECv2(-W$O1OYle>t4h`GKM$^k(MQv>K2)n znwP$Q<@n{kHiWm%*2k4`s=O-`NMaWoXCFUJeURJU9@p8{x%l=(MY`V>|9DIg#O1|w zv@Q0JOU66fuF7lce;dD3Cn-*1v4nhNFd{L9fru>@F=QY(oF2b|IJu7Db>abcCxGi< z!}y8ILvX@L&*}R^w@Q|WI0agf<>VLh6MdbjW|2lHTS==(_N&&}SeTeZ3E6CFrjW}P z(%5Viz%+FNw;`vu6eTx3^p17uXjKK%y<*D)_ z`nv0DC5pPbHiB+1X0@pM5PkYRE#GvYS@HQ?zKuKj=m&{t%|3JBAm zo_eIA%-t)1ax^gdf}F&}99!E>k(Q=wEDbjxs$1!Y2LwdLCdI}^Me*4o!mO;!LOMHv zoxtU*s|(b<%|GX8TBeFTa84MymSk`cdWZXg{onJuB%{}6iieEduCqct^(np179=wy{~ zCAH_2Wh|*&AlNI&AJKr^f`DI4sGPZ?@a_M(I^K2AbymM(?Fe>|=|^)6j#yKm)p}wM z#MU=5U{k;beLGV-QfRfE`B2|4^N&ZHP>}goJe*yu z?H|1|q34kHNf1` z+|tZo(}p)m&dyXMdd8&i@HC6(9gV}t#$FQ;mgub=xMj_5m z=pFVCJA^(!bTXCzYl}VKb)5R>c*FUg%iV2bJ$)FLscd?XSNRxCn#W(nv`3_>o?(M_ zQ{4Lpki@9c|CsSle^A+1qmY-Dw$}ArJyj!}tdZ|kyeU;4%vWM0qnO8Gh{Uk?AVgFc zJiJYd9l#+vl>(vTy<0?J7H*=!i1yUZ@GOtnJ67_dOWnm zCx$(8cnl4)yxzLw!{2=K<1cq^7D{@$D^*A1;`*AZ;+j-#zy5kW%K+#CUB@ZJB)Z?xm}8IZIlm+$$*K9Fua2M~-oh!PF@Pui*ekK)Aoj zbV`Qawce&fOvsALaS%e7`nMh}_m*$n$5+eusyP~srXYu3Pz~^W-$be}_BfesG_}R* zi%p;YkG|L1HlvxuQk}eFr6Lp~K{~M5FU{ zoz+8hA9N`Vk<>Z0+@=h*OwSF?wJ-=L*FK53&bOuVsR3q2tMyl}F)}hU+(@!=TW9yK z)oM&xJ^$qkn6uj!wQY~hTE~#AtOW49kSpX?bGa9qmy?}}TAGJ?h3cPsZxlV+?g86N zCW>ZM6$LB-kLBz#_|q>xb{wBQ|JLQYhFZm$)GMQ%ss#-FS5)OLl*hEkS1sh_rm6xD zRpf>4%d1fNEq=Oq>HP6$7ZtUF`cmcmhZ9S!1IlWp;2=*a6CcbM33x%GW60QHZn}_4 zq!U_((-HehNMB+1`;Q(?FE2m3Q6ReaX#QHkg&d(!2nWX-4t}I%W@Lbao`Igdsl5To zj*4tf-_lH)BXXc)59zW66$5

^J3SC{O=CWxCY&tzNKiT7Ed?5&{U3B&KGl|Qi^kMOQv-cdv&|b# zHv+SZnT-wAe#7(YZP%L^B$3jDwEgJu(xPef1bPBj%~dC;>1=x8>E5aNpVdk9wEbN6 znfaFOK%PuQ9ON7bZ#)?~79(fcCXQqA`D`Z^Rgu8`diJp@{pdoRYN4v4B4!~qJ-xju zz9IuzeC7N8f2iUny2fVW&qlO$b@fXohTE2YkVtuxm^Lfs2*8}h`MmELTD7An)$top z>)iW4A+RHqf!yXsIQ;4yji&n6bje&nP9`W_hdwjbH)&I*Wh8ZLl=GX0)U9S4oXxg6 zZ{12VGBnnQ1(;YF+gRC~?6xwY(n4ZEb7U-Fc{#E{b-*pmQcv9y{)P@%LPCS`v-JaK zT8IV_uYiNZn#0rZdHL1O0GRqoE^pN`*{DwiyuB!#aE=KF62E}$cw>RQ+gAg zsYe&`UP`U3`0(qQqqLS-DIYLd2FV&Z7OZ9beu-$Fy5@4Pb z6%`PyADnHMZKoHEky+BJHLEtSH`ZHcVG(Ar7F!#4+W1&I9@$}i^N1`Z}+u zyi=Qw=EXF5SA_bhQsc@)(<>q}u&VxP-`GS?*T*03`fjmreyMNxr#i(*y+SY|FB7<- zD&PpDJk~K?2M(O7O=WZpM`W%ZI&sp{EfdLxXo|~@txkZj&oI8f*6T%cbPRVShlPZM z#D<5PS=s3u8DSG|fYF-ZZ2e%+oP!-UfH)X$UQIF%U!9HeWsmU-pG8@J7J`j}&tbIQ z+S<{5tvflT?#xdObSDT|o*GbB3%T4RuJ9Z)`NCCN zY)F{#>hap_GezrY3Wg~|+7OjT3*K0kle_;}|XMc1yy z$2TV>jf%nkGC}`HjgpA$0<@fqWrFW{_|MQg1>#9aGQhu16cF2;{t<%wz=60#_pdGA zQYR#Ex%{7)qSI_)Y)E7XEs7QyYn7N}a?r%~O%u#hSUOW(Tx@r5^^M)@>+4KfV_;-p zVn{O9vr4itNlJ3tZ*K0D7T_2{^9rMxxJSiC(=r>_v}kiWo1c=zEli*{@X2IqA-7<@ zh)L1fBhoDf*e-}C;vkz>3ah^5K?(!o;_$)KVhple11Wk?gIgQTKrF(Zh{Bw!Q8r!I#@`l`!c zi87)Hf^SQ-jfv!w_vWru=OAUhaDO0CSm46;%@k5IU0hBHAa`bPTpq*eA77VFTTbKCQR$>Gl|b{yVw~P=d z3=WBRgDu98<0@Q&37mDX67^AAcaqNd*F>^iooNO>OPEi{rzytxqraRR!ji z@2WTy5$7M1TD7Iz`+zDi=$U9%U8o5M@M-iZal% zBN^G5t}c6CZY*#!^&6N=h@@7dR~*C@GVH9bPHo@K{nFELN^ijCYQ;XLNq^q|ZAdG;UY> z7yj)T54L-~<*q85t>WG@_0-w!Jhz$v$g?NSA(AGJaSUK24kyaZS z6S~$92FY)>vopnp=HNBKo3o9wadS3{FW-IFWY1@M*ztZC8($6|w*Knyw!^q_A0}^K z!IJZ~BZSs>ypnPRAIOfU2cF#Hh|#6wKmeNXc@1bj)45FYd})7AS5Irj<+0)MEA7w9 z;{q!V>}vWvFx6ibxa-0DGgY52e!jR^{_xqK{ffq#$yyYxW&LtQHK|-9Rce$x@cTjM zVsxJwFf3HaI%mff*uFyUcxtuI#N~%=FvaJt-x9KELUuSilg6fj*J&1CW{2BnuUVa~ zA0BL%9gMpX8Ll=Ax4?^Au!Ef$QMo~EoNbc$Nl~_L25xBv_GzT`ULotq`@?tInERwf zoiN$oKqK$ZjHV}?E(|*%bajnAolvd5aPM9+n3u`K`BB*sZi$vHPg9I^zO3eV(s*6P z<+i>jqZzNp9O@`PkP+{HH1yM|R}Y{&^YZ&0!*?@g(2NA;Nu>f?BnFiT=PaItB|G;> z=ES5--_}esVNF_g15yalbVaU?7pNT%0zLHZS;BU$*E=+RI`!3C1&z7ahRpK z>^67a?SlKSP#s*HF&1pR*V64E>CHEd4hGng0vt#VHs(gbdaDuOOh^`MNzd=m!v+HE zD8L;$$e(PpUb_?ffUI4~m`-tb-)a3^iqFny*FrU2-4a9;t#C9k;pssL@;nVoIwGi% zl%lU(+t~fEGriI;9f>>E7xUsUD^%%M?jP^nG1C$8hyTo9fBntVmB%$*#^H@!>>f;H z12$xXjbIXJvXT&*vtSJZW&;HlM}#`=iGi$$h{MWFXAp=MA{BH%fgGiiL(Iz1C`GbE zR8Uu>r9t)Sdxr(_A z0$UfPC8dZcl(ZzN#zR9#%1#wA=?srh4F{cOwo4h4=Bf15d&YWG0|S{`x3a>Y$-p$H z8?=qwpyaoDb@T%dtae+y_h4!S*hBKvy(bTvOs2lsMYIgp4JZ;GI6d@13nO>8Ihnw( zet+?si)Wu)SGw-;xWjSUEtS>#FqvK15w)%B?&_#hKb82;|NZwLf4z06;@zoh7cU(u z1iob+KlIu0fm1$Rst>+3>tN^bI(ha%i^i8c-a}-fMQ_l@CS3MGm}FT zDxgbhRgF$nmkuAN^i~pCUW_u9hD{{YGkFvymndb|OOvE9c%U>C0voo@CbH`JYyqE7 z%S*2CEYRyKWO)@8%8G)#0=-IQsxhgJs9}m~dUI5UT_#zrsl2nc`@0bQVt8IBOba)c zwHV+~a<&1XMEP>;%lS3hn4{W`(k-Q>>(*@BxA}#2G0(>Pw?tJxaO$VvkN*7g?>|33 zG+_Va=g@QZm+}uBXc(M0^6J}fUmE&uMab~b(-&!1cwxpKmO9=0;@?UnC8JJmX1X`b%C`tvlhL}z%z@rEp7uuDZ7 zo<$$Gl;1khlF5Gfo?GK1HdUIjMwb_wuBu7T)bOZ~Tw`L;hv&=lkuZdzzQXkZ$$kOC z$n|O2%Od>He+ zohpx~R0@=t*jO32zFt~Z&u0-Un6P*$5f7P6p=*2yOmdP7kqd<;9*vs97ZN?`PQEOS z0NO0yRiEsu;4|cWb#%HxohH|zLm`Vc%A-{V6Hxle+s-{><48G?%;1a)tMU&70hT^} z43z$k2jSn}*#(yY^;73UVfY7*$tZ=!MTowV<%pH|F1s}$2=HwIR1x^e{OC0 z==YwU>9-rI4wb}6dk-~kZ7eEWud(0*sOyS8&; zc&>Ms5jMW7Hm9%#P*g$kGGWj%1|tX;-jz!ANJ3nPfAb)+rED@Y$q7btLenH^X(>V- zEmT0GS75%AEa3B4L{GN2CoO|U#ZW=`{o?SzFtIpHrVtzC^1KK|pFwX@mk(aXnP+7! z8oRT6vox9u^V{1bMypCAsl8zxw9* z$7fHUzH+7K`1Y^H9{#jzwEEgW|MluLNK{Q8PkB*QTBEsab^$1(E8@Ar7 zF7ND~xl@e5>WnXlzl~NL(oVkvRRz~ZbB}@73dU#flck&A*xUi>(3tHVTJ5%HgCE_p zCU?X3(x{_x4}NcSH*R!K8P!F3=#l2h#C*M{ zx4_$r=HM<%Wf?kF*Kfs@hPs9Xj83f#Uj=x8$lpTJ#r-uU-IhES#r%?&+mEGiN| zt>f3^g$h-n1)&8TPSG+lmm~r^)Pv#bL4iUxh0l~S$xNavmCW^^Q?sF=>cU~r1+FQc z$pWf`&vj)$Zr9h7%kbjyyr_JyVCyMF7E3_jQRyB8 zj#Nlbqthidz8Z-rNuuG1D3Jkv=)TmG>nRjAJBdiFFJqL&l9BV)ds0$(z-TEzZorgx z7evP@#6^4cM!8xXT`up_^_lAA>T&~6!2Y2d-|g7lT$nxS_JG^Ty$2t<*l=Rgqo+3H zLOc|rO3w!G>(Kfi-Wa@YyW_!9d=bQjhaD%6o~-`%D#l&gfW#eWKh)6NFol=@L@7@<{w?&jLA*2zBB*-$ey~||AJ@Q%<>a}Q@s8j`f z9XNn|0fEKl)t9lU0u~oyYAm8hJ(Ec!N{P7pJ`9dX6tFXtK$cK_m?SQbz~zH4D@mb+ z(geb?ydZairy$5PnZyesxeJ1}dMcFqt%|%%gDgxPW&rg-A(NS8261oi$c^K(0H*v# znwkzaVI1(Tu^wnQtSxyorg}@qzK(71aSKmY#xHE{S}18bdb1__e77nA1hADi`t7&u!?%Zj`)z6KO9|{!E|=v5EvO0AUu!;2abZ;J!%oR}qy-Fz*@Pb{W6cI&AVUi?h!Dy01 zDH`aA)9C3W&U(6VXAXTmQzFbGpwZ$*Lr2Q%{&4SSFbR(_st9-3y4p=1CYQ;>6nTIu z4Jz9=#|JL?9Y`Md;;Ge7J2T$Fm#b791N(tK;HhP91BF zIu_pAbk zS-S(1U)(zGyJgmX&TgtxtI-lx$z;Hv-Q9Ii5@oV@JcKS^Ave;6;RE;0b0zWp7#hEH zjt~*tg(&rK@%8g1Joz^3n4M9Yxc$keSe!`>p3!Pa!G>b%cH>%*z1Klykpcl7wEe`);MN3~k)xMMy( zc)oODzO*Z5Avf27F%E^};Dsq66dVdIW~+H;L%U^vW1@L~R^oe!AuC?lvGSKshgYCF zFK%3kt3F<3o|+wAdHc0R@csJS+}vybb~=ZLC&zmSdu^S%U9~!tl{$4@C?b#&Ghc#0 z&sdr_i-+9Yg9y41)rUl<`-;+bl6(S0bQcL-D9TyyD4&vr z18HC8cCGOr{p63cXECSTv1NXrzr!C9E!P3HfyYj@mUJmnqocY88qB*7Ou^dQ3lSX5 z2~#0p<~3XoNf<0nFyF8@6gHb18bcCS+SQkm{W{N#&)vK7<$LbAetUXwdUz#V-1U%g z`|qIqcXroxmm6yhIw?(H5HLGL2_)6*Vb5Nmm=IvvHZTh zvIp*49vybyeXHd!rrwo$R~X3Rtvv%6Xd9R~5_D|MT~TWHJVWZ?f+${KVeVR?mfl7 z-0piizZ~=@>l{q{-a9kXgPnVZ?u0l~8vB_cm1muL$X;%<88P>x(&_6|>FBla^}?JW zjy{0z?Lz|-6z9z#ijc=ZFx`bK(ulYaX(15n^VyhgBqed!n0;Y08H^n0!=q7^EQu5_ z2xU|VchTxuWs5P+J2o%Y9kC-EZ3%qEPIOqRTeL#av^ua!X=oAyyMZXj@hZu;S3cQv zSIdP*$4+gC(w1ob7fRwC{>Qc>Y0q6a)%EBCUe(Q~4t~*}xU;#c%C8;mR15m{K-aAA zCA`^aS&`Lvz4+c6{j0Ke?Hbc2 zd5&>-&X}SuLI$f=DBLqMV#B>-Gh&&sEEXY!$q|yXef@Sy0wmmJWQGQOp>!$R!wJxc z=yZG`0D;S)`vzpY?i7+Dd0bHtTObq&7+!2HE;|Dv2g%7n1VNb~7AZZ-S2(<|5t-HlSzI(7e0Zj5c*b;o$Y_mWDxVqO}v=Zv56rL1F*J)No^O?Ik0Y ze(0A~*2(gkBDL6PFdR<+tqZQs}x>hCBz5#V8BBqIu=AgDw{1J z2v})Mz9^K#$qrZ+8Q?34qz3u1T^NxJczcnb$d%3^Xeb^O3Q-^-5;+7egnCFkBC1va zgF$2D=yM8WLRyeOuY?;>gsJ6jXhALCyF4t_xd7Zm;N#xtgO4=zoE~W(Go?QA(Abx! z$DWFUf@pk8+@_lg59gLdJ#yjZrlx~y@4HK{?;0rF{dDvG#=`61Wi&VMPq2c3idWE> zXjy?9Uwr%Wg#F}QDRSE`paQtiioV&91f;A6gTZ$2xs!8tOLOD6EmIa~f>Odcl|C<1 zta(Ps$gHSvqn9aJK`8`2bhU&OK7~Z(feR~QQlxBbkEhZ2Nz-<6BeNs3G3Vy$=i=*u zP(X!NIFm>&i*@zlk6i_B}5 zZR&JE#YByX|9p=6t-B>8@SXF1-+OzW=l%GjZ_nKG^k2|+$3Tnji;p~X@k@L3;>FtP z?aCs$YYT7qR-a#f7e4K-xh|aY+*DT=>e;yQE*%fc`2JSKoTVw+fw3cr^jfAZCa^X6)+U@~PL)O)#Ma@_ zk-BMk#wIB@7&nPzav9!lP!c4N$Tum(0Rxg*x0UOz#uw6zVCQt=}b3M%P<#DO}=^wwQJyno{aG_O#npRTrR>&@&f{mYzm+QQUoCqb{!~0gC_;(m9y-x@ zGIj!GjuVlcW*yquNi=Ex;gtW~ptjZngsWi%$)zqL6%*92e@$1MtIBvKBE3Y}7+ zCirS2m?6;8KiP1<=>E3G@m7(8GE$-Vc;Yk$jo3gW>%@4ol@>5WAP5zW7CYKcf$jR< z`|n>?UHKmCHSVjQzSn*G@!O9)a(t@2_srzo4}?FYQq|1xam)5XR}N_pkn1CJBW!SX z$Jx2{vj7|eQZWVCec=mNd-J)np8?;hx)|;Fd~d5vQRQ}~W1iaHDOZ?gv(8@$``_O> z+M6~Hj`lmu;nOM2#2pE>O{(_DiMk@Xf=_1Lne}RlWv*C5R__yBoFl(Er)B; zb7iDNA{O(SR6=7=frD<8RuNSpOPt4%fF5O;4w1YtkEp3T-Ij3H&euS(7L6zf8iL(# z@AO0;=vcy;pLf~jPfhmT-G1uMjkmrRqpR}PYu~^2^N-&>c;>Hrx{n{ZxN>}E1yVoJ zUVAtyDpq!{?OxtL+}!y6@7vfqHXuWN=q(qLR~9l?rg96Ffhawi_GY7C8HPNQ2?lh& zbP1u<#`fl=3XLWxy?yCM_1<2^6LP@0)j1RmpmZk3MV3epGE?NKD71?S4#`((b*+fDY-!8hMZ_H9$>L@8byigVrD+5X!j{F_-7#D>IgePfb`w5sTcy0i;qQ zwtxrr#A$XaL@UI+TE}ZdI%S;)o{cGbI%aEGQdsR0v^71Mk!tV6Q1#~RNlL>SE?CkPMOhGRU+#i zf1)ma;=~ET6DRrnNN^|}% zzVo%_9w8BSG>juMktjF{u22BBu8OA$$^t=?P~-FYjP8DGM9kyFd_t*If+lmos_vKh zcy1F3B0pgjNM)ibC~K=ZgqSbm%k&n#$xBA+rS-7;L}NWVG7c!9u%gO#mI!9+)X`BL ztxI`yOgW^}v5=#$fQuONx!;(Ih{YDu>o2@H}ZlV-Ij@E;vLpK`idVg2^v{@m5g z%Kq8)&CM@DDF< zz7YUvOcFgup8*vH-XFIjuocFj%EaXw_;LfGSF4js(l8z&2sW7!iR#deX@-O{jd=s% z5XGy(ejT=U8&t%jo+xhkB31M->GbB=97sZi!qfs&w7q47ce%x`!c-=Au(zfRhs!RHISMnfN9|AvSh9QI zLgv9kqv*u;SC3WV8{1oz-QRv-KL7J@^S4_+EiNx_?e=*0;>}M8>c&ZZBx!ZKNrN!h zUlr6=Nn?DmSR*!wtsF(hs}>uR7>FPxs>mQuC2!)gLmdrLq0GW}TS%Y9q>fFitvqDA zb&wuB(a_WIgrm+F4iTY72jy^eOt#dr2H#G3pvxCFqjZ7d6?$>m&9fsJ@PRTu!|>G0 z5yR_OED&gcud96B-Tihi#@;=!vNQqN@kw(hV{U0~on^ju8*nWQxu*;Zxi=&W8*SlY zI28@iblhz2cbOF~nxb3`?SWt{)9xyJvfG=0bou>`neDAn@3hY`xVw3U zh$x;sp*kT|#mSzWAy6=glPW$J!<_^w+;MV~Po|N;)=2ak^!Y#Uo!dvFWbrwa9G{W~^2>PbSlv zFw_i6n;ENtE0kmQlTfLbgX_!H2o*+!+ejq&GB=QB5v8RLvsxS5+A!Fyrg6BgXFMFH zU1oD_2Oa_>rEN?qA5P^%-n@5g?B?phr9PGn$9AJY5EFSmy&iOE|&5hx!Mn#pR3Uv!a@LI&J zq%tWnka{am&*A6=$YGGjYr*d3Sw-X4NMtBtGVzjDiJAl2A4e#CMmP@VhMSHjs>7(a zfdOZ=4TBRCE(-4VD*z# zNh(HQII#jfxCV$lxmp3EqFpFWQeJ%0*)b-aH-jFBrw{!67eD=9C&%mW>RMmyLSDYx zGU~E7uF&UuYdh|S;_p39XKxz!cadt_e!P%;ys$X3Siq-{dv|Z`^R4UKlv5Y=z%1+@ zT=GtEO=+`E_iR4xW&D0Bn{tHE6v&R2E?+vlus*jxT%P;=8c3=`R_hG-OECfjW_3T= zPg;3$4PWj9S6>^G2@3&;uJJi?0}p3i9MniPY$iYC)9}bDkya|#i?t@ToG;`^)uxmI z_r0}0E>h|e=s%+8UN_JTpo+*G3h7{s9Xe-iEtO5{vi|YWHI_Q?EVjRYlif4BmPgLQ z>T!jYoavH1)lq^(R`gDUeRmf<6J}Q%sy+8#&5c}n90w1sFlQL~>ae)GKeyxYhIQVW zM5?;lHjhcXY#3p4MYAsa-w~oxgIO5BaN_eDxeR=1;b>>`X#JL;rw2bO&{FOs8Plo+ zQf{0b0zk%MrkFMoAZ0k}Ds99>YV=Jp#5QhU@|=Xv#ZCq6h2Y}~v{g#uI38C9Gd+1? zxC$ZScSMNwpty_b@C;hpXh@0M=J8`B9OfFjCdJSc8gY=zSpDkxRd9?B{(kH~FyAZa z!!CB+(RY0VCw3lF*H)a+s_dP(yBjiYQM>0QWGBDP}(GzkarYYh?rCjHA)TGl%*)e+wBj>RD%j*Ti5V^v7;VTf=%W*<20$3;%Gm3?J zlOzc}HNCV-5@Z{VVu{9@F&K@Sq!{pE=*Y_50dQfE$BVg|02I@OZaG4kq+6^}6Odaa z;N4*RBDFMvo&-k$qj$7n?r~y(mA!#SccmE@n(Z@r?@Sh0#npd5V}rQr{*_Z;0anYb zz`~^xqOu~w6uZvjY_q#uEr4TE@DPxe!51$Be#O$n3)lA2X5IF}@-CCWX`*d57l!%R z;Z1A22%siHc0@IfaJ7wULx_KQe-0;v-TgX#Eza%iPWOA+R(gyinvjheG#rglD}f(Z z3%R(^3`%2wi@24S(aVw?+yN%ORm_)T+8GQ&#w!ScAhd{^xTFlqd>kbqtJ4}S2Eu9) zHPqF&wY56f$(V^SokFQ1p{VxK9@-YxnE@;UGI@0sTW8mP9~wi;iw|FTcyS%OpWDha zB!GE}Lbj|Mt%P_5DQ1P#h&Nt)6 zYsY*Wlq$jrue!#I`b1^n@eAu%7ykc^KexUDqw85c*)LNf<(4b8e6%5CVw7xf)$xg> z*raWeD0qA$8NgeYsPr5XnuBhAl2m3C3Tu$i5M;Qi0Dw7Z4`kr zK!kKcI^5`V=&EaR--XjUGt{nXY&Is%i~`fK%C3X!7w)*w*N2}5O!7PSE8BU*qzLzm z9yTy#7d(}{$fQeYJThz@3r4@(_tSxYaOTE~*AMbuzc;R<<90e89S*r@q_1=~)la(+ zEhBjy1Z437yYMX*3+osDTd%;wtv-A1Szl&I4q(PF zEfa`Qs?cOepMfMn`inQ25X%Y`G9^c*!iZ|fOrsnrsy_+8CQ_?J^}@Qk`V&esWcS0T z?}tq7zBe1wRm3u|$%YjJCjVH|9;3N5W-KqF8E42=ZL`tE!E6Yj>*y#N ztOxrnIe#7d1ylY1H~-jeET0hs<)NYB3<->wMr?v`a!^22srWeQZiyRmb9_~VgtnxZ zBr{grX2{mH@*vO`$tGEHIO*o|2m&U-=gZ|nk@}=sWR#?o1kQS6Rr6_J>RN3;*PzMc zBv6-z;+amD_QO>FJ?>bWM}3RzT3*Lz%j-{%tx;YxlP(YX(_z*@+lpx_no6g!^|7(t zo9ve^!?7*w>ZZf~)w184&Fa9i)PaXVowqyB!=WO4s2U& z`}haeZNGrI%5t+oc4C7%nM}q<1xm<^LtwEd5X1$57p=~iK;qZCwI;ci-^7>mtuk&V z7AwRJG6fF0M#fVK|EZ!VJQA7~*Am03C)o*upc9*$){oeO`@BQBUy>GX__i|0_qxU@A z`VA0BaO}62r>6&Z{`>$Zf~e+$r#`s&q;ws83sR6>2q=JcnBErJd+5`V>8+qI`1Dl_ z*f{||eGb%Xgsqhn-L_CnHaWyFU0(N^YZFz~xnwL((xgBg6131ZdDYSl70^e|Z~^jp8?99- zf+o;bJW~dCD#F$h5hBYll9cI)w3yu^67@um1tC;_QQQT8bOYyu(^yQQB0NG5>GIQC zPle|QpnLVzPjSd)tqT9Q6S7TL@bj8eeFwdl;kI#8rmG>0H)Q1Re7XuZcm@DCo(4-) zj~klk^ma<#uG89G-MDeH1!KQC4FUD&;%Dp?JHEH)XYoB;e?Y|w1?$mx0Y#^vrX?fQ zqtl!*Xu9KTa-8C66UjQsg?C-g4=l?9&M7uW>frFAgi2F-(J;6HYLNs{iKeJYSgK9T zr8&iBscd$mg9nth#gMSt9-+@-G+Cmz;TXmYls`pZ%h~y@5ASUpD(BB{?BLwo)vkxQ z{~c{-YZvRC(#}XL4@2>2Yk4+Z{sKMp;mLPj;_rTIhz$nA<8XdJ8Bn^l9$qe|wKZ*M zr)Y?T(sp?YY4*jR&qA*K=dZv1_1Di2W9#AGANT_&9{xUB9FEa2D;Rn^D&PT(SI`_T zHwRsKZK@c>u2E#hT}PFfE5y=dJgz25lgiJefdM~=dr{z%JV;$?u5*CIL%bP=}=a;KtaNQrRra(og&9(q=AOpm(RTIf#V|n{_C_%XR z`Qbl*{R`#Sqn|GR{tGQ;5cB>T+WP@8eu3Yz{Y-O4xs;NQPnuA1Lh(UyLScZ?qQOwa z0OfT)Miyz3)77F%(O?+T_sbt};bLcGGDFtfT6E1_JCKFSmu+1pR;XDd5=H&d&L zcqs*s5a2dyVZHZYxI8*IJy?Eq=ZQC-1E+rZ%iS-ukIPsq*gLrU^_^YxnqS3XLR!)< zjR1|SRqICS?6Z$P`R0@BH~L$3q z7r*`S=bx`09o@e5+fP3}5N`eFyN@5e6>c8eKmBD|w2;NP$X{Zr8Rf50vTWwlF(xnB zU~CD#kkl#FQuRE*zI{lMvo@ut^-!PndX7}{r`J#6M}Toh_aw@% zzVPaE&mBGYI5a3vUHlztxc_+Y=--V$fsrJ4ep)WnisfZvYt#vXdL6<(I$bmisv-%D zO`uoOR%C@UY+)eKFGb^AnpTTNGuE`oLDW!r-t&??i;@h-`f`QGu5-`lG8y!gAF4DjR0kRMZr@qvaw;kP1C+&JGI({(3E~=Skg5 z+l(=;*n%2Mb_oflPMh5Ugn-#ZHkFOU3n9$0IjK`ACjmQXGaKY z?%etiQT62)UmxGRQG&TwtDS1Kj7Je+?8x+9Tn|rk2aOq>P6q)&38~61Dwp^k{;)O* zJ=(}&=JAcncCNjJ(q65f(`q%xA32bghorz0w{hKHeeRxVFYxE>7cMU^PoKb%W9!XO zzx>6szug{>Ay=llZ9bXL<5n}Vg22rXttxSvXdVs@JsIu-`&)a=O}WRIeOAR@%9G<+1wx4{g0&-FdHH#U3>@gCLH<8@TB09RkftxYpb7 zgIDWULwRX+jz;BNVN%KE_P6KPM-V9ew@y!C?>Of%_USGU4(@)t7#}T;76%6t*!x%C zo_~D6T#HeraN>K>sMl*-oJw9Jl>##`b(0Vj+6Kz2a*QWwb<7E~cH50c3rT{@>*z2{ z32KVryL8BNVwwp@Nlm_zVY8vZ1L{Yt?>iPhvCzC#^H$EvIreV`r@vof>p$LUVAe}( zRc^pi{mzbtG;F<&Q-1{M>mztD?S2ptRdBiZyc)p3N4K164UoBAV-P1rH}{BoW@BHh z?>!x^{mnW?=P8r9+^~Eg%OYF{;TkuWFQKb;arVbwf#tdjkW<{@?Ci&jPY)Kcq9CPa zi8c~5j`P4srf6N^lAK&Y=4Oz#>n16~hO(P#Mp>av%5BC-n+j!CKzD$++Cgh>D{SRyg&fsye_-o(ZbBW_DpxnJS7GpF$SF{| zz&pR#`Mrf_xe%OUVaRhCugtu>D?(az72qkNBO8GuRhQ;_Jm#T_Vou!KM1?a zH;}Z!WLJ~c)L#r2i_vl<24F1Ce|qEHJ70h}L_=G@-$DK{*N|?n=N{X{E8&lBJ-WO3 zc7N+JaZ7_veib;Hd!<&p;y7Zb-`^CsH|n_^dMTx2e32K}!R{H+()Oe}DPz-F6(zYjeEdl^$kpscN30$e0ZZPK^~6 z@a)21aOfL4MX8(_L);S?FwL1ODAyz!t>e1dmQB_~>PrhsC6$%3y`CZa_C!HYlj-O7 zYAlE_ZwklO3be)u*wn%}-%o%1;KOG>Z2-A%0LXTyqsAy0l}BQ~ysm9uspFZ7^7>Wa zeHf(y=5WzR>)Ya^b@3r>Tg-@&TneEb7&2$F?ztd$!MF?VcLq``uvZ}K%uAEWVm=8-l#|wg*Yin&Mq?daA$SEE=()TW4@=J343&{s#}A~& zy*URCu(wlNIhug%?Y9r#ci$gU9pz58+YW^{pz9 zZY7Gl;GH&iVC$Rv;W$jhii(&KuB2Fz&y3g&tlUOve}6yq{A99x#-A0erWN?hMH2=O zg_kWi7nUx&NYavwKpFn{`?E3K_GDfj$B9^)_GgwW@LW3S@j8*`p?5L~({!i&6CNl3^kx<8S0G8(+tSyD5tbJO3o%3)HK>lmIX^kWjQ-;rVwesJ@p$Sr{@hV z%UL!cL74`~C*M6EPMzbDgj5SI`8q~-Yfwf$(g(5i8s3lYzo*sj7eVH?MlH+Hq$^@) zd*oo-`?>u(n9pr7ThHw5Z{*P2WP%Epn7zzC5Z;-%!D0f7p9PDtbvTADbul*l1@8Dj zE)-0@?dyUfnZ7Rw7G&y#AMd$QQgta$p4f8CZO0-M4JEUU!c(!yH3x<+I|2h>i^i@+ zT+e_JA!ubN5*2xp(IpTWN=%_BHu1_N5*bj2HJ{AUNvCzfn5SV4{YFsr8h!9aD25!I zfB4~#A0Hq0!)~_Px`&X|Z(Q;EAl2AXsfM=t{^pKWeOj!C>WY@^^u6`|_KV`))4e(l zoXPPWB#C^*scndxn|pxwM7GNoC`rhyIlW%n_bssOiohEK|73h}B+H9yNnQ!8=FIYK zo}keY>bgwNx5m~$kldcsW?WTJx?IJkRLbNqx}i&OwhrqVOhDe|i*YVmk-PFtYQqtN zsRY(jN>>$BicC^0#8Ujk=sv>}1S`D~N#IXuUYX2&WNniMme+Dtojzn{%ex=k`gU=1 zQR7>UPNy^ywd*Sw{Q7IJq1_M*I#Iy;I$lq|TGcQKM%+U6w!B%@#Lj#)8cCyQB1ejQ z<0=pyA=MngBL?Tx_xBPKV@$?lO844|tEdJ#95GGokSom0@R^4q9CKkjwr$oX;+*Tc zV>Vjwe2Dv8zg|=2gE+Mq>V7e z9;mk4uf5ja-0EW(hSq3iOrGjA_@**rT$s~2i$z~T`8hdku`i&%`+tj|qYpaNs3l z(WE3PNLyzzqY|?w*-Yk(BnS+l;M+akgwiz&}U@7Q?QWT}=tit7$bRukmqULN90$RTVB`UY5qa*s9xR2McYi$hM&i~E4prOsJ0oRM5gWb! zQ1qOtr-hFfR2!YGRJDUlESQc&shUf?oQXV?%E61XsZ=(D>ZVuQ$Pl@DCYS3}x*&^y zJM3PD@dR`XFrEk5`Qga{R2*cIv7&83m>HB2c6}FJANu7&P#6pONbwbD9nxxEiI{Vl z7u+_vM)6UBJ0y}S?z#}|mG31xwKz`?j_4Pw@qY7=BM-ELyZUMi9&72RN?G;3QrPtGA&PU8d(y&|)MAk$G2 zF+6AH2b4AI>M=3~^(Xq~6nM;J3^NU4#U#yBf=#FbB(Efcep*U5Q{z;HsnF0&xILnB z)?9{Kai1NHY8`3R8_mzgH-jTopT219=YVIuvM81T@uNBb3_)2AacXTlA?|fHLt0Y| z|1&4To!7TSQ9~gohkvqr8{sUpST04Z3E?MSsjv)~;l%SE%AMB))~o3 z)-nhtN)A!?Ry~2|^dzmsd$qZg%T+p(S7n_lsLhc!!jPY^bej}wUO9s?{<#_gyfu@Ev4vb2#*4xizdX^%)ETV1Nvd5URB1~u=FVlvTqmOFeA;7=$78UE*t=saXJmvTiqJp-X$Z}_G!jXXl|a!J2(nN{ZxIp&$jvK3 z;@@(d1q$v<#(BRM?|Uh~`ugQ-WGQePH-yKC`)cBbLf^fISFq3S zKKb~=4-wF-xI`MU_3CgJsn2;9l{m9`KA?=uuAhGWvic(eA{ z4`~#gyc>2eEpbw8IVmg==ii33iFD+kj^Yg`d3-Q#vqmp}e0=(H_@SvDpK*!$c>nNz zh8t7-^2he~@1MVTzxd?-^ZK(-KF2L+K8nAEJ|jgTPi1$X!kb@bHU56T5I%#fe+YxN ze}fpf`?`4fVe`@)p0^vm(S?l*Nc1>rV;*pQAlqKjJ~}=cGdbp4pYt>NuH3f?lZb%J z3e^rg{5tCZRIa%~A{qg|47p`BCO^PkhIAV!b;IiESt99qq_zzp4`Fn9x+I zBp)J%|3%MQVoz1N9iH|?NGqt`pi0c2t2CyjE{`v@c}e;G;qcStx9#)OSMMG_e;41Y z_?!aJx8HvI?pG-IVfUZjEr6Gsqd(l;;u_Fv4Bvc%d&OsqmaXa)%H-@NTiLJc`h^yX z zdbo>>9#4yxG~&4x-VdcTG>^dWq?!z+~;V$UdQhi!-Wo9r-Q9N z|K=NP$SRHs1XK|(zomaMvVy;bXh;#`Js$4{{v)cqyEvoHw#p{)x^MRVunsPlEZ@E9 zFYA-s zxqI)E?-n7i@38^cgazBb&$zCSXoK*jpab>QT)(qU@V(=;y3OG+0&9J{2~IX|hm(b2=8MRE(@kPy}(F2o+qxmnupIO&6Evx6WT-~E0yI-hH7RWf#`y1iEx%+g9`5Vta1?`uUU<6zYuh;Qnw5~VD zto}61ZeB+&*%U>gNfbp$sFR6`JO#aXsdYq-Y3}n&yM7Z`+f`MUKW%@!ti^K@#UVJG zd$TJ@KTW}Cn>_EDB%=92g^=?#@x2(V?a{bJt(hvK8|l!YCqxG+o#*SOqq2n`8_C#^ z4;>_iYzXHdSUf-k8$u!~j`N(YNKKE$0v*5S<3qDRN2wL5&ft9CKeZ5|dgpws_GGhEoPujA;bY?P0 zZOf`I?(He@e!n3ifBW@f{vaML1N{f7;7 ziu|@ui+gm|85j+;48AnRtTg-zS3hK*!o#nYEite>Rtwt^)DZ}@i6V68*a|$x<0BDV zD99Y8)(Xb#X~LXVhQO?)v>;4*-(8}^o^>6rR$O+;d8kTBtvh(p(H(JvGlw~Q+*Kay zpAtnFE=CM*8YKNKKSM1g`nKiL#g(?2vVv4mCq_x7c0nPuP$rzfJkljq|3+{wMhA^0 zR+54ja3C)!jpGP@B~QasTGUH$-!1GOfnkM5gkiDct3lu5qBbToc(2G_zvfuP$7MHT zQDC6Q@vCKS!U)WAVxfGeDMElF6s5C>b!j347WJPp4L##x_sSWaw>=dHvAUeeFD*#TiIR&DsL3(3mJNkic0@xc9BCP=5XOSI@|Z z1-2^QC4PhylQ=sG`=)l0<~(4#4v;J3P}2B4BE;?U{%i)FwrpnE^-Z%oWV4$NIiZTU z&@wtp>ilk3@`85~6`Y0?Zo@sEqi*DS7+f@~s9 zSLGu2uvK=2-7Uk6C+y)qzQ5@}nSxFNpbL@RUBMO}ixH>Tg48uiC8|`jF%#p81veQ= zly8F*mhhd=&zr;g@K?8f6ts|?SNxE_iTB^x}tLrx2Nn-?w(nPdEFv24!tyhdyL9o1I!nP5lXY@qM1v-L~$JEeG z_gEYe#4cOvk*mm#6tEV-$5kf8Gr}8|&8DW=JexV2R|Vb!cDPn+3X3?BxQpllT}LDV z+xf^Wfy;6ygya(LzzK&mWm)UhroXh@SImMK3N5yWzKPQ`MGbS8&BTo6Rz~5lgYwP3 zP>uI|Pu>hxczy3zm2$9i6GdZV?d)bpgo`&X#p8bDD}0 zGTU)!Rx6#+Xk71_$RNwnhlSV=={@?IMdmQTOtGl-t#FA;TECjjU_ig5bOWOnLuO`C zj%@Ka>f1;(xnG*`nM#KjmTJ9pFG-Mur*HTBU@hl)*Qtn%p;f!C+%9rZU&pB36Qhl2 z0LQJX)=zBvsqfOOHWdCK0&~s`X4+a zNklAA1HZ9x1a~BoX4y*>(He=2KESRI_Bv zO}HKBfU|~1NdihUCL=0k#h8%77zwQrl12#Q{_^JW(F@;oETrH-dx|2%(abf%0mW$M zGF|6P(wX=rE%oc6iCWo`wr3Z;-66M`XrevpqH7eWmO5(k#L3x6m^)4qE*C@z)$WxF z%0pkfrh&q=*4oqy5W{FJ*Tii^Gl6glYr2S*)gb z^9Ehqju71?)@5)}Btw#%#!)6nZcY(!KRD?GZ)~^gd7CUxwP;W-tO|m(QahFo+olkj zGCI{=!nt%aBP6MsCK+r;c+dY7jhqT*g{sf9OXjP)LzZMNrU?AmOok{)4T)@`fHPF8 zYV+0-+aby<#Lh|0C>BfQ0=-t0E72ttv?2#Z$@KVo0|dptBKom z3v>mj3&VgIcXeKGY-ArdDSJIV?6g2^iZ%4%VmXac@YcUt}E&?3f9K0 z9+)o-D-v9cT(8O7OUS2Z&fvD?`w=rFIr0@!YQ~hj(km5AU#FD`-cHlR6pAJrN#1*} z+JZo77-Viz3k2%SVodA*pwF++VgEq~?8UHjvK%5n7q8GU0ev;L%(g%WLipA?Bw4Hw z!pm@GA_igJiefrmwn?8Scz<7YjdHFT1|^ZdRYzhwN$%s!nXaj>lhKTkP50uNKUz`_ z{!H?<8-jl>wpCP_2X@s7ul=1t+Qi0B*20g5GBHuRH11wN-58oBMIr))cUG#Uw0d2u z`zJ!pe1nb+_&;>0Hvlh~WdzNH0eT^D{vYW2)$6zE3=|&FC36;D4?#+8*sSR^P7~fI z_+~>o%D_4#@y?E_^IWw|AQ)}L3f4NP6D2L3qeA6L6wQ-zqvs;`)+V$kz6x8Nzljo= zEv2uGI;;Soslz8{ji84Uu~NA#lzD|%55#d5>;gTYRj>}wDOU84*TW3_sBf;>40#I~ zeT7~da9A(U$zqNWetQMS3!J~117wY-SdPGX#0VD#w?KEV(5ap*1y$hfA|6kHB|t8^ zG4Y)ejZa#pFmG#_pbj#j?K}x8xe!80F+=6mx!JS{8wgvIzf__p8koI;Ac8$$)sn5Q z8nhzwJn67xcq5pCi-oW~bd$9qEHyk7sC5pkkEH$=Ix_~CF$qSqKwr$*8pyF^0u!&$ zg?)uyup3^Oi(a8Kz1Yp`k#r2uCH}qtpo1J@C{ryF3?$__SN_~C#jYPJB?wb3!3>O9 s>SmKTFz#xX%2+j_#T4;&ea^-9Z+8#z7el$et^fc407*qoM6N<$f?|Tx;{X5v literal 0 HcmV?d00001 diff --git a/vendor/github.com/go-playground/locales/rules.go b/vendor/github.com/go-playground/locales/rules.go new file mode 100644 index 0000000000..9202900149 --- /dev/null +++ b/vendor/github.com/go-playground/locales/rules.go @@ -0,0 +1,293 @@ +package locales + +import ( + "strconv" + "time" + + "github.com/go-playground/locales/currency" +) + +// // ErrBadNumberValue is returned when the number passed for +// // plural rule determination cannot be parsed +// type ErrBadNumberValue struct { +// NumberValue string +// InnerError error +// } + +// // Error returns ErrBadNumberValue error string +// func (e *ErrBadNumberValue) Error() string { +// return fmt.Sprintf("Invalid Number Value '%s' %s", e.NumberValue, e.InnerError) +// } + +// var _ error = new(ErrBadNumberValue) + +// PluralRule denotes the type of plural rules +type PluralRule int + +// PluralRule's +const ( + PluralRuleUnknown PluralRule = iota + PluralRuleZero // zero + PluralRuleOne // one - singular + PluralRuleTwo // two - dual + PluralRuleFew // few - paucal + PluralRuleMany // many - also used for fractions if they have a separate class + PluralRuleOther // other - required—general plural form—also used if the language only has a single form +) + +const ( + pluralsString = "UnknownZeroOneTwoFewManyOther" +) + +// Translator encapsulates an instance of a locale +// NOTE: some values are returned as a []byte just in case the caller +// wishes to add more and can help avoid allocations; otherwise just cast as string +type Translator interface { + + // The following Functions are for overriding, debugging or developing + // with a Translator Locale + + // Locale returns the string value of the translator + Locale() string + + // returns an array of cardinal plural rules associated + // with this translator + PluralsCardinal() []PluralRule + + // returns an array of ordinal plural rules associated + // with this translator + PluralsOrdinal() []PluralRule + + // returns an array of range plural rules associated + // with this translator + PluralsRange() []PluralRule + + // returns the cardinal PluralRule given 'num' and digits/precision of 'v' for locale + CardinalPluralRule(num float64, v uint64) PluralRule + + // returns the ordinal PluralRule given 'num' and digits/precision of 'v' for locale + OrdinalPluralRule(num float64, v uint64) PluralRule + + // returns the ordinal PluralRule given 'num1', 'num2' and digits/precision of 'v1' and 'v2' for locale + RangePluralRule(num1 float64, v1 uint64, num2 float64, v2 uint64) PluralRule + + // returns the locales abbreviated month given the 'month' provided + MonthAbbreviated(month time.Month) string + + // returns the locales abbreviated months + MonthsAbbreviated() []string + + // returns the locales narrow month given the 'month' provided + MonthNarrow(month time.Month) string + + // returns the locales narrow months + MonthsNarrow() []string + + // returns the locales wide month given the 'month' provided + MonthWide(month time.Month) string + + // returns the locales wide months + MonthsWide() []string + + // returns the locales abbreviated weekday given the 'weekday' provided + WeekdayAbbreviated(weekday time.Weekday) string + + // returns the locales abbreviated weekdays + WeekdaysAbbreviated() []string + + // returns the locales narrow weekday given the 'weekday' provided + WeekdayNarrow(weekday time.Weekday) string + + // WeekdaysNarrowreturns the locales narrow weekdays + WeekdaysNarrow() []string + + // returns the locales short weekday given the 'weekday' provided + WeekdayShort(weekday time.Weekday) string + + // returns the locales short weekdays + WeekdaysShort() []string + + // returns the locales wide weekday given the 'weekday' provided + WeekdayWide(weekday time.Weekday) string + + // returns the locales wide weekdays + WeekdaysWide() []string + + // The following Functions are common Formatting functionsfor the Translator's Locale + + // returns 'num' with digits/precision of 'v' for locale and handles both Whole and Real numbers based on 'v' + FmtNumber(num float64, v uint64) string + + // returns 'num' with digits/precision of 'v' for locale and handles both Whole and Real numbers based on 'v' + // NOTE: 'num' passed into FmtPercent is assumed to be in percent already + FmtPercent(num float64, v uint64) string + + // returns the currency representation of 'num' with digits/precision of 'v' for locale + FmtCurrency(num float64, v uint64, currency currency.Type) string + + // returns the currency representation of 'num' with digits/precision of 'v' for locale + // in accounting notation. + FmtAccounting(num float64, v uint64, currency currency.Type) string + + // returns the short date representation of 't' for locale + FmtDateShort(t time.Time) string + + // returns the medium date representation of 't' for locale + FmtDateMedium(t time.Time) string + + // returns the long date representation of 't' for locale + FmtDateLong(t time.Time) string + + // returns the full date representation of 't' for locale + FmtDateFull(t time.Time) string + + // returns the short time representation of 't' for locale + FmtTimeShort(t time.Time) string + + // returns the medium time representation of 't' for locale + FmtTimeMedium(t time.Time) string + + // returns the long time representation of 't' for locale + FmtTimeLong(t time.Time) string + + // returns the full time representation of 't' for locale + FmtTimeFull(t time.Time) string +} + +// String returns the string value of PluralRule +func (p PluralRule) String() string { + + switch p { + case PluralRuleZero: + return pluralsString[7:11] + case PluralRuleOne: + return pluralsString[11:14] + case PluralRuleTwo: + return pluralsString[14:17] + case PluralRuleFew: + return pluralsString[17:20] + case PluralRuleMany: + return pluralsString[20:24] + case PluralRuleOther: + return pluralsString[24:] + default: + return pluralsString[:7] + } +} + +// +// Precision Notes: +// +// must specify a precision >= 0, and here is why https://play.golang.org/p/LyL90U0Vyh +// +// v := float64(3.141) +// i := float64(int64(v)) +// +// fmt.Println(v - i) +// +// or +// +// s := strconv.FormatFloat(v-i, 'f', -1, 64) +// fmt.Println(s) +// +// these will not print what you'd expect: 0.14100000000000001 +// and so this library requires a precision to be specified, or +// inaccurate plural rules could be applied. +// +// +// +// n - absolute value of the source number (integer and decimals). +// i - integer digits of n. +// v - number of visible fraction digits in n, with trailing zeros. +// w - number of visible fraction digits in n, without trailing zeros. +// f - visible fractional digits in n, with trailing zeros. +// t - visible fractional digits in n, without trailing zeros. +// +// +// Func(num float64, v uint64) // v = digits/precision and prevents -1 as a special case as this can lead to very unexpected behaviour, see precision note's above. +// +// n := math.Abs(num) +// i := int64(n) +// v := v +// +// +// w := strconv.FormatFloat(num-float64(i), 'f', int(v), 64) // then parse backwards on string until no more zero's.... +// f := strconv.FormatFloat(n, 'f', int(v), 64) // then turn everything after decimal into an int64 +// t := strconv.FormatFloat(n, 'f', int(v), 64) // then parse backwards on string until no more zero's.... +// +// +// +// General Inclusion Rules +// - v will always be available inherently +// - all require n +// - w requires i +// + +// W returns the number of visible fraction digits in N, without trailing zeros. +func W(n float64, v uint64) (w int64) { + + s := strconv.FormatFloat(n-float64(int64(n)), 'f', int(v), 64) + + // with either be '0' or '0.xxxx', so if 1 then w will be zero + // otherwise need to parse + if len(s) != 1 { + + s = s[2:] + end := len(s) + 1 + + for i := end; i >= 0; i-- { + if s[i] != '0' { + end = i + 1 + break + } + } + + w = int64(len(s[:end])) + } + + return +} + +// F returns the visible fractional digits in N, with trailing zeros. +func F(n float64, v uint64) (f int64) { + + s := strconv.FormatFloat(n-float64(int64(n)), 'f', int(v), 64) + + // with either be '0' or '0.xxxx', so if 1 then f will be zero + // otherwise need to parse + if len(s) != 1 { + + // ignoring error, because it can't fail as we generated + // the string internally from a real number + f, _ = strconv.ParseInt(s[2:], 10, 64) + } + + return +} + +// T returns the visible fractional digits in N, without trailing zeros. +func T(n float64, v uint64) (t int64) { + + s := strconv.FormatFloat(n-float64(int64(n)), 'f', int(v), 64) + + // with either be '0' or '0.xxxx', so if 1 then t will be zero + // otherwise need to parse + if len(s) != 1 { + + s = s[2:] + end := len(s) + 1 + + for i := end; i >= 0; i-- { + if s[i] != '0' { + end = i + 1 + break + } + } + + // ignoring error, because it can't fail as we generated + // the string internally from a real number + t, _ = strconv.ParseInt(s[:end], 10, 64) + } + + return +} diff --git a/vendor/github.com/go-playground/universal-translator/.gitignore b/vendor/github.com/go-playground/universal-translator/.gitignore new file mode 100644 index 0000000000..bc4e07f34e --- /dev/null +++ b/vendor/github.com/go-playground/universal-translator/.gitignore @@ -0,0 +1,25 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test +*.prof +*.coverprofile \ No newline at end of file diff --git a/vendor/github.com/go-playground/universal-translator/.travis.yml b/vendor/github.com/go-playground/universal-translator/.travis.yml new file mode 100644 index 0000000000..39b8b923e4 --- /dev/null +++ b/vendor/github.com/go-playground/universal-translator/.travis.yml @@ -0,0 +1,27 @@ +language: go +go: + - 1.13.4 + - tip +matrix: + allow_failures: + - go: tip + +notifications: + email: + recipients: dean.karn@gmail.com + on_success: change + on_failure: always + +before_install: + - go install github.com/mattn/goveralls + +# Only clone the most recent commit. +git: + depth: 1 + +script: + - go test -v -race -covermode=atomic -coverprofile=coverage.coverprofile ./... + +after_success: | + [ $TRAVIS_GO_VERSION = 1.13.4 ] && + goveralls -coverprofile=coverage.coverprofile -service travis-ci -repotoken $COVERALLS_TOKEN \ No newline at end of file diff --git a/vendor/github.com/go-playground/universal-translator/LICENSE b/vendor/github.com/go-playground/universal-translator/LICENSE new file mode 100644 index 0000000000..8d8aba15ba --- /dev/null +++ b/vendor/github.com/go-playground/universal-translator/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016 Go Playground + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/go-playground/universal-translator/Makefile b/vendor/github.com/go-playground/universal-translator/Makefile new file mode 100644 index 0000000000..ec3455bd59 --- /dev/null +++ b/vendor/github.com/go-playground/universal-translator/Makefile @@ -0,0 +1,18 @@ +GOCMD=GO111MODULE=on go + +linters-install: + @golangci-lint --version >/dev/null 2>&1 || { \ + echo "installing linting tools..."; \ + curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh| sh -s v1.41.1; \ + } + +lint: linters-install + golangci-lint run + +test: + $(GOCMD) test -cover -race ./... + +bench: + $(GOCMD) test -bench=. -benchmem ./... + +.PHONY: test lint linters-install \ No newline at end of file diff --git a/vendor/github.com/go-playground/universal-translator/README.md b/vendor/github.com/go-playground/universal-translator/README.md new file mode 100644 index 0000000000..46dec6d2b2 --- /dev/null +++ b/vendor/github.com/go-playground/universal-translator/README.md @@ -0,0 +1,89 @@ +## universal-translator +![Project status](https://img.shields.io/badge/version-0.18.0-green.svg) +[![Build Status](https://travis-ci.org/go-playground/universal-translator.svg?branch=master)](https://travis-ci.org/go-playground/universal-translator) +[![Coverage Status](https://coveralls.io/repos/github/go-playground/universal-translator/badge.svg)](https://coveralls.io/github/go-playground/universal-translator) +[![Go Report Card](https://goreportcard.com/badge/github.com/go-playground/universal-translator)](https://goreportcard.com/report/github.com/go-playground/universal-translator) +[![GoDoc](https://godoc.org/github.com/go-playground/universal-translator?status.svg)](https://godoc.org/github.com/go-playground/universal-translator) +![License](https://img.shields.io/dub/l/vibe-d.svg) +[![Gitter](https://badges.gitter.im/go-playground/universal-translator.svg)](https://gitter.im/go-playground/universal-translator?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) + +Universal Translator is an i18n Translator for Go/Golang using CLDR data + pluralization rules + +Why another i18n library? +-------------------------- +Because none of the plural rules seem to be correct out there, including the previous implementation of this package, +so I took it upon myself to create [locales](https://github.com/go-playground/locales) for everyone to use; this package +is a thin wrapper around [locales](https://github.com/go-playground/locales) in order to store and translate text for +use in your applications. + +Features +-------- +- [x] Rules generated from the [CLDR](http://cldr.unicode.org/index/downloads) data, v36.0.1 +- [x] Contains Cardinal, Ordinal and Range Plural Rules +- [x] Contains Month, Weekday and Timezone translations built in +- [x] Contains Date & Time formatting functions +- [x] Contains Number, Currency, Accounting and Percent formatting functions +- [x] Supports the "Gregorian" calendar only ( my time isn't unlimited, had to draw the line somewhere ) +- [x] Support loading translations from files +- [x] Exporting translations to file(s), mainly for getting them professionally translated +- [ ] Code Generation for translation files -> Go code.. i.e. after it has been professionally translated +- [ ] Tests for all languages, I need help with this, please see [here](https://github.com/go-playground/locales/issues/1) + +Installation +----------- + +Use go get + +```shell +go get github.com/go-playground/universal-translator +``` + +Usage & Documentation +------- + +Please see https://godoc.org/github.com/go-playground/universal-translator for usage docs + +##### Examples: + +- [Basic](https://github.com/go-playground/universal-translator/tree/master/_examples/basic) +- [Full - no files](https://github.com/go-playground/universal-translator/tree/master/_examples/full-no-files) +- [Full - with files](https://github.com/go-playground/universal-translator/tree/master/_examples/full-with-files) + +File formatting +-------------- +All types, Plain substitution, Cardinal, Ordinal and Range translations can all be contained within the same file(s); +they are only separated for easy viewing. + +##### Examples: + +- [Formats](https://github.com/go-playground/universal-translator/tree/master/_examples/file-formats) + +##### Basic Makeup +NOTE: not all fields are needed for all translation types, see [examples](https://github.com/go-playground/universal-translator/tree/master/_examples/file-formats) +```json +{ + "locale": "en", + "key": "days-left", + "trans": "You have {0} day left.", + "type": "Cardinal", + "rule": "One", + "override": false +} +``` +|Field|Description| +|---|---| +|locale|The locale for which the translation is for.| +|key|The translation key that will be used to store and lookup each translation; normally it is a string or integer.| +|trans|The actual translation text.| +|type|The type of translation Cardinal, Ordinal, Range or "" for a plain substitution(not required to be defined if plain used)| +|rule|The plural rule for which the translation is for eg. One, Two, Few, Many or Other.(not required to be defined if plain used)| +|override|If you wish to override an existing translation that has already been registered, set this to 'true'. 99% of the time there is no need to define it.| + +Help With Tests +--------------- +To anyone interesting in helping or contributing, I sure could use some help creating tests for each language. +Please see issue [here](https://github.com/go-playground/locales/issues/1) for details. + +License +------ +Distributed under MIT License, please see license file in code for more details. diff --git a/vendor/github.com/go-playground/universal-translator/errors.go b/vendor/github.com/go-playground/universal-translator/errors.go new file mode 100644 index 0000000000..38b163b626 --- /dev/null +++ b/vendor/github.com/go-playground/universal-translator/errors.go @@ -0,0 +1,148 @@ +package ut + +import ( + "errors" + "fmt" + + "github.com/go-playground/locales" +) + +var ( + // ErrUnknowTranslation indicates the translation could not be found + ErrUnknowTranslation = errors.New("Unknown Translation") +) + +var _ error = new(ErrConflictingTranslation) +var _ error = new(ErrRangeTranslation) +var _ error = new(ErrOrdinalTranslation) +var _ error = new(ErrCardinalTranslation) +var _ error = new(ErrMissingPluralTranslation) +var _ error = new(ErrExistingTranslator) + +// ErrExistingTranslator is the error representing a conflicting translator +type ErrExistingTranslator struct { + locale string +} + +// Error returns ErrExistingTranslator's internal error text +func (e *ErrExistingTranslator) Error() string { + return fmt.Sprintf("error: conflicting translator for locale '%s'", e.locale) +} + +// ErrConflictingTranslation is the error representing a conflicting translation +type ErrConflictingTranslation struct { + locale string + key interface{} + rule locales.PluralRule + text string +} + +// Error returns ErrConflictingTranslation's internal error text +func (e *ErrConflictingTranslation) Error() string { + + if _, ok := e.key.(string); !ok { + return fmt.Sprintf("error: conflicting key '%#v' rule '%s' with text '%s' for locale '%s', value being ignored", e.key, e.rule, e.text, e.locale) + } + + return fmt.Sprintf("error: conflicting key '%s' rule '%s' with text '%s' for locale '%s', value being ignored", e.key, e.rule, e.text, e.locale) +} + +// ErrRangeTranslation is the error representing a range translation error +type ErrRangeTranslation struct { + text string +} + +// Error returns ErrRangeTranslation's internal error text +func (e *ErrRangeTranslation) Error() string { + return e.text +} + +// ErrOrdinalTranslation is the error representing an ordinal translation error +type ErrOrdinalTranslation struct { + text string +} + +// Error returns ErrOrdinalTranslation's internal error text +func (e *ErrOrdinalTranslation) Error() string { + return e.text +} + +// ErrCardinalTranslation is the error representing a cardinal translation error +type ErrCardinalTranslation struct { + text string +} + +// Error returns ErrCardinalTranslation's internal error text +func (e *ErrCardinalTranslation) Error() string { + return e.text +} + +// ErrMissingPluralTranslation is the error signifying a missing translation given +// the locales plural rules. +type ErrMissingPluralTranslation struct { + locale string + key interface{} + rule locales.PluralRule + translationType string +} + +// Error returns ErrMissingPluralTranslation's internal error text +func (e *ErrMissingPluralTranslation) Error() string { + + if _, ok := e.key.(string); !ok { + return fmt.Sprintf("error: missing '%s' plural rule '%s' for translation with key '%#v' and locale '%s'", e.translationType, e.rule, e.key, e.locale) + } + + return fmt.Sprintf("error: missing '%s' plural rule '%s' for translation with key '%s' and locale '%s'", e.translationType, e.rule, e.key, e.locale) +} + +// ErrMissingBracket is the error representing a missing bracket in a translation +// eg. This is a {0 <-- missing ending '}' +type ErrMissingBracket struct { + locale string + key interface{} + text string +} + +// Error returns ErrMissingBracket error message +func (e *ErrMissingBracket) Error() string { + return fmt.Sprintf("error: missing bracket '{}', in translation. locale: '%s' key: '%v' text: '%s'", e.locale, e.key, e.text) +} + +// ErrBadParamSyntax is the error representing a bad parameter definition in a translation +// eg. This is a {must-be-int} +type ErrBadParamSyntax struct { + locale string + param string + key interface{} + text string +} + +// Error returns ErrBadParamSyntax error message +func (e *ErrBadParamSyntax) Error() string { + return fmt.Sprintf("error: bad parameter syntax, missing parameter '%s' in translation. locale: '%s' key: '%v' text: '%s'", e.param, e.locale, e.key, e.text) +} + +// import/export errors + +// ErrMissingLocale is the error representing an expected locale that could +// not be found aka locale not registered with the UniversalTranslator Instance +type ErrMissingLocale struct { + locale string +} + +// Error returns ErrMissingLocale's internal error text +func (e *ErrMissingLocale) Error() string { + return fmt.Sprintf("error: locale '%s' not registered.", e.locale) +} + +// ErrBadPluralDefinition is the error representing an incorrect plural definition +// usually found within translations defined within files during the import process. +type ErrBadPluralDefinition struct { + tl translation +} + +// Error returns ErrBadPluralDefinition's internal error text +func (e *ErrBadPluralDefinition) Error() string { + return fmt.Sprintf("error: bad plural definition '%#v'", e.tl) +} diff --git a/vendor/github.com/go-playground/universal-translator/import_export.go b/vendor/github.com/go-playground/universal-translator/import_export.go new file mode 100644 index 0000000000..1216f19237 --- /dev/null +++ b/vendor/github.com/go-playground/universal-translator/import_export.go @@ -0,0 +1,276 @@ +package ut + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "os" + "path/filepath" + + "io" + + "github.com/go-playground/locales" +) + +type translation struct { + Locale string `json:"locale"` + Key interface{} `json:"key"` // either string or integer + Translation string `json:"trans"` + PluralType string `json:"type,omitempty"` + PluralRule string `json:"rule,omitempty"` + OverrideExisting bool `json:"override,omitempty"` +} + +const ( + cardinalType = "Cardinal" + ordinalType = "Ordinal" + rangeType = "Range" +) + +// ImportExportFormat is the format of the file import or export +type ImportExportFormat uint8 + +// supported Export Formats +const ( + FormatJSON ImportExportFormat = iota +) + +// Export writes the translations out to a file on disk. +// +// NOTE: this currently only works with string or int translations keys. +func (t *UniversalTranslator) Export(format ImportExportFormat, dirname string) error { + + _, err := os.Stat(dirname) + fmt.Println(dirname, err, os.IsNotExist(err)) + if err != nil { + + if !os.IsNotExist(err) { + return err + } + + if err = os.MkdirAll(dirname, 0744); err != nil { + return err + } + } + + // build up translations + var trans []translation + var b []byte + var ext string + + for _, locale := range t.translators { + + for k, v := range locale.(*translator).translations { + trans = append(trans, translation{ + Locale: locale.Locale(), + Key: k, + Translation: v.text, + }) + } + + for k, pluralTrans := range locale.(*translator).cardinalTanslations { + + for i, plural := range pluralTrans { + + // leave enough for all plural rules + // but not all are set for all languages. + if plural == nil { + continue + } + + trans = append(trans, translation{ + Locale: locale.Locale(), + Key: k.(string), + Translation: plural.text, + PluralType: cardinalType, + PluralRule: locales.PluralRule(i).String(), + }) + } + } + + for k, pluralTrans := range locale.(*translator).ordinalTanslations { + + for i, plural := range pluralTrans { + + // leave enough for all plural rules + // but not all are set for all languages. + if plural == nil { + continue + } + + trans = append(trans, translation{ + Locale: locale.Locale(), + Key: k.(string), + Translation: plural.text, + PluralType: ordinalType, + PluralRule: locales.PluralRule(i).String(), + }) + } + } + + for k, pluralTrans := range locale.(*translator).rangeTanslations { + + for i, plural := range pluralTrans { + + // leave enough for all plural rules + // but not all are set for all languages. + if plural == nil { + continue + } + + trans = append(trans, translation{ + Locale: locale.Locale(), + Key: k.(string), + Translation: plural.text, + PluralType: rangeType, + PluralRule: locales.PluralRule(i).String(), + }) + } + } + + switch format { + case FormatJSON: + b, err = json.MarshalIndent(trans, "", " ") + ext = ".json" + } + + if err != nil { + return err + } + + err = ioutil.WriteFile(filepath.Join(dirname, fmt.Sprintf("%s%s", locale.Locale(), ext)), b, 0644) + if err != nil { + return err + } + + trans = trans[0:0] + } + + return nil +} + +// Import reads the translations out of a file or directory on disk. +// +// NOTE: this currently only works with string or int translations keys. +func (t *UniversalTranslator) Import(format ImportExportFormat, dirnameOrFilename string) error { + + fi, err := os.Stat(dirnameOrFilename) + if err != nil { + return err + } + + processFn := func(filename string) error { + + f, err := os.Open(filename) + if err != nil { + return err + } + defer f.Close() + + return t.ImportByReader(format, f) + } + + if !fi.IsDir() { + return processFn(dirnameOrFilename) + } + + // recursively go through directory + walker := func(path string, info os.FileInfo, err error) error { + + if info.IsDir() { + return nil + } + + switch format { + case FormatJSON: + // skip non JSON files + if filepath.Ext(info.Name()) != ".json" { + return nil + } + } + + return processFn(path) + } + + return filepath.Walk(dirnameOrFilename, walker) +} + +// ImportByReader imports the the translations found within the contents read from the supplied reader. +// +// NOTE: generally used when assets have been embedded into the binary and are already in memory. +func (t *UniversalTranslator) ImportByReader(format ImportExportFormat, reader io.Reader) error { + + b, err := ioutil.ReadAll(reader) + if err != nil { + return err + } + + var trans []translation + + switch format { + case FormatJSON: + err = json.Unmarshal(b, &trans) + } + + if err != nil { + return err + } + + for _, tl := range trans { + + locale, found := t.FindTranslator(tl.Locale) + if !found { + return &ErrMissingLocale{locale: tl.Locale} + } + + pr := stringToPR(tl.PluralRule) + + if pr == locales.PluralRuleUnknown { + + err = locale.Add(tl.Key, tl.Translation, tl.OverrideExisting) + if err != nil { + return err + } + + continue + } + + switch tl.PluralType { + case cardinalType: + err = locale.AddCardinal(tl.Key, tl.Translation, pr, tl.OverrideExisting) + case ordinalType: + err = locale.AddOrdinal(tl.Key, tl.Translation, pr, tl.OverrideExisting) + case rangeType: + err = locale.AddRange(tl.Key, tl.Translation, pr, tl.OverrideExisting) + default: + return &ErrBadPluralDefinition{tl: tl} + } + + if err != nil { + return err + } + } + + return nil +} + +func stringToPR(s string) locales.PluralRule { + + switch s { + case "Zero": + return locales.PluralRuleZero + case "One": + return locales.PluralRuleOne + case "Two": + return locales.PluralRuleTwo + case "Few": + return locales.PluralRuleFew + case "Many": + return locales.PluralRuleMany + case "Other": + return locales.PluralRuleOther + default: + return locales.PluralRuleUnknown + } + +} diff --git a/vendor/github.com/go-playground/universal-translator/logo.png b/vendor/github.com/go-playground/universal-translator/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..a37aa8c0cd0f6e1b98e0be3eb2531ebc6ac6717b GIT binary patch literal 16598 zcmV(yK*U_<=i=1Q$^7;0v#+eDrK0%p z>%6(N%f`XBv#;pk-N3xJlaY`9`tZ@r#>d0H&B?^Dtf>F`_3`TEoSK)csHK;dl)1LD z{xUb9o}0zMyZALSjf{%1BqI0!{{5jc`1SO`zPq8KpwB5MBz`@`DJHxnB>jUjr=XpP zhJ*ceGX0V>qah&tt}xmxDK3XPA9F;SA|8N$duRs?{%JJ*T{HG>5AcL8I*&O1Ju^KN z1^!Yp@h&apFDzno38}29au*Y6VF#%(B=Pd^`t{{04g#CPRH8PEL>89OH1Y4=wM`?Y+cnsCD|dZGb#-yb zPbYsY6v#U#TTlf1)HKmxCR88|TWkfi;WgJmEa>U!iH1CPzc%zlFUrZIxOpL50SAW2 zHrkRe-Bv8!+}rP-U23*Bp`mB-jzz%dHuKoF($TRq)t%&MEAPFIet}u?$D-;-NTfd? zqGBFudL7@{$H>RCmXS~SDk-e2cr(q3b}2D4;I^fdk8wf@!NHcex`pmIGxX}ykX2Zk zP#l(MXu)GF(Pvk zb5n$3uu@QfLrR3XE#bH{zmF;My}ImfZ|eE@n0GU+i65iC#kVv_JUkHP6q^ z=b4$1KRnawHnN9;XOVD+dTcU@PWtQI+{V7)vVb@}2{~W|d768ob{*KawLyATCMyBY zhk?3y?SQh*YZ(!U#KDNg9qaM-(p?CZPE$X(8z(y`Rk002FaNkl8uC7fajE|-h>jHG2b9lbevz(KOfu`z+X2)PND2t1w1WGFmB z;BZ@Tf}w8eW!d6lVUNJlhe<3w@VLAr5!hqYo=(frj?qrXhNe@r$z?o#)_BC$c#6Tn zw%ibJSrePzu1EE-o7FRWE@Bmr=0#t-W8=a(6GTqoYvcqTWN@=@*0!nMye8HIu2(T+Ak@9J5Z~>D99iw*`m8V%yP8G^_lKA3_-39D4+I+C1zz z%PxAIjtxqC6rEeEoK;TYRK5moFT3e)S;c473ltAKvc{hCWlVc;gKFP7(_^pP+TQSQ zjTnnuLBc{Sdb7KSnYy{T8Mi%*-`7X=bnva_VNVf!d<1rL=-JH6uuGF1?^y5f9AB6q zotFt+&fvKN9wTt?2px9TxG)4b)AV}%MO>l#`PSCbhc8CH z(ahGS3jt5QrHGrvLqpybTd3aT!_Ma3C?0!8iS}-@N4$|3Vjk~Odfkur_B2j4Q=ai9 zwCdFE-MgodJ$v@--@hOJdcD5T)wQs^+~2>veB#83lSsEgpFKBQ8LAYfrz?!j@VGrK zfD?mhnuhu zc6A*>`uqE-yqo0c(WA$Y&khU>p!`akr_C16;qx9(K3}Q48GMs(2|#W(U+C>U+gs?p z^6}jBk0WP#6@}XUG1|MFxifa;Gu`Gf@{^8r3D0vJ&-0ExB2Qql!KaO@u%q%RuxCa- z=nDq{@3OWa?o`}pF?bNzz;Q^nz?4c2d1Yzhk<6eIWaeu#=B8Cm810v^Rke)+e)?h zH``r9!+0zn64TyHj(U9NCw8Ir?OU83bm-%VH;0Wb>dWQso<4o4T$akBA7WgT3iz&_ zN#||w+mrl%lwSPt^Vg61UR6`~YFWHi_l{!JcULueSU zuU#7-U!wAd^F!yiGqsgYce}fpeBa&ns10GwH=8Hj)>BVDk~}BH;~@vhCnx{=D_1_h z9(z4@+Q`0r`z}a*NhgoKotri}dCcg8TMu47d)M~vT^slBr56_$zkgrMPE@N|O(WZ! zsLQ%0YpP1+LKrd6^35*)GUSB5)MzwrJS8#U4D>#RSz-pt?c=lJXO zeSaQ*)aC{sacalkE(o<+>1c~WPfGnKtu-k`2YJOl(N%r)u4fVPB7smYkR!~c!2?5` z13>TVn~)3sx0VVE3qQ8?KZ&MxkE4I%0~`Az9FB(`>c8OVKkXPppkEAHPbYRdx2|$6 zf*j~H;Ex?orIrKyj}eYAQ%S`h#fdpw@Cz<58T?>}2zx?ZT|%y(T{~Xpi=gkZTF;#e z3F=$F{`}PNFa>wR$HyM5Ztd#os_vSakjh6}Iy<|C2zX8|>ielr&R9gEe{Fo0|8gK| zkY8VlfcpEtiRi!U(S93Z-L~--2kINT8Vb8(?fP;$%dGar++*t=TX-4CqacXL~rY1d|=Z=r( zT@Q{j(+PIADfOvY)=!t^b(wRg^=0R7n8aR zGu)okchJ@@r~V1+Ujz8JBY#ZBac;u{>vE*5fRzYXDa*3>N)mKP)O|L;_+)+@W$#W_ z1HCSw0BPQbdWUK^n3k3~2){GaaiQou{J~fvivE1qGekZm14C^s_>uYe_~`Zew$6dh z&dz2jY$hilM;G9l1sq4)7Rn-P`H|OEqLr&S14g)DnOR!8zA!U0bMNinM7RaVpGDl; zY-jGh@Wtt|F$}V_tG&EfzS=j}cU7%lLF4S~p35Z7OJBR(*!bOV-xB?PmY6P)N+eR& zm~-CP8no)@pwxKED3P8YEr^+%?8q=F+vn#4EnG5nUJd7iSCx$h8STYo>M5XqKb%>U znOOtZDR(?fN4Uox1Ub*XkD$wZHf)e>(EIqv@I>f+HsGnMd7^oAVqjvh1vQ|K6RZ%6 zS(agDR(SBQc^!rdmzN8vK88rJqp)LqgEnqF@z805HGQJ@1$%=?VI znx@@zXBFMuwRP&sqPpVZvLw6xjS9oC{Zv}oug2jiu%}ZIcF@Ph^RCBI+pC^=W&^+h zj2nbIz;VS1L`O&K^(`$vP;`|5u!wLu!{jbqrQrBbaLVo`2m4qAM6qoVHq>>S?SyR` z*c}LXS5Tn6g}o`iI4?0VQ5zK%Rio1xlm=zWuo0G1 z^py0Jec*;-d4*BepMTH?oH9ZSY$|#H{6GG`^dbW~(Tbd;`3i5jm;5kK&YSMhLvC&3 zHVlp9eiusn*^WX_1XErv-9)w42ysdA?Q+H zW2CX6=ZBNdm?l$Xli3vMR5s}}x+#0!T+v)!UV9=H(9Y8J_>rsU{BkbR#TC3Ak&M^yN+acyB-!s$e-Ut;vL8ySlm4a z;eC8dRw94`tf=X%Uv6%$8=aRI9J<1TIMbMW6^gFu(4jHQl%}SF=r%{bpn^hWvR;$u# z?d{>=gnV=2*2E~n{(eP81u1Vp-=CRI+4rUIi{BUTb=|}MLKVTK$?cJhCIQZa#yajY zS(}2N?bT>;%*x8uf2KJB_nPh{ry9GsF6g#rFPyoz{6b}Ux%JHA;^J%)xNpWt!c`tW z{u(CNPsL)vuD!{O6hY2%>I8qZSX5O>PtGWEy~`Lmb<%8B>Xe$#4z(JbN}bN!q|z#P z103ko^(ZQx!H{Jz7!K^;PuL-zok!n77@PpuN3`=QIJaXNJwN>xw8No`D|!K~UHql+Qv5HWo# zB}cT^)aaC12QmqJ`hK3=ZTlv`6W5{ViSOGfIrW*|Np9;)2Kq```l9tRy)3$O^iF?{ zPUxJ75m{!I-KK-QaAxVc*K(Nd4R;SXqMht4{NEVX+)5Xg*@A@Hq<~LB?(fg+E!|uH zU3PZ%u1f#x_XH9a#ZAHrAeO}~uDGbkZnqajX~LVrJ32BtOdr;k&6(!Li-vb=RcYZo z`qr(9iCZ7x(X%SDkm@`-$X^FI#FKA=?VA8jd`GrF3{<|9@ts|UOIx>`TRl)x)i(4! zVqK1178248PoY+zy&b-K_%Oy7g$1LI+PVzSss7D$wDbGdl?MTRO~_3yx};tzTQz$r zSe*>=WM;>E0%_2DZ|vGpUk`K^A_F2WgkGGN_tjVSqN1X_;l#xEe>Y_`nRX?JRuvab z&g~`&C+yn9tq{;bzH_ItrY6OpN)iIAqhPS4RrcG0}H-ItzJ63yu82&@oOwU+_mf1X}n+g2RO*VZncK44<-BB z+G+Yq=F+7-dwvP<@5T-$&i;rIO9hgIw?BI0!*bRmde8z!{OebMCn_45k1IEu%%;5w zZ2pLs8`5bugFNbyN1`6vx%0719fnqA*1>c_p8opl;C9=-g_85G(`0|)akx&hT0i8E z*A@6EL~^dPMBnD8U_geo*8BDX#{gcTd}-NoZ9(W=)2}TPcDLmocn>*d*J+ov2jn5X zXFPA=Qd371{#Zkjvdg7$5|ZN*kx0rQ<9P{LJPXA|<1mAld=H zeF6pxh+y>)4x?&9&JdUXE;854k?u3tb-luOx$vDg{YKA04)&K8U7-bQ)+Wt*$g!p+ zd>R)h=2(eXDrI1_slN=}1S%ohp zYxPt}n<|U+ZLLX3DU^`n%%gKDue)jSGZ|@jXG+Vz=eq5l&YUz)X3nM`O}_;8bW6G= z_o!T>E7p}a=o+%+4G~%088Lh6<#L=(cY(ZrFR_KH+jR%FgZ+7u*Ku0ym53ZDlD%;M zDK00U$79jCFr3=+e>+Zd8Kbx^y8rpdw;+ePi0(rEcF{vXXUH9M*J=IbOtmtzv9U2p zZ8n=LDb51T5%B!EI7_u9F0HyYe&&bWyDz1GlxsT+qsKmW{8-WTmSZB|aUiV( zp-$K&$n7N5VfYthn(2a0mpq8WDj|Q##oe9cXkS151>`UX`LAYm5)73sDbrS_7t)At z*5MiTSA0^HksSw%*X)LU1ay357LSh~J$h6Zm8R3Ap?k~D-LOHIy{AFm-Px^**;QYa zRWHuV0((CzdpO8}4s*y3Xwud&^^FK$SLZ;dLr&F+Ft25_rg2cGMHE*=P(hwTxPLCH!Q#wALd+)uu>YY1x z@80P^ABRO1AI(Ks%hl*K+3~t~e6n@AtgJn{^)dCj`q*8&RP*TJAcw=-+1WIg>Og-! zi0R>uof>t-y6A!jjiN=dZvEf4lN?@2@VXN~XWf0N=0ImPpPrm-n>8vX&)n@Ol2R#B znbf1LwNQFh?-AAi|L(|>>jb9nKL5a# z9Oin*V%Hps8x@|4J7>=Pz-uLu-d02$AM6y*6+OQCyoDT5;^I)icc$llc4<5}_oyZ} z9q6GAFnMu9vAj6DbA5(iJ=DU~vNpz>?Ab;zfJ01KKV`b&+4+RMK#-yA2MrCG_ zjasUD`OG&}adz8*Hiir*E=5IYiqq0M(?ZkbGuepsVqLeqJEOB(2kKohauw41-dFoo zTMPU9LH@!E;jl%)zA-iRc}Di9+Jk~xPK8|TB|^jN?%g<&O~C;*1>ZTr|1HqT^~&AZ zt2|$RWm0odWs$lF-$Id8uw<=`?m#1}vaQK}T3tBj~iK{rDR^4%a1L}Fip6pKf zo^E+P(CcIO@2Z!pRH`=%LEgUw>`rv2>e~rA)5v2sH_8=VnBt-*_gW4*wPuqbAjy{F zg8t9slNhyMMJprJo3Y9#Q_FY~k2ZAkutg4!9=0@%*iP77rNsdba<2F7igPm&jID>o z#Kgo_Rqc*a9xqlw4X(wq?9avVNq zlfWb>_yT3k)!mnn1Ko?Cg6jldkn@@v0Zpnql3mf#LUJI^Vez+xlB;b|b15a~Lmi@X zJWG2YK1tUT^v0&MU$F+&){6@@u6Tr zjdB19{%^XtMFoAbLxMTGeca3`Dl2Pk)9Z^WWs<-7woPeKX~Znm6;#ut=)i4DZGI`h zOUtV7N~y{@4xQgO_dr`{X@zvA z9J2{nIpTZ?Ix9NJfxgt`Nv!vrR&C#Sx@&moL?lHYuRFE;i^icGLGYMgK=2as!*F+y zzYB7^=2C^ii(DQ062r07cvB{%yjs=fMwz`zF6@(vkk(-#is~cOIV0CsxT=)reLM7O z{`m-UPzCo=aF7%BcH;2FTvT^-HCu;GT{Si0(*uFSLtPj@?fr^guIS!|F@Y(-mgIM0 zaW8WisqhzQofDQsa1z#?_ca*OC3#HY)*TC(}?XH@?&Z-WxtL~JYjrGCdlLMQysqz8SfFa-G>$_VQx`Nh36<)yN?DnC)#7fB z!>_%4IZIsJ+?=ICB0tL7{@(1QvYaHs45Uw{tXPiEHi zq;9v>)C6A~O&ks3E?4zOPYwjEGlgLhcHN7M-5uy4zvVcsRg7q(#oprRXf3(HQ)IUJ z(u5qhYprT2kK(wXIgT4Cestix!M$rbb2e+FyM>a9riL|Pi${b zWYL!fd*tdHml<@G>e3Yo=eHL4-U>46j7L+xp|&jsyRdcav_GR z?TLwOu)`KNH6uRBVLeKlQl-)kmWV=@sXCVuBE7nXm4b>5UH&(vkkqhs7x<)`RO!=hk@B#+>Rab5%2HV z@qUDT;C_V5J-1;)dF|B@?)S7eM0aW)%WxBPyXuLse{y(u{0LS@BmIVYYLo{hWD2@W zboZVy!GJQ!6dA~Det&WKgV$KiKP2R^X|e|>@v@5htOl`G9KBCW0iDKWi+vohILtX5 z^p*J^*^es_9A7ZZoR6G~M`F*2FVBc^fIH)yC5P$^JM5o4eyi0V`;&p#WgX~oN6;>J z0et0m>jc5dfw0Ihzd--h$)=yy!QEN%TWxJW>+df)pr5|OSDf3oFFG2ZXzc}>q&b_B zMpg&^BI6+advZH0JMHW&ICIl5U)0LyHUE0eet<6}U*hm=L-*YCgZ@xG46Ceyo+d7D zd3%z`xob`i3j~46u;DJPA=%%@|0kPmUi4qEJc4B@?^XHJXFAqO`V1r1zKLtsR*;NE zNzF#Pd#CU{q(+zR9chQO!m{&Hv4xPQX#j3VXTf1#kFu$KhQ1i<)SPUJuM zj6L-LfC+56y*~W^lm#th`;^yuyU3>Y=Bs#gX zxN*THx|cicONSWMm{YK(W-A(|v90N^r041!rU`A>rg4C?uVnZw%yymDml4p z^m^gTU=MovKC&c}*us#r9&ZPCq7Nqfe2aR-pda$Z&s?U*NA?7pOv(Y%6~k)7gUQK0 zPXzxS#^$&-EO5FRvD@!aGJV(U+5=erBbz^6`zYjanHk5nd2`k^-vU{R(Sp&GUG>oM zZ5lf{)4a0iGhRQkVSen#&u&g#tE(%ltE+q2en+0jqO)y0J_P+)(#k#;`K>=vJhLjj zDUys|mm@j;KfzeA0IK^LwAwBofAX$JdD#!-1bxj)vM1(_E%vq6zP{+w){!n8mrh3; zP?>3?t*o`RwXLm94=ZA`CPfMH&zg&g9c98Cs=H{;pvT01{ONu+!|ngfTKN5O>D1Ks z9zV8_B>{)%4%Nf)K|f~~9kP!c9En^VwmOiYuRDl&ySn`A%x**wgO0!UE)4c?Ms(|g2CMy12+&Pq_u%a! ziOWhQZw%-Gfyx`CR6=wgpC=AI^yt$zfZw|H0Q}u;1(u~|^$B3tVn=nvYQ4ed2zgxS zE>vK*U!tfik_qSiodN)Tp2_W+;!qadsW~ZX1U+VRZAlf|$MhE>%)cUcmcFa5x76XP zJduPuW)*eUUzl&>!y);g^^r$>h9i^xfsWT$ICA<@{~MmBOC;O{I_0brprKJlb|J+N zgZ&Vmu|4|e&9I`IX0;XsGxg9iuu zuqIF5#P}!U6;uFJ7mT4u{r~d{{YO5J)tr*#)Qq8zwfTvo#i?CPtTX5!huvS|)--)a zw#q}{A!(XCZ|$>Mts^5NR&tLlRg*lYuGAyZt6S$YJjeGH{cYSNYBb}WgdFH;5svdY zJ~6}?^eSp<6xf?_U?H9R$5?|PZITxa^q>|(e$2hsyTr=+`}M~s1`m^+} zk2rdWpck2C5|LhA$x9JQGc#F_$6+?9IdeQ+jvIysW^EuLAuqlmuUj6mzB@0AxVyL$ z4qu-aJCQT;`sS@0+g~r-xOdA*nUt*3k`V|&2YJh}RphC_r-R6Ig#F?g!ysM&;#ElG zL7#6|M+Tbw0&44d(q-Q%l06rGzZ+>}TLX6*pw|{x?0MNM(^eHS2w6q_?+H`NP_lgzP>mx6aB=_u_k3P+) z?qe7vNjYG^WP0@gS$Q~#=Lw3FI z^kQ#lUte#p+rA4F$6!E4qNPdBj>arwkE;qgrLh@`!#X>ea{d=7=N{8m702;%aa^D< zV6csc@^TEk>mZD>DT%9=&`nn;gh)mlB7!rdB9AJME`b_S!eiwj ztdeHfL{c_bjmTcch>`u}|Hkh*x3{+)Iw$_<;Qj;ar@!axl#^7s(}uH{Y;^fAa2w@GE+?S3Ep z{Oz~%^F4tvUh2BKPS&D;Oly$Rx%c=!JlS~bVug~%%PXR^tFgEVUFh02#JbG1Hj4fs zK|iWiefYX6=Vd3lDs^3Z}T+Ya;&Ni@f!YgQA1J`fWyK%5;X(4!FEX-yLqx}StO zvq`UuOHP2T0^S!C>=UXTiWi?HgPSd*;fB$KaJ9bkRLETcolYqut+(&mx3K>6{O>(6 z(xBB&wIz3z1iCvgYY78VLd(Bg2Z+2ir8OlLRQf6^D$l010h^$|1oUdv`+2I5dGy!v zw0Uo7b($(eu6+&YXc+P65lgLzaR@ILFc;IX>f_gL+Az^7-f8e=hu$F%q3A7}estPl zClWei9YrA0N6X`Y}!prk%Okx6*BdR;WvleVA97X%R&DC&^KGs4G%(E9BPQ3WVdbTMFDE;wHAn3hB92y`<(J4RpFY&niX{j{c{56Ajx2`3ml z3fQ;c>p4Jo)B2IDr>0~gI!SKW&s+)ExP68iybs8Cn>KJ{GmNBl7`%LMaDv`qk|)q8 zHxsyH^j%19*lhfyv{Tm^M^|oc=wK(aO{nJfg)QB^NrbM+Cg#s=d3U|a7w%$7!w0WjnU;tsxcgfeU z!?dyx7KV9G__}WK*;7dg`FeRQjqo#4cN+G;pa+uVW{6GJVKT>Y@9r}s&UvEy?;{8Q z&z$ienRm*$b0Z@-4u%F5>Am6&pQ(Y?1u=tp?;Tih9fz8ispN9RXD5#@M; zUofRC52d6oL`9K%EKJWmrz2O^$de5Sa+{ki%nln=5G-1gS{}57_x38x_&7y$jFZ## zx)WV0t*op2e!iCY`o#BDyx=f6mT!;;VjCm~uFlJ6-XzA55Fs*gIpRz!<4JhY;1C}BLr<47kbpwp6LEtidvj$ud5s%uc(|KfsBujHs zu&DiuCeolf92|`Gx_Pw4UJ1D9V@qY-!+W&I#AW{29FwE2=PFt>@h#h zt83>+6l!>Rt$O|(1e@nSZo3i;tX{b|f1ug3=c{HsbI`g!Gpgm$tGA*1!O`1o2iI&x ze~V5d{Gu)+_2JOdQD)kZ&6#$XrqM%POeS3#xfef}x)b&Uawo^A)iBnHv>qa$3)#(Y zR|nLNF`uH5`Pw=Zv9=FJftcKx8M3trvP+}!MTCi;sSA~5@A^0wGD`#u@a zPY`s4>LQPxrPgNUXj3-qyEOLw<+i9bTa1v~Ku*z7&4C=f5?|kSQ)=pZSd@+)E_k?i zT4z2LVvRNH_2KEyau{9QA$#!gq;zw5EY|%xY(Y?Tu#1U(cRSU3Gql}Tr)Y!D;p>R+ zw(%-nUWEudt==&Ci0tMwJzX_LXTGT6u(Dv*>;aNd?bVmxQmIcUh_B~$Q*>zk{BFCy z%pTQYi!|7RM07$f6{4IEt}wZ~n3}pV7`B(#d)`p&b9#qEXHK?S^3&g(9w0+5GT9D{ zo{2i14x5j6bdF8;-V3=)J5(Y%&2B&sX#e?~Q^vo)NsRsGcy@L+4^NhF5{B*of!({N zr1aDBlG4(W&u9R;Zx5Bg*H2tkDNxI_=3$*$U6)m$%_z_Y_}WHCZGMPxqc+5MF~Ead zK!>mIj*LSIZ(1DGV+O=DsDIvc4_o5X4y&biF6F@NB*$Env3I157c78za&+`6tm$S$ ze7FT2*N~7?+Y>w32|7|a0vn=R8TE4rzCm92=1_5cNsWYotuwTg^)7#}SqeWW=VL&W z&F(X5U%YriMdV_JR;AL`W#y~TvkAJeX|ru=?%Td#qwm~S^`r3rdWmkw(A_ZEroDXB-mrlx2GAF?s==(t${^?w zUiWO9p;$Nv7+M5$C|z)MitbC$BcpUVD^JsFOHju4S{?LWD!ggyMk3}wPEN{}u3wi8 zkUd1N|8nb6fB#&6Z@)!7hCdi0E?dJqLVU;gxrsU|WE*0l z%F)~gbllSvYF?;4p6^DdPo+Iefy}C|^Ia#!LicZx|=kx;>#>W*m5$35-OP}~2($)sWSM+5L zV}#I2OF4kVH+~tA(W`!DFJ@7pL)Lh~OgZ6=68MPisZB)3;w5VTVLA2y%=mIR^!oVN za9o=7%<|Go>#b`m-M`^#21YutbVv5&T}nwX)w)%$9r>>m^wyho>i54Tc5$@-0|-^qv5389|oe03Z9LVZLDo@$A6KChyh0HFb zH|ekA^*^-Xq<(=~-FL`Hb?zd+to(?BY9G`5mrZ$+6K9vnVpwKiz>6mbx@hn2sV$OM zx`58#I~W^2XUVr*-@~%AlU^LLIT;BlEKM=)I%iqUKdFR$1L*kb*CV^R%J|T279Vra znbN;OkGa_B0*5r+_(=H?N}9)@vyFLnOlern>=agSth1P*!@GE9=pzJ1!2Y8(j?VDtI3JWOqCdKV*>@q}he~y2-0s-K{cKKo9a*x=?b8&f7b>u^^`# z%sPvuKfgeogGi~_NSvZWKRhb=lQR0m(e&}y`hKv*ItTLp1ie~L)Q%>VE6@SmrS>9S zop8E9eaLtW=m4kEnA=l$nS}C3RVZb_Q zLr^-sTY=1-lhBT_YrJoOi%O^Huy^;Q?o>K=1xUtEJY7?Lw5zbeUY7t>e@cVp)&9rjhRZL@fiLU zrln!fK{?De4Re>ji@tQZr)STlo*U5|+k?w_7{SVxy8+FklYbz`r^BqH6dUm7(J8rS zCC8(KT(EbX@d`PmvtZT@qCVohi>Ld*B$kaXduBN)RY5fS4+&j-@}B`Z#sT6_jg1|5 zQ#-m;e1nd%<0_h=PNX#j&POZG76Kd8g+`pxtWE^ zON@Zd>}y5+D#o}g10)b5_$AIpgIp6BNR=*F+*~lm}B~8kn%Sz?&C8hFo&_{(Bb_!y|k|xpJD$#tM6v`FKZc zQ~INxPFy{1I_G(iQ*?DcnQ5hw1GXa-K4flvSxOT1azhW<|(3Ixh;XVH5*TL2eCp0E53{WhKEG`gQ5;{d6>n1~Y%ma5 ze%K}aNC~DK+Vp_bAjJX&l~pX!HM@JUkSiCE6(PF9szj`{VmUYnXKNuyYDA-?mnbI= zsh~ZyRfU{fDpf5|C4zE^Q2q(TcV>4o9$LVOR9;-yQ7`@Y`{vD?H?#AWj`#f-Tvb8Q zUxWKlaGD_9;s-W;cL!JpYxaX9{H|njNAxrP{08)3)lS)azB%(9Qkr}U?AFTRqbo-b zTZUFDhsq_bTvp4Lx;{EpLvo`M^rK}B=xpIG%i}ZL;Rk1KDR4;S-xqIb96ccCbGjfp zVqD)Z!Ce(JzK^vBkLS;AqgJx}6XJ(3+PUn0kpH{vllyxveEH@X`^Y5bH zJ^uSU3>{aL@axuK2%L&cu2tNv0bO7hWcOYE(F<#j|L_L}`pfU;&!0?zdu64RR?CK= zOP65uu<`3BHspiAXcZJDAca~fGrg@ zXaUNypPzhv!T|cGVXbP_jO{5Sw?W=(En_)N(2?B$eXCq1IZZ<^LUX_)o>TO(4;^ez zlZuqxP(hyLE{ivC?6?#-Q@L5-8-bNImmP%IEA*pTR~CjEX8 z>A)_?&e&qn8IoWk7-CsWpnHEm4E)p9JqzF|z|j9S{59x_T{BPGjLSp#~jHQiDq zsGg;YW;(C;L2N8*xG7Ur(2`b z8bu!(CFsatG1p-T$UZs|9U086-xhmRX~Aq@w%2m8^k#3-ZFF_ndLtHP`GtGq!0v zF(NuA?-t2{4)Wg*ku4V(*eCs~(j&iZ!r?(axGLfd-NZEC>G{!N$R4mC5ZNI+Vej5I zn}=C>ihe7XZ|1j>Eu(4}O4({!B`sA-!_$vinp{q`q;;za^stn1OfTsG&iSKXRNxrc%gd^^9xB5b@^qq~|8u$i?VRV;s)e zf3rCiOXGobOKn<)Va2d;l?Zwhi&p#<);vsZwwX=Nn-#}|`{(8h+MJ%4vvZD?gEOtE0_g@+bTz-JE3tKTXm%mBT z^LK7yBdUL~7w|#fgS3hXN=v3Unl-gnBF?@MADXTjHBuFI^^8Owlkn`cr-xk~GHVT6 z#mn>-^h(q-l*t_jANT-SAV8EK@>Q9n2(Ueq}&dkrOkQyCnK;ggPO| z!yt^^*Ig{wK!&^Lanorve**{f19reCeD?G>rPnliRX8yXIZHf5&~vKoNYWQ(*fz-* z;M!rwjoWTUpPSd?b=&sliR6qt&>W%*1D%m$NS>BNOZ>WuaL+ZDw=a%ugIoqxhoO$i zPT7Ip&JOh1>l3g~w^?jVcxVAZ8$PIk`gn^Ic*!H^URYH!r*tQ3yJ=+Z`dpMqp7Gq=oE`nlZHw)q z<}8`Pyv9Ty7BW^A+L-Fd;#SWMUWE3$YX$SzC9eC9%Tsndasz)S=<92=XoJ-|7oJLw z{ubjnFh|C`N(Vmp@h9Zzu?)~L%jvq8Fy|4~qlIEtuefH^p6h8iEpuL&)dX@RGsN9F z`N);~?C60q#6BxMSIPP{#5UbJp5PceOX}Lf{8tqHgB#sJ!AgJ^y4)AOy<2b!$cE8t%=oOIDMpsA~@74TSHqZwM`NJLD9VqXm`O76C)V;u~ zRZEY*_`}3`kgxeg8yII7;h9nLG|;s=vi7XrsO$6fLN-&V7xe|#?6KXt9?95quH7GD z)A{Y2ocy^Uxcj0H_yc`-JoMifd%DEn8K5(EA=JU=ucIf&ylJtPPZ13ae}EbQrV zV26r&v4U421KtMG8GFGj7VWNxQ_yGk`{d-P)Sm!n`72G`LEb*lp9=jK8G`zrYrqR+?Y^hyzW7cvbqA4f-Sr5ueUzLvaeN$c zN4~mq=gtS4q#5s%SFUt3c+fwz)XZ9+$XWABkh2YCQFBE14o3Rk8(kf|4|{N)uJ1bFF9hp%-l;Rvb+;eJ;5k1mnn*vn zRR5`tmENP7u0(G#8I97WR;;HNeh)bt=Pb5U&1rCd;(_ZHiyEwno#Y`YP z=)oSiJ!{S?@Z$sdh<6zNiBL0eLe3l2ve3@Qxsb|0^hxP~+r$6B&T?ARtbF0Q@`N77 z;R&Z;nSQP}xQPjUTE$82e&nx658Oi1fxoe{+C1BsAngAEz5qf00MAd3Cq<=4x Z{{;$xH 0 && tarr[rule] != nil && !override { + return &ErrConflictingTranslation{locale: t.Locale(), key: key, rule: rule, text: text} + } + + } else { + tarr = make([]*transText, 7) + t.cardinalTanslations[key] = tarr + } + + trans := &transText{ + text: text, + indexes: make([]int, 2), + } + + tarr[rule] = trans + + idx := strings.Index(text, paramZero) + if idx == -1 { + tarr[rule] = nil + return &ErrCardinalTranslation{text: fmt.Sprintf("error: parameter '%s' not found, may want to use 'Add' instead of 'AddCardinal'. locale: '%s' key: '%v' text: '%s'", paramZero, t.Locale(), key, text)} + } + + trans.indexes[0] = idx + trans.indexes[1] = idx + len(paramZero) + + return nil +} + +// AddOrdinal adds an ordinal plural translation for a particular language/locale +// {0} is the only replacement type accepted and only one variable is accepted as +// multiple cannot be used for a plural rule determination, unless it is a range; +// see AddRange below. +// eg. in locale 'en' one: '{0}st day of spring' other: '{0}nd day of spring' - 1st, 2nd, 3rd... +func (t *translator) AddOrdinal(key interface{}, text string, rule locales.PluralRule, override bool) error { + + var verified bool + + // verify plural rule exists for locale + for _, pr := range t.PluralsOrdinal() { + if pr == rule { + verified = true + break + } + } + + if !verified { + return &ErrOrdinalTranslation{text: fmt.Sprintf("error: ordinal plural rule '%s' does not exist for locale '%s' key: '%v' text: '%s'", rule, t.Locale(), key, text)} + } + + tarr, ok := t.ordinalTanslations[key] + if ok { + // verify not adding a conflicting record + if len(tarr) > 0 && tarr[rule] != nil && !override { + return &ErrConflictingTranslation{locale: t.Locale(), key: key, rule: rule, text: text} + } + + } else { + tarr = make([]*transText, 7) + t.ordinalTanslations[key] = tarr + } + + trans := &transText{ + text: text, + indexes: make([]int, 2), + } + + tarr[rule] = trans + + idx := strings.Index(text, paramZero) + if idx == -1 { + tarr[rule] = nil + return &ErrOrdinalTranslation{text: fmt.Sprintf("error: parameter '%s' not found, may want to use 'Add' instead of 'AddOrdinal'. locale: '%s' key: '%v' text: '%s'", paramZero, t.Locale(), key, text)} + } + + trans.indexes[0] = idx + trans.indexes[1] = idx + len(paramZero) + + return nil +} + +// AddRange adds a range plural translation for a particular language/locale +// {0} and {1} are the only replacement types accepted and only these are accepted. +// eg. in locale 'nl' one: '{0}-{1} day left' other: '{0}-{1} days left' +func (t *translator) AddRange(key interface{}, text string, rule locales.PluralRule, override bool) error { + + var verified bool + + // verify plural rule exists for locale + for _, pr := range t.PluralsRange() { + if pr == rule { + verified = true + break + } + } + + if !verified { + return &ErrRangeTranslation{text: fmt.Sprintf("error: range plural rule '%s' does not exist for locale '%s' key: '%v' text: '%s'", rule, t.Locale(), key, text)} + } + + tarr, ok := t.rangeTanslations[key] + if ok { + // verify not adding a conflicting record + if len(tarr) > 0 && tarr[rule] != nil && !override { + return &ErrConflictingTranslation{locale: t.Locale(), key: key, rule: rule, text: text} + } + + } else { + tarr = make([]*transText, 7) + t.rangeTanslations[key] = tarr + } + + trans := &transText{ + text: text, + indexes: make([]int, 4), + } + + tarr[rule] = trans + + idx := strings.Index(text, paramZero) + if idx == -1 { + tarr[rule] = nil + return &ErrRangeTranslation{text: fmt.Sprintf("error: parameter '%s' not found, are you sure you're adding a Range Translation? locale: '%s' key: '%v' text: '%s'", paramZero, t.Locale(), key, text)} + } + + trans.indexes[0] = idx + trans.indexes[1] = idx + len(paramZero) + + idx = strings.Index(text, paramOne) + if idx == -1 { + tarr[rule] = nil + return &ErrRangeTranslation{text: fmt.Sprintf("error: parameter '%s' not found, a Range Translation requires two parameters. locale: '%s' key: '%v' text: '%s'", paramOne, t.Locale(), key, text)} + } + + trans.indexes[2] = idx + trans.indexes[3] = idx + len(paramOne) + + return nil +} + +// T creates the translation for the locale given the 'key' and params passed in +func (t *translator) T(key interface{}, params ...string) (string, error) { + + trans, ok := t.translations[key] + if !ok { + return unknownTranslation, ErrUnknowTranslation + } + + b := make([]byte, 0, 64) + + var start, end, count int + + for i := 0; i < len(trans.indexes); i++ { + end = trans.indexes[i] + b = append(b, trans.text[start:end]...) + b = append(b, params[count]...) + i++ + start = trans.indexes[i] + count++ + } + + b = append(b, trans.text[start:]...) + + return string(b), nil +} + +// C creates the cardinal translation for the locale given the 'key', 'num' and 'digit' arguments and param passed in +func (t *translator) C(key interface{}, num float64, digits uint64, param string) (string, error) { + + tarr, ok := t.cardinalTanslations[key] + if !ok { + return unknownTranslation, ErrUnknowTranslation + } + + rule := t.CardinalPluralRule(num, digits) + + trans := tarr[rule] + + b := make([]byte, 0, 64) + b = append(b, trans.text[:trans.indexes[0]]...) + b = append(b, param...) + b = append(b, trans.text[trans.indexes[1]:]...) + + return string(b), nil +} + +// O creates the ordinal translation for the locale given the 'key', 'num' and 'digit' arguments and param passed in +func (t *translator) O(key interface{}, num float64, digits uint64, param string) (string, error) { + + tarr, ok := t.ordinalTanslations[key] + if !ok { + return unknownTranslation, ErrUnknowTranslation + } + + rule := t.OrdinalPluralRule(num, digits) + + trans := tarr[rule] + + b := make([]byte, 0, 64) + b = append(b, trans.text[:trans.indexes[0]]...) + b = append(b, param...) + b = append(b, trans.text[trans.indexes[1]:]...) + + return string(b), nil +} + +// R creates the range translation for the locale given the 'key', 'num1', 'digit1', 'num2' and 'digit2' arguments +// and 'param1' and 'param2' passed in +func (t *translator) R(key interface{}, num1 float64, digits1 uint64, num2 float64, digits2 uint64, param1, param2 string) (string, error) { + + tarr, ok := t.rangeTanslations[key] + if !ok { + return unknownTranslation, ErrUnknowTranslation + } + + rule := t.RangePluralRule(num1, digits1, num2, digits2) + + trans := tarr[rule] + + b := make([]byte, 0, 64) + b = append(b, trans.text[:trans.indexes[0]]...) + b = append(b, param1...) + b = append(b, trans.text[trans.indexes[1]:trans.indexes[2]]...) + b = append(b, param2...) + b = append(b, trans.text[trans.indexes[3]:]...) + + return string(b), nil +} + +// VerifyTranslations checks to ensures that no plural rules have been +// missed within the translations. +func (t *translator) VerifyTranslations() error { + + for k, v := range t.cardinalTanslations { + + for _, rule := range t.PluralsCardinal() { + + if v[rule] == nil { + return &ErrMissingPluralTranslation{locale: t.Locale(), translationType: "plural", rule: rule, key: k} + } + } + } + + for k, v := range t.ordinalTanslations { + + for _, rule := range t.PluralsOrdinal() { + + if v[rule] == nil { + return &ErrMissingPluralTranslation{locale: t.Locale(), translationType: "ordinal", rule: rule, key: k} + } + } + } + + for k, v := range t.rangeTanslations { + + for _, rule := range t.PluralsRange() { + + if v[rule] == nil { + return &ErrMissingPluralTranslation{locale: t.Locale(), translationType: "range", rule: rule, key: k} + } + } + } + + return nil +} diff --git a/vendor/github.com/go-playground/universal-translator/universal_translator.go b/vendor/github.com/go-playground/universal-translator/universal_translator.go new file mode 100644 index 0000000000..dbf707f5c7 --- /dev/null +++ b/vendor/github.com/go-playground/universal-translator/universal_translator.go @@ -0,0 +1,113 @@ +package ut + +import ( + "strings" + + "github.com/go-playground/locales" +) + +// UniversalTranslator holds all locale & translation data +type UniversalTranslator struct { + translators map[string]Translator + fallback Translator +} + +// New returns a new UniversalTranslator instance set with +// the fallback locale and locales it should support +func New(fallback locales.Translator, supportedLocales ...locales.Translator) *UniversalTranslator { + + t := &UniversalTranslator{ + translators: make(map[string]Translator), + } + + for _, v := range supportedLocales { + + trans := newTranslator(v) + t.translators[strings.ToLower(trans.Locale())] = trans + + if fallback.Locale() == v.Locale() { + t.fallback = trans + } + } + + if t.fallback == nil && fallback != nil { + t.fallback = newTranslator(fallback) + } + + return t +} + +// FindTranslator trys to find a Translator based on an array of locales +// and returns the first one it can find, otherwise returns the +// fallback translator. +func (t *UniversalTranslator) FindTranslator(locales ...string) (trans Translator, found bool) { + + for _, locale := range locales { + + if trans, found = t.translators[strings.ToLower(locale)]; found { + return + } + } + + return t.fallback, false +} + +// GetTranslator returns the specified translator for the given locale, +// or fallback if not found +func (t *UniversalTranslator) GetTranslator(locale string) (trans Translator, found bool) { + + if trans, found = t.translators[strings.ToLower(locale)]; found { + return + } + + return t.fallback, false +} + +// GetFallback returns the fallback locale +func (t *UniversalTranslator) GetFallback() Translator { + return t.fallback +} + +// AddTranslator adds the supplied translator, if it already exists the override param +// will be checked and if false an error will be returned, otherwise the translator will be +// overridden; if the fallback matches the supplied translator it will be overridden as well +// NOTE: this is normally only used when translator is embedded within a library +func (t *UniversalTranslator) AddTranslator(translator locales.Translator, override bool) error { + + lc := strings.ToLower(translator.Locale()) + _, ok := t.translators[lc] + if ok && !override { + return &ErrExistingTranslator{locale: translator.Locale()} + } + + trans := newTranslator(translator) + + if t.fallback.Locale() == translator.Locale() { + + // because it's optional to have a fallback, I don't impose that limitation + // don't know why you wouldn't but... + if !override { + return &ErrExistingTranslator{locale: translator.Locale()} + } + + t.fallback = trans + } + + t.translators[lc] = trans + + return nil +} + +// VerifyTranslations runs through all locales and identifies any issues +// eg. missing plural rules for a locale +func (t *UniversalTranslator) VerifyTranslations() (err error) { + + for _, trans := range t.translators { + err = trans.VerifyTranslations() + if err != nil { + return + } + } + + return +} diff --git a/vendor/github.com/go-playground/validator/v10/.gitignore b/vendor/github.com/go-playground/validator/v10/.gitignore new file mode 100644 index 0000000000..6e43fac0d5 --- /dev/null +++ b/vendor/github.com/go-playground/validator/v10/.gitignore @@ -0,0 +1,30 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test +bin + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test +*.prof +*.test +*.out +*.txt +cover.html +README.html diff --git a/vendor/github.com/go-playground/validator/v10/LICENSE b/vendor/github.com/go-playground/validator/v10/LICENSE new file mode 100644 index 0000000000..6a2ae9aa4d --- /dev/null +++ b/vendor/github.com/go-playground/validator/v10/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2015 Dean Karn + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/vendor/github.com/go-playground/validator/v10/MAINTAINERS.md b/vendor/github.com/go-playground/validator/v10/MAINTAINERS.md new file mode 100644 index 0000000000..b809c4ce12 --- /dev/null +++ b/vendor/github.com/go-playground/validator/v10/MAINTAINERS.md @@ -0,0 +1,16 @@ +## Maintainers Guide + +### Semantic Versioning +Semantic versioning as defined [here](https://semver.org) must be strictly adhered to. + +### External Dependencies +Any new external dependencies MUST: +- Have a compatible LICENSE present. +- Be actively maintained. +- Be approved by @go-playground/admins + +### PR Merge Requirements +- Up-to-date branch. +- Passing tests and linting. +- CODEOWNERS approval. +- Tests that cover both the Happy and Unhappy paths. \ No newline at end of file diff --git a/vendor/github.com/go-playground/validator/v10/Makefile b/vendor/github.com/go-playground/validator/v10/Makefile new file mode 100644 index 0000000000..ec3455bd59 --- /dev/null +++ b/vendor/github.com/go-playground/validator/v10/Makefile @@ -0,0 +1,18 @@ +GOCMD=GO111MODULE=on go + +linters-install: + @golangci-lint --version >/dev/null 2>&1 || { \ + echo "installing linting tools..."; \ + curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh| sh -s v1.41.1; \ + } + +lint: linters-install + golangci-lint run + +test: + $(GOCMD) test -cover -race ./... + +bench: + $(GOCMD) test -bench=. -benchmem ./... + +.PHONY: test lint linters-install \ No newline at end of file diff --git a/vendor/github.com/go-playground/validator/v10/README.md b/vendor/github.com/go-playground/validator/v10/README.md new file mode 100644 index 0000000000..9d0a79e98c --- /dev/null +++ b/vendor/github.com/go-playground/validator/v10/README.md @@ -0,0 +1,338 @@ +Package validator +================= +[![Join the chat at https://gitter.im/go-playground/validator](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/go-playground/validator?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +![Project status](https://img.shields.io/badge/version-10.11.1-green.svg) +[![Build Status](https://travis-ci.org/go-playground/validator.svg?branch=master)](https://travis-ci.org/go-playground/validator) +[![Coverage Status](https://coveralls.io/repos/go-playground/validator/badge.svg?branch=master&service=github)](https://coveralls.io/github/go-playground/validator?branch=master) +[![Go Report Card](https://goreportcard.com/badge/github.com/go-playground/validator)](https://goreportcard.com/report/github.com/go-playground/validator) +[![GoDoc](https://godoc.org/github.com/go-playground/validator?status.svg)](https://pkg.go.dev/github.com/go-playground/validator/v10) +![License](https://img.shields.io/dub/l/vibe-d.svg) + +Package validator implements value validations for structs and individual fields based on tags. + +It has the following **unique** features: + +- Cross Field and Cross Struct validations by using validation tags or custom validators. +- Slice, Array and Map diving, which allows any or all levels of a multidimensional field to be validated. +- Ability to dive into both map keys and values for validation +- Handles type interface by determining it's underlying type prior to validation. +- Handles custom field types such as sql driver Valuer see [Valuer](https://golang.org/src/database/sql/driver/types.go?s=1210:1293#L29) +- Alias validation tags, which allows for mapping of several validations to a single tag for easier defining of validations on structs +- Extraction of custom defined Field Name e.g. can specify to extract the JSON name while validating and have it available in the resulting FieldError +- Customizable i18n aware error messages. +- Default validator for the [gin](https://github.com/gin-gonic/gin) web framework; upgrading from v8 to v9 in gin see [here](https://github.com/go-playground/validator/tree/master/_examples/gin-upgrading-overriding) + +Installation +------------ + +Use go get. + + go get github.com/go-playground/validator/v10 + +Then import the validator package into your own code. + + import "github.com/go-playground/validator/v10" + +Error Return Value +------- + +Validation functions return type error + +They return type error to avoid the issue discussed in the following, where err is always != nil: + +* http://stackoverflow.com/a/29138676/3158232 +* https://github.com/go-playground/validator/issues/134 + +Validator returns only InvalidValidationError for bad validation input, nil or ValidationErrors as type error; so, in your code all you need to do is check if the error returned is not nil, and if it's not check if error is InvalidValidationError ( if necessary, most of the time it isn't ) type cast it to type ValidationErrors like so: + +```go +err := validate.Struct(mystruct) +validationErrors := err.(validator.ValidationErrors) + ``` + +Usage and documentation +------ + +Please see https://pkg.go.dev/github.com/go-playground/validator/v10 for detailed usage docs. + +##### Examples: + +- [Simple](https://github.com/go-playground/validator/blob/master/_examples/simple/main.go) +- [Custom Field Types](https://github.com/go-playground/validator/blob/master/_examples/custom/main.go) +- [Struct Level](https://github.com/go-playground/validator/blob/master/_examples/struct-level/main.go) +- [Translations & Custom Errors](https://github.com/go-playground/validator/blob/master/_examples/translations/main.go) +- [Gin upgrade and/or override validator](https://github.com/go-playground/validator/tree/v9/_examples/gin-upgrading-overriding) +- [wash - an example application putting it all together](https://github.com/bluesuncorp/wash) + +Baked-in Validations +------ + +### Fields: + +| Tag | Description | +| - | - | +| eqcsfield | Field Equals Another Field (relative)| +| eqfield | Field Equals Another Field | +| fieldcontains | NOT DOCUMENTED IN doc.go | +| fieldexcludes | NOT DOCUMENTED IN doc.go | +| gtcsfield | Field Greater Than Another Relative Field | +| gtecsfield | Field Greater Than or Equal To Another Relative Field | +| gtefield | Field Greater Than or Equal To Another Field | +| gtfield | Field Greater Than Another Field | +| ltcsfield | Less Than Another Relative Field | +| ltecsfield | Less Than or Equal To Another Relative Field | +| ltefield | Less Than or Equal To Another Field | +| ltfield | Less Than Another Field | +| necsfield | Field Does Not Equal Another Field (relative) | +| nefield | Field Does Not Equal Another Field | + +### Network: + +| Tag | Description | +| - | - | +| cidr | Classless Inter-Domain Routing CIDR | +| cidrv4 | Classless Inter-Domain Routing CIDRv4 | +| cidrv6 | Classless Inter-Domain Routing CIDRv6 | +| datauri | Data URL | +| fqdn | Full Qualified Domain Name (FQDN) | +| hostname | Hostname RFC 952 | +| hostname_port | HostPort | +| hostname_rfc1123 | Hostname RFC 1123 | +| ip | Internet Protocol Address IP | +| ip4_addr | Internet Protocol Address IPv4 | +| ip6_addr | Internet Protocol Address IPv6 | +| ip_addr | Internet Protocol Address IP | +| ipv4 | Internet Protocol Address IPv4 | +| ipv6 | Internet Protocol Address IPv6 | +| mac | Media Access Control Address MAC | +| tcp4_addr | Transmission Control Protocol Address TCPv4 | +| tcp6_addr | Transmission Control Protocol Address TCPv6 | +| tcp_addr | Transmission Control Protocol Address TCP | +| udp4_addr | User Datagram Protocol Address UDPv4 | +| udp6_addr | User Datagram Protocol Address UDPv6 | +| udp_addr | User Datagram Protocol Address UDP | +| unix_addr | Unix domain socket end point Address | +| uri | URI String | +| url | URL String | +| url_encoded | URL Encoded | +| urn_rfc2141 | Urn RFC 2141 String | + +### Strings: + +| Tag | Description | +| - | - | +| alpha | Alpha Only | +| alphanum | Alphanumeric | +| alphanumunicode | Alphanumeric Unicode | +| alphaunicode | Alpha Unicode | +| ascii | ASCII | +| boolean | Boolean | +| contains | Contains | +| containsany | Contains Any | +| containsrune | Contains Rune | +| endsnotwith | Ends Not With | +| endswith | Ends With | +| excludes | Excludes | +| excludesall | Excludes All | +| excludesrune | Excludes Rune | +| lowercase | Lowercase | +| multibyte | Multi-Byte Characters | +| number | NOT DOCUMENTED IN doc.go | +| numeric | Numeric | +| printascii | Printable ASCII | +| startsnotwith | Starts Not With | +| startswith | Starts With | +| uppercase | Uppercase | + +### Format: +| Tag | Description | +| - | - | +| base64 | Base64 String | +| base64url | Base64URL String | +| bic | Business Identifier Code (ISO 9362) | +| bcp47_language_tag | Language tag (BCP 47) | +| btc_addr | Bitcoin Address | +| btc_addr_bech32 | Bitcoin Bech32 Address (segwit) | +| credit_card | Credit Card Number | +| datetime | Datetime | +| e164 | e164 formatted phone number | +| email | E-mail String +| eth_addr | Ethereum Address | +| hexadecimal | Hexadecimal String | +| hexcolor | Hexcolor String | +| hsl | HSL String | +| hsla | HSLA String | +| html | HTML Tags | +| html_encoded | HTML Encoded | +| isbn | International Standard Book Number | +| isbn10 | International Standard Book Number 10 | +| isbn13 | International Standard Book Number 13 | +| iso3166_1_alpha2 | Two-letter country code (ISO 3166-1 alpha-2) | +| iso3166_1_alpha3 | Three-letter country code (ISO 3166-1 alpha-3) | +| iso3166_1_alpha_numeric | Numeric country code (ISO 3166-1 numeric) | +| iso3166_2 | Country subdivision code (ISO 3166-2) | +| iso4217 | Currency code (ISO 4217) | +| json | JSON | +| jwt | JSON Web Token (JWT) | +| latitude | Latitude | +| longitude | Longitude | +| postcode_iso3166_alpha2 | Postcode | +| postcode_iso3166_alpha2_field | Postcode | +| rgb | RGB String | +| rgba | RGBA String | +| ssn | Social Security Number SSN | +| timezone | Timezone | +| uuid | Universally Unique Identifier UUID | +| uuid3 | Universally Unique Identifier UUID v3 | +| uuid3_rfc4122 | Universally Unique Identifier UUID v3 RFC4122 | +| uuid4 | Universally Unique Identifier UUID v4 | +| uuid4_rfc4122 | Universally Unique Identifier UUID v4 RFC4122 | +| uuid5 | Universally Unique Identifier UUID v5 | +| uuid5_rfc4122 | Universally Unique Identifier UUID v5 RFC4122 | +| uuid_rfc4122 | Universally Unique Identifier UUID RFC4122 | +| md4 | MD4 hash | +| md5 | MD5 hash | +| sha256 | SHA256 hash | +| sha384 | SHA384 hash | +| sha512 | SHA512 hash | +| ripemd128 | RIPEMD-128 hash | +| ripemd128 | RIPEMD-160 hash | +| tiger128 | TIGER128 hash | +| tiger160 | TIGER160 hash | +| tiger192 | TIGER192 hash | +| semver | Semantic Versioning 2.0.0 | +| ulid | Universally Unique Lexicographically Sortable Identifier ULID | + +### Comparisons: +| Tag | Description | +| - | - | +| eq | Equals | +| gt | Greater than| +| gte | Greater than or equal | +| lt | Less Than | +| lte | Less Than or Equal | +| ne | Not Equal | + +### Other: +| Tag | Description | +| - | - | +| dir | Directory | +| file | File path | +| isdefault | Is Default | +| len | Length | +| max | Maximum | +| min | Minimum | +| oneof | One Of | +| required | Required | +| required_if | Required If | +| required_unless | Required Unless | +| required_with | Required With | +| required_with_all | Required With All | +| required_without | Required Without | +| required_without_all | Required Without All | +| excluded_if | Excluded If | +| excluded_unless | Excluded Unless | +| excluded_with | Excluded With | +| excluded_with_all | Excluded With All | +| excluded_without | Excluded Without | +| excluded_without_all | Excluded Without All | +| unique | Unique | + +#### Aliases: +| Tag | Description | +| - | - | +| iscolor | hexcolor\|rgb\|rgba\|hsl\|hsla | +| country_code | iso3166_1_alpha2\|iso3166_1_alpha3\|iso3166_1_alpha_numeric | + +Benchmarks +------ +###### Run on MacBook Pro (15-inch, 2017) go version go1.10.2 darwin/amd64 +```go +goos: darwin +goarch: amd64 +pkg: github.com/go-playground/validator +BenchmarkFieldSuccess-8 20000000 83.6 ns/op 0 B/op 0 allocs/op +BenchmarkFieldSuccessParallel-8 50000000 26.8 ns/op 0 B/op 0 allocs/op +BenchmarkFieldFailure-8 5000000 291 ns/op 208 B/op 4 allocs/op +BenchmarkFieldFailureParallel-8 20000000 107 ns/op 208 B/op 4 allocs/op +BenchmarkFieldArrayDiveSuccess-8 2000000 623 ns/op 201 B/op 11 allocs/op +BenchmarkFieldArrayDiveSuccessParallel-8 10000000 237 ns/op 201 B/op 11 allocs/op +BenchmarkFieldArrayDiveFailure-8 2000000 859 ns/op 412 B/op 16 allocs/op +BenchmarkFieldArrayDiveFailureParallel-8 5000000 335 ns/op 413 B/op 16 allocs/op +BenchmarkFieldMapDiveSuccess-8 1000000 1292 ns/op 432 B/op 18 allocs/op +BenchmarkFieldMapDiveSuccessParallel-8 3000000 467 ns/op 432 B/op 18 allocs/op +BenchmarkFieldMapDiveFailure-8 1000000 1082 ns/op 512 B/op 16 allocs/op +BenchmarkFieldMapDiveFailureParallel-8 5000000 425 ns/op 512 B/op 16 allocs/op +BenchmarkFieldMapDiveWithKeysSuccess-8 1000000 1539 ns/op 480 B/op 21 allocs/op +BenchmarkFieldMapDiveWithKeysSuccessParallel-8 3000000 613 ns/op 480 B/op 21 allocs/op +BenchmarkFieldMapDiveWithKeysFailure-8 1000000 1413 ns/op 721 B/op 21 allocs/op +BenchmarkFieldMapDiveWithKeysFailureParallel-8 3000000 575 ns/op 721 B/op 21 allocs/op +BenchmarkFieldCustomTypeSuccess-8 10000000 216 ns/op 32 B/op 2 allocs/op +BenchmarkFieldCustomTypeSuccessParallel-8 20000000 82.2 ns/op 32 B/op 2 allocs/op +BenchmarkFieldCustomTypeFailure-8 5000000 274 ns/op 208 B/op 4 allocs/op +BenchmarkFieldCustomTypeFailureParallel-8 20000000 116 ns/op 208 B/op 4 allocs/op +BenchmarkFieldOrTagSuccess-8 2000000 740 ns/op 16 B/op 1 allocs/op +BenchmarkFieldOrTagSuccessParallel-8 3000000 474 ns/op 16 B/op 1 allocs/op +BenchmarkFieldOrTagFailure-8 3000000 471 ns/op 224 B/op 5 allocs/op +BenchmarkFieldOrTagFailureParallel-8 3000000 414 ns/op 224 B/op 5 allocs/op +BenchmarkStructLevelValidationSuccess-8 10000000 213 ns/op 32 B/op 2 allocs/op +BenchmarkStructLevelValidationSuccessParallel-8 20000000 91.8 ns/op 32 B/op 2 allocs/op +BenchmarkStructLevelValidationFailure-8 3000000 473 ns/op 304 B/op 8 allocs/op +BenchmarkStructLevelValidationFailureParallel-8 10000000 234 ns/op 304 B/op 8 allocs/op +BenchmarkStructSimpleCustomTypeSuccess-8 5000000 385 ns/op 32 B/op 2 allocs/op +BenchmarkStructSimpleCustomTypeSuccessParallel-8 10000000 161 ns/op 32 B/op 2 allocs/op +BenchmarkStructSimpleCustomTypeFailure-8 2000000 640 ns/op 424 B/op 9 allocs/op +BenchmarkStructSimpleCustomTypeFailureParallel-8 5000000 318 ns/op 440 B/op 10 allocs/op +BenchmarkStructFilteredSuccess-8 2000000 597 ns/op 288 B/op 9 allocs/op +BenchmarkStructFilteredSuccessParallel-8 10000000 266 ns/op 288 B/op 9 allocs/op +BenchmarkStructFilteredFailure-8 3000000 454 ns/op 256 B/op 7 allocs/op +BenchmarkStructFilteredFailureParallel-8 10000000 214 ns/op 256 B/op 7 allocs/op +BenchmarkStructPartialSuccess-8 3000000 502 ns/op 256 B/op 6 allocs/op +BenchmarkStructPartialSuccessParallel-8 10000000 225 ns/op 256 B/op 6 allocs/op +BenchmarkStructPartialFailure-8 2000000 702 ns/op 480 B/op 11 allocs/op +BenchmarkStructPartialFailureParallel-8 5000000 329 ns/op 480 B/op 11 allocs/op +BenchmarkStructExceptSuccess-8 2000000 793 ns/op 496 B/op 12 allocs/op +BenchmarkStructExceptSuccessParallel-8 10000000 193 ns/op 240 B/op 5 allocs/op +BenchmarkStructExceptFailure-8 2000000 639 ns/op 464 B/op 10 allocs/op +BenchmarkStructExceptFailureParallel-8 5000000 300 ns/op 464 B/op 10 allocs/op +BenchmarkStructSimpleCrossFieldSuccess-8 3000000 417 ns/op 72 B/op 3 allocs/op +BenchmarkStructSimpleCrossFieldSuccessParallel-8 10000000 163 ns/op 72 B/op 3 allocs/op +BenchmarkStructSimpleCrossFieldFailure-8 2000000 645 ns/op 304 B/op 8 allocs/op +BenchmarkStructSimpleCrossFieldFailureParallel-8 5000000 285 ns/op 304 B/op 8 allocs/op +BenchmarkStructSimpleCrossStructCrossFieldSuccess-8 3000000 588 ns/op 80 B/op 4 allocs/op +BenchmarkStructSimpleCrossStructCrossFieldSuccessParallel-8 10000000 221 ns/op 80 B/op 4 allocs/op +BenchmarkStructSimpleCrossStructCrossFieldFailure-8 2000000 868 ns/op 320 B/op 9 allocs/op +BenchmarkStructSimpleCrossStructCrossFieldFailureParallel-8 5000000 337 ns/op 320 B/op 9 allocs/op +BenchmarkStructSimpleSuccess-8 5000000 260 ns/op 0 B/op 0 allocs/op +BenchmarkStructSimpleSuccessParallel-8 20000000 90.6 ns/op 0 B/op 0 allocs/op +BenchmarkStructSimpleFailure-8 2000000 619 ns/op 424 B/op 9 allocs/op +BenchmarkStructSimpleFailureParallel-8 5000000 296 ns/op 424 B/op 9 allocs/op +BenchmarkStructComplexSuccess-8 1000000 1454 ns/op 128 B/op 8 allocs/op +BenchmarkStructComplexSuccessParallel-8 3000000 579 ns/op 128 B/op 8 allocs/op +BenchmarkStructComplexFailure-8 300000 4140 ns/op 3041 B/op 53 allocs/op +BenchmarkStructComplexFailureParallel-8 1000000 2127 ns/op 3041 B/op 53 allocs/op +BenchmarkOneof-8 10000000 140 ns/op 0 B/op 0 allocs/op +BenchmarkOneofParallel-8 20000000 70.1 ns/op 0 B/op 0 allocs/op +``` + +Complementary Software +---------------------- + +Here is a list of software that complements using this library either pre or post validation. + +* [form](https://github.com/go-playground/form) - Decodes url.Values into Go value(s) and Encodes Go value(s) into url.Values. Dual Array and Full map support. +* [mold](https://github.com/go-playground/mold) - A general library to help modify or set data within data structures and other objects + +How to Contribute +------ + +Make a pull request... + +License +------- +Distributed under MIT License, please see license file within the code for more details. + +Maintainers +----------- +This project has grown large enough that more than one person is required to properly support the community. +If you are interested in becoming a maintainer please reach out to me https://github.com/deankarn diff --git a/vendor/github.com/go-playground/validator/v10/baked_in.go b/vendor/github.com/go-playground/validator/v10/baked_in.go new file mode 100644 index 0000000000..c9b1db402e --- /dev/null +++ b/vendor/github.com/go-playground/validator/v10/baked_in.go @@ -0,0 +1,2526 @@ +package validator + +import ( + "bytes" + "context" + "crypto/sha256" + "encoding/hex" + "encoding/json" + "fmt" + "net" + "net/url" + "os" + "reflect" + "strconv" + "strings" + "sync" + "time" + "unicode/utf8" + + "golang.org/x/crypto/sha3" + "golang.org/x/text/language" + + urn "github.com/leodido/go-urn" +) + +// Func accepts a FieldLevel interface for all validation needs. The return +// value should be true when validation succeeds. +type Func func(fl FieldLevel) bool + +// FuncCtx accepts a context.Context and FieldLevel interface for all +// validation needs. The return value should be true when validation succeeds. +type FuncCtx func(ctx context.Context, fl FieldLevel) bool + +// wrapFunc wraps noramal Func makes it compatible with FuncCtx +func wrapFunc(fn Func) FuncCtx { + if fn == nil { + return nil // be sure not to wrap a bad function. + } + return func(ctx context.Context, fl FieldLevel) bool { + return fn(fl) + } +} + +var ( + restrictedTags = map[string]struct{}{ + diveTag: {}, + keysTag: {}, + endKeysTag: {}, + structOnlyTag: {}, + omitempty: {}, + skipValidationTag: {}, + utf8HexComma: {}, + utf8Pipe: {}, + noStructLevelTag: {}, + requiredTag: {}, + isdefault: {}, + } + + // bakedInAliases is a default mapping of a single validation tag that + // defines a common or complex set of validation(s) to simplify + // adding validation to structs. + bakedInAliases = map[string]string{ + "iscolor": "hexcolor|rgb|rgba|hsl|hsla", + "country_code": "iso3166_1_alpha2|iso3166_1_alpha3|iso3166_1_alpha_numeric", + } + + // bakedInValidators is the default map of ValidationFunc + // you can add, remove or even replace items to suite your needs, + // or even disregard and use your own map if so desired. + bakedInValidators = map[string]Func{ + "required": hasValue, + "required_if": requiredIf, + "required_unless": requiredUnless, + "required_with": requiredWith, + "required_with_all": requiredWithAll, + "required_without": requiredWithout, + "required_without_all": requiredWithoutAll, + "excluded_if": excludedIf, + "excluded_unless": excludedUnless, + "excluded_with": excludedWith, + "excluded_with_all": excludedWithAll, + "excluded_without": excludedWithout, + "excluded_without_all": excludedWithoutAll, + "isdefault": isDefault, + "len": hasLengthOf, + "min": hasMinOf, + "max": hasMaxOf, + "eq": isEq, + "ne": isNe, + "lt": isLt, + "lte": isLte, + "gt": isGt, + "gte": isGte, + "eqfield": isEqField, + "eqcsfield": isEqCrossStructField, + "necsfield": isNeCrossStructField, + "gtcsfield": isGtCrossStructField, + "gtecsfield": isGteCrossStructField, + "ltcsfield": isLtCrossStructField, + "ltecsfield": isLteCrossStructField, + "nefield": isNeField, + "gtefield": isGteField, + "gtfield": isGtField, + "ltefield": isLteField, + "ltfield": isLtField, + "fieldcontains": fieldContains, + "fieldexcludes": fieldExcludes, + "alpha": isAlpha, + "alphanum": isAlphanum, + "alphaunicode": isAlphaUnicode, + "alphanumunicode": isAlphanumUnicode, + "boolean": isBoolean, + "numeric": isNumeric, + "number": isNumber, + "hexadecimal": isHexadecimal, + "hexcolor": isHEXColor, + "rgb": isRGB, + "rgba": isRGBA, + "hsl": isHSL, + "hsla": isHSLA, + "e164": isE164, + "email": isEmail, + "url": isURL, + "uri": isURI, + "urn_rfc2141": isUrnRFC2141, // RFC 2141 + "file": isFile, + "base64": isBase64, + "base64url": isBase64URL, + "contains": contains, + "containsany": containsAny, + "containsrune": containsRune, + "excludes": excludes, + "excludesall": excludesAll, + "excludesrune": excludesRune, + "startswith": startsWith, + "endswith": endsWith, + "startsnotwith": startsNotWith, + "endsnotwith": endsNotWith, + "isbn": isISBN, + "isbn10": isISBN10, + "isbn13": isISBN13, + "eth_addr": isEthereumAddress, + "btc_addr": isBitcoinAddress, + "btc_addr_bech32": isBitcoinBech32Address, + "uuid": isUUID, + "uuid3": isUUID3, + "uuid4": isUUID4, + "uuid5": isUUID5, + "uuid_rfc4122": isUUIDRFC4122, + "uuid3_rfc4122": isUUID3RFC4122, + "uuid4_rfc4122": isUUID4RFC4122, + "uuid5_rfc4122": isUUID5RFC4122, + "ulid": isULID, + "md4": isMD4, + "md5": isMD5, + "sha256": isSHA256, + "sha384": isSHA384, + "sha512": isSHA512, + "ripemd128": isRIPEMD128, + "ripemd160": isRIPEMD160, + "tiger128": isTIGER128, + "tiger160": isTIGER160, + "tiger192": isTIGER192, + "ascii": isASCII, + "printascii": isPrintableASCII, + "multibyte": hasMultiByteCharacter, + "datauri": isDataURI, + "latitude": isLatitude, + "longitude": isLongitude, + "ssn": isSSN, + "ipv4": isIPv4, + "ipv6": isIPv6, + "ip": isIP, + "cidrv4": isCIDRv4, + "cidrv6": isCIDRv6, + "cidr": isCIDR, + "tcp4_addr": isTCP4AddrResolvable, + "tcp6_addr": isTCP6AddrResolvable, + "tcp_addr": isTCPAddrResolvable, + "udp4_addr": isUDP4AddrResolvable, + "udp6_addr": isUDP6AddrResolvable, + "udp_addr": isUDPAddrResolvable, + "ip4_addr": isIP4AddrResolvable, + "ip6_addr": isIP6AddrResolvable, + "ip_addr": isIPAddrResolvable, + "unix_addr": isUnixAddrResolvable, + "mac": isMAC, + "hostname": isHostnameRFC952, // RFC 952 + "hostname_rfc1123": isHostnameRFC1123, // RFC 1123 + "fqdn": isFQDN, + "unique": isUnique, + "oneof": isOneOf, + "html": isHTML, + "html_encoded": isHTMLEncoded, + "url_encoded": isURLEncoded, + "dir": isDir, + "json": isJSON, + "jwt": isJWT, + "hostname_port": isHostnamePort, + "lowercase": isLowercase, + "uppercase": isUppercase, + "datetime": isDatetime, + "timezone": isTimeZone, + "iso3166_1_alpha2": isIso3166Alpha2, + "iso3166_1_alpha3": isIso3166Alpha3, + "iso3166_1_alpha_numeric": isIso3166AlphaNumeric, + "iso3166_2": isIso31662, + "iso4217": isIso4217, + "iso4217_numeric": isIso4217Numeric, + "bcp47_language_tag": isBCP47LanguageTag, + "postcode_iso3166_alpha2": isPostcodeByIso3166Alpha2, + "postcode_iso3166_alpha2_field": isPostcodeByIso3166Alpha2Field, + "bic": isIsoBicFormat, + "semver": isSemverFormat, + "dns_rfc1035_label": isDnsRFC1035LabelFormat, + "credit_card": isCreditCard, + } +) + +var ( + oneofValsCache = map[string][]string{} + oneofValsCacheRWLock = sync.RWMutex{} +) + +func parseOneOfParam2(s string) []string { + oneofValsCacheRWLock.RLock() + vals, ok := oneofValsCache[s] + oneofValsCacheRWLock.RUnlock() + if !ok { + oneofValsCacheRWLock.Lock() + vals = splitParamsRegex.FindAllString(s, -1) + for i := 0; i < len(vals); i++ { + vals[i] = strings.Replace(vals[i], "'", "", -1) + } + oneofValsCache[s] = vals + oneofValsCacheRWLock.Unlock() + } + return vals +} + +func isURLEncoded(fl FieldLevel) bool { + return uRLEncodedRegex.MatchString(fl.Field().String()) +} + +func isHTMLEncoded(fl FieldLevel) bool { + return hTMLEncodedRegex.MatchString(fl.Field().String()) +} + +func isHTML(fl FieldLevel) bool { + return hTMLRegex.MatchString(fl.Field().String()) +} + +func isOneOf(fl FieldLevel) bool { + vals := parseOneOfParam2(fl.Param()) + + field := fl.Field() + + var v string + switch field.Kind() { + case reflect.String: + v = field.String() + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + v = strconv.FormatInt(field.Int(), 10) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + v = strconv.FormatUint(field.Uint(), 10) + default: + panic(fmt.Sprintf("Bad field type %T", field.Interface())) + } + for i := 0; i < len(vals); i++ { + if vals[i] == v { + return true + } + } + return false +} + +// isUnique is the validation function for validating if each array|slice|map value is unique +func isUnique(fl FieldLevel) bool { + field := fl.Field() + param := fl.Param() + v := reflect.ValueOf(struct{}{}) + + switch field.Kind() { + case reflect.Slice, reflect.Array: + elem := field.Type().Elem() + if elem.Kind() == reflect.Ptr { + elem = elem.Elem() + } + + if param == "" { + m := reflect.MakeMap(reflect.MapOf(elem, v.Type())) + + for i := 0; i < field.Len(); i++ { + m.SetMapIndex(reflect.Indirect(field.Index(i)), v) + } + return field.Len() == m.Len() + } + + sf, ok := elem.FieldByName(param) + if !ok { + panic(fmt.Sprintf("Bad field name %s", param)) + } + + sfTyp := sf.Type + if sfTyp.Kind() == reflect.Ptr { + sfTyp = sfTyp.Elem() + } + + m := reflect.MakeMap(reflect.MapOf(sfTyp, v.Type())) + for i := 0; i < field.Len(); i++ { + m.SetMapIndex(reflect.Indirect(reflect.Indirect(field.Index(i)).FieldByName(param)), v) + } + return field.Len() == m.Len() + case reflect.Map: + m := reflect.MakeMap(reflect.MapOf(field.Type().Elem(), v.Type())) + + for _, k := range field.MapKeys() { + m.SetMapIndex(field.MapIndex(k), v) + } + return field.Len() == m.Len() + default: + panic(fmt.Sprintf("Bad field type %T", field.Interface())) + } +} + +// isMAC is the validation function for validating if the field's value is a valid MAC address. +func isMAC(fl FieldLevel) bool { + _, err := net.ParseMAC(fl.Field().String()) + + return err == nil +} + +// isCIDRv4 is the validation function for validating if the field's value is a valid v4 CIDR address. +func isCIDRv4(fl FieldLevel) bool { + ip, _, err := net.ParseCIDR(fl.Field().String()) + + return err == nil && ip.To4() != nil +} + +// isCIDRv6 is the validation function for validating if the field's value is a valid v6 CIDR address. +func isCIDRv6(fl FieldLevel) bool { + ip, _, err := net.ParseCIDR(fl.Field().String()) + + return err == nil && ip.To4() == nil +} + +// isCIDR is the validation function for validating if the field's value is a valid v4 or v6 CIDR address. +func isCIDR(fl FieldLevel) bool { + _, _, err := net.ParseCIDR(fl.Field().String()) + + return err == nil +} + +// isIPv4 is the validation function for validating if a value is a valid v4 IP address. +func isIPv4(fl FieldLevel) bool { + ip := net.ParseIP(fl.Field().String()) + + return ip != nil && ip.To4() != nil +} + +// isIPv6 is the validation function for validating if the field's value is a valid v6 IP address. +func isIPv6(fl FieldLevel) bool { + ip := net.ParseIP(fl.Field().String()) + + return ip != nil && ip.To4() == nil +} + +// isIP is the validation function for validating if the field's value is a valid v4 or v6 IP address. +func isIP(fl FieldLevel) bool { + ip := net.ParseIP(fl.Field().String()) + + return ip != nil +} + +// isSSN is the validation function for validating if the field's value is a valid SSN. +func isSSN(fl FieldLevel) bool { + field := fl.Field() + + if field.Len() != 11 { + return false + } + + return sSNRegex.MatchString(field.String()) +} + +// isLongitude is the validation function for validating if the field's value is a valid longitude coordinate. +func isLongitude(fl FieldLevel) bool { + field := fl.Field() + + var v string + switch field.Kind() { + case reflect.String: + v = field.String() + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + v = strconv.FormatInt(field.Int(), 10) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + v = strconv.FormatUint(field.Uint(), 10) + case reflect.Float32: + v = strconv.FormatFloat(field.Float(), 'f', -1, 32) + case reflect.Float64: + v = strconv.FormatFloat(field.Float(), 'f', -1, 64) + default: + panic(fmt.Sprintf("Bad field type %T", field.Interface())) + } + + return longitudeRegex.MatchString(v) +} + +// isLatitude is the validation function for validating if the field's value is a valid latitude coordinate. +func isLatitude(fl FieldLevel) bool { + field := fl.Field() + + var v string + switch field.Kind() { + case reflect.String: + v = field.String() + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + v = strconv.FormatInt(field.Int(), 10) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + v = strconv.FormatUint(field.Uint(), 10) + case reflect.Float32: + v = strconv.FormatFloat(field.Float(), 'f', -1, 32) + case reflect.Float64: + v = strconv.FormatFloat(field.Float(), 'f', -1, 64) + default: + panic(fmt.Sprintf("Bad field type %T", field.Interface())) + } + + return latitudeRegex.MatchString(v) +} + +// isDataURI is the validation function for validating if the field's value is a valid data URI. +func isDataURI(fl FieldLevel) bool { + uri := strings.SplitN(fl.Field().String(), ",", 2) + + if len(uri) != 2 { + return false + } + + if !dataURIRegex.MatchString(uri[0]) { + return false + } + + return base64Regex.MatchString(uri[1]) +} + +// hasMultiByteCharacter is the validation function for validating if the field's value has a multi byte character. +func hasMultiByteCharacter(fl FieldLevel) bool { + field := fl.Field() + + if field.Len() == 0 { + return true + } + + return multibyteRegex.MatchString(field.String()) +} + +// isPrintableASCII is the validation function for validating if the field's value is a valid printable ASCII character. +func isPrintableASCII(fl FieldLevel) bool { + return printableASCIIRegex.MatchString(fl.Field().String()) +} + +// isASCII is the validation function for validating if the field's value is a valid ASCII character. +func isASCII(fl FieldLevel) bool { + return aSCIIRegex.MatchString(fl.Field().String()) +} + +// isUUID5 is the validation function for validating if the field's value is a valid v5 UUID. +func isUUID5(fl FieldLevel) bool { + return uUID5Regex.MatchString(fl.Field().String()) +} + +// isUUID4 is the validation function for validating if the field's value is a valid v4 UUID. +func isUUID4(fl FieldLevel) bool { + return uUID4Regex.MatchString(fl.Field().String()) +} + +// isUUID3 is the validation function for validating if the field's value is a valid v3 UUID. +func isUUID3(fl FieldLevel) bool { + return uUID3Regex.MatchString(fl.Field().String()) +} + +// isUUID is the validation function for validating if the field's value is a valid UUID of any version. +func isUUID(fl FieldLevel) bool { + return uUIDRegex.MatchString(fl.Field().String()) +} + +// isUUID5RFC4122 is the validation function for validating if the field's value is a valid RFC4122 v5 UUID. +func isUUID5RFC4122(fl FieldLevel) bool { + return uUID5RFC4122Regex.MatchString(fl.Field().String()) +} + +// isUUID4RFC4122 is the validation function for validating if the field's value is a valid RFC4122 v4 UUID. +func isUUID4RFC4122(fl FieldLevel) bool { + return uUID4RFC4122Regex.MatchString(fl.Field().String()) +} + +// isUUID3RFC4122 is the validation function for validating if the field's value is a valid RFC4122 v3 UUID. +func isUUID3RFC4122(fl FieldLevel) bool { + return uUID3RFC4122Regex.MatchString(fl.Field().String()) +} + +// isUUIDRFC4122 is the validation function for validating if the field's value is a valid RFC4122 UUID of any version. +func isUUIDRFC4122(fl FieldLevel) bool { + return uUIDRFC4122Regex.MatchString(fl.Field().String()) +} + +// isULID is the validation function for validating if the field's value is a valid ULID. +func isULID(fl FieldLevel) bool { + return uLIDRegex.MatchString(fl.Field().String()) +} + +// isMD4 is the validation function for validating if the field's value is a valid MD4. +func isMD4(fl FieldLevel) bool { + return md4Regex.MatchString(fl.Field().String()) +} + +// isMD5 is the validation function for validating if the field's value is a valid MD5. +func isMD5(fl FieldLevel) bool { + return md5Regex.MatchString(fl.Field().String()) +} + +// isSHA256 is the validation function for validating if the field's value is a valid SHA256. +func isSHA256(fl FieldLevel) bool { + return sha256Regex.MatchString(fl.Field().String()) +} + +// isSHA384 is the validation function for validating if the field's value is a valid SHA384. +func isSHA384(fl FieldLevel) bool { + return sha384Regex.MatchString(fl.Field().String()) +} + +// isSHA512 is the validation function for validating if the field's value is a valid SHA512. +func isSHA512(fl FieldLevel) bool { + return sha512Regex.MatchString(fl.Field().String()) +} + +// isRIPEMD128 is the validation function for validating if the field's value is a valid PIPEMD128. +func isRIPEMD128(fl FieldLevel) bool { + return ripemd128Regex.MatchString(fl.Field().String()) +} + +// isRIPEMD160 is the validation function for validating if the field's value is a valid PIPEMD160. +func isRIPEMD160(fl FieldLevel) bool { + return ripemd160Regex.MatchString(fl.Field().String()) +} + +// isTIGER128 is the validation function for validating if the field's value is a valid TIGER128. +func isTIGER128(fl FieldLevel) bool { + return tiger128Regex.MatchString(fl.Field().String()) +} + +// isTIGER160 is the validation function for validating if the field's value is a valid TIGER160. +func isTIGER160(fl FieldLevel) bool { + return tiger160Regex.MatchString(fl.Field().String()) +} + +// isTIGER192 is the validation function for validating if the field's value is a valid isTIGER192. +func isTIGER192(fl FieldLevel) bool { + return tiger192Regex.MatchString(fl.Field().String()) +} + +// isISBN is the validation function for validating if the field's value is a valid v10 or v13 ISBN. +func isISBN(fl FieldLevel) bool { + return isISBN10(fl) || isISBN13(fl) +} + +// isISBN13 is the validation function for validating if the field's value is a valid v13 ISBN. +func isISBN13(fl FieldLevel) bool { + s := strings.Replace(strings.Replace(fl.Field().String(), "-", "", 4), " ", "", 4) + + if !iSBN13Regex.MatchString(s) { + return false + } + + var checksum int32 + var i int32 + + factor := []int32{1, 3} + + for i = 0; i < 12; i++ { + checksum += factor[i%2] * int32(s[i]-'0') + } + + return (int32(s[12]-'0'))-((10-(checksum%10))%10) == 0 +} + +// isISBN10 is the validation function for validating if the field's value is a valid v10 ISBN. +func isISBN10(fl FieldLevel) bool { + s := strings.Replace(strings.Replace(fl.Field().String(), "-", "", 3), " ", "", 3) + + if !iSBN10Regex.MatchString(s) { + return false + } + + var checksum int32 + var i int32 + + for i = 0; i < 9; i++ { + checksum += (i + 1) * int32(s[i]-'0') + } + + if s[9] == 'X' { + checksum += 10 * 10 + } else { + checksum += 10 * int32(s[9]-'0') + } + + return checksum%11 == 0 +} + +// isEthereumAddress is the validation function for validating if the field's value is a valid Ethereum address. +func isEthereumAddress(fl FieldLevel) bool { + address := fl.Field().String() + + if !ethAddressRegex.MatchString(address) { + return false + } + + if ethAddressRegexUpper.MatchString(address) || ethAddressRegexLower.MatchString(address) { + return true + } + + // Checksum validation. Reference: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-55.md + address = address[2:] // Skip "0x" prefix. + h := sha3.NewLegacyKeccak256() + // hash.Hash's io.Writer implementation says it never returns an error. https://golang.org/pkg/hash/#Hash + _, _ = h.Write([]byte(strings.ToLower(address))) + hash := hex.EncodeToString(h.Sum(nil)) + + for i := 0; i < len(address); i++ { + if address[i] <= '9' { // Skip 0-9 digits: they don't have upper/lower-case. + continue + } + if hash[i] > '7' && address[i] >= 'a' || hash[i] <= '7' && address[i] <= 'F' { + return false + } + } + + return true +} + +// isBitcoinAddress is the validation function for validating if the field's value is a valid btc address +func isBitcoinAddress(fl FieldLevel) bool { + address := fl.Field().String() + + if !btcAddressRegex.MatchString(address) { + return false + } + + alphabet := []byte("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz") + + decode := [25]byte{} + + for _, n := range []byte(address) { + d := bytes.IndexByte(alphabet, n) + + for i := 24; i >= 0; i-- { + d += 58 * int(decode[i]) + decode[i] = byte(d % 256) + d /= 256 + } + } + + h := sha256.New() + _, _ = h.Write(decode[:21]) + d := h.Sum([]byte{}) + h = sha256.New() + _, _ = h.Write(d) + + validchecksum := [4]byte{} + computedchecksum := [4]byte{} + + copy(computedchecksum[:], h.Sum(d[:0])) + copy(validchecksum[:], decode[21:]) + + return validchecksum == computedchecksum +} + +// isBitcoinBech32Address is the validation function for validating if the field's value is a valid bech32 btc address +func isBitcoinBech32Address(fl FieldLevel) bool { + address := fl.Field().String() + + if !btcLowerAddressRegexBech32.MatchString(address) && !btcUpperAddressRegexBech32.MatchString(address) { + return false + } + + am := len(address) % 8 + + if am == 0 || am == 3 || am == 5 { + return false + } + + address = strings.ToLower(address) + + alphabet := "qpzry9x8gf2tvdw0s3jn54khce6mua7l" + + hr := []int{3, 3, 0, 2, 3} // the human readable part will always be bc + addr := address[3:] + dp := make([]int, 0, len(addr)) + + for _, c := range addr { + dp = append(dp, strings.IndexRune(alphabet, c)) + } + + ver := dp[0] + + if ver < 0 || ver > 16 { + return false + } + + if ver == 0 { + if len(address) != 42 && len(address) != 62 { + return false + } + } + + values := append(hr, dp...) + + GEN := []int{0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3} + + p := 1 + + for _, v := range values { + b := p >> 25 + p = (p&0x1ffffff)<<5 ^ v + + for i := 0; i < 5; i++ { + if (b>>uint(i))&1 == 1 { + p ^= GEN[i] + } + } + } + + if p != 1 { + return false + } + + b := uint(0) + acc := 0 + mv := (1 << 5) - 1 + var sw []int + + for _, v := range dp[1 : len(dp)-6] { + acc = (acc << 5) | v + b += 5 + for b >= 8 { + b -= 8 + sw = append(sw, (acc>>b)&mv) + } + } + + if len(sw) < 2 || len(sw) > 40 { + return false + } + + return true +} + +// excludesRune is the validation function for validating that the field's value does not contain the rune specified within the param. +func excludesRune(fl FieldLevel) bool { + return !containsRune(fl) +} + +// excludesAll is the validation function for validating that the field's value does not contain any of the characters specified within the param. +func excludesAll(fl FieldLevel) bool { + return !containsAny(fl) +} + +// excludes is the validation function for validating that the field's value does not contain the text specified within the param. +func excludes(fl FieldLevel) bool { + return !contains(fl) +} + +// containsRune is the validation function for validating that the field's value contains the rune specified within the param. +func containsRune(fl FieldLevel) bool { + r, _ := utf8.DecodeRuneInString(fl.Param()) + + return strings.ContainsRune(fl.Field().String(), r) +} + +// containsAny is the validation function for validating that the field's value contains any of the characters specified within the param. +func containsAny(fl FieldLevel) bool { + return strings.ContainsAny(fl.Field().String(), fl.Param()) +} + +// contains is the validation function for validating that the field's value contains the text specified within the param. +func contains(fl FieldLevel) bool { + return strings.Contains(fl.Field().String(), fl.Param()) +} + +// startsWith is the validation function for validating that the field's value starts with the text specified within the param. +func startsWith(fl FieldLevel) bool { + return strings.HasPrefix(fl.Field().String(), fl.Param()) +} + +// endsWith is the validation function for validating that the field's value ends with the text specified within the param. +func endsWith(fl FieldLevel) bool { + return strings.HasSuffix(fl.Field().String(), fl.Param()) +} + +// startsNotWith is the validation function for validating that the field's value does not start with the text specified within the param. +func startsNotWith(fl FieldLevel) bool { + return !startsWith(fl) +} + +// endsNotWith is the validation function for validating that the field's value does not end with the text specified within the param. +func endsNotWith(fl FieldLevel) bool { + return !endsWith(fl) +} + +// fieldContains is the validation function for validating if the current field's value contains the field specified by the param's value. +func fieldContains(fl FieldLevel) bool { + field := fl.Field() + + currentField, _, ok := fl.GetStructFieldOK() + + if !ok { + return false + } + + return strings.Contains(field.String(), currentField.String()) +} + +// fieldExcludes is the validation function for validating if the current field's value excludes the field specified by the param's value. +func fieldExcludes(fl FieldLevel) bool { + field := fl.Field() + + currentField, _, ok := fl.GetStructFieldOK() + if !ok { + return true + } + + return !strings.Contains(field.String(), currentField.String()) +} + +// isNeField is the validation function for validating if the current field's value is not equal to the field specified by the param's value. +func isNeField(fl FieldLevel) bool { + field := fl.Field() + kind := field.Kind() + + currentField, currentKind, ok := fl.GetStructFieldOK() + + if !ok || currentKind != kind { + return true + } + + switch kind { + + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return field.Int() != currentField.Int() + + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + return field.Uint() != currentField.Uint() + + case reflect.Float32, reflect.Float64: + return field.Float() != currentField.Float() + + case reflect.Slice, reflect.Map, reflect.Array: + return int64(field.Len()) != int64(currentField.Len()) + + case reflect.Bool: + return field.Bool() != currentField.Bool() + + case reflect.Struct: + + fieldType := field.Type() + + if fieldType.ConvertibleTo(timeType) && currentField.Type().ConvertibleTo(timeType) { + + t := currentField.Interface().(time.Time) + fieldTime := field.Interface().(time.Time) + + return !fieldTime.Equal(t) + } + + // Not Same underlying type i.e. struct and time + if fieldType != currentField.Type() { + return true + } + } + + // default reflect.String: + return field.String() != currentField.String() +} + +// isNe is the validation function for validating that the field's value does not equal the provided param value. +func isNe(fl FieldLevel) bool { + return !isEq(fl) +} + +// isLteCrossStructField is the validation function for validating if the current field's value is less than or equal to the field, within a separate struct, specified by the param's value. +func isLteCrossStructField(fl FieldLevel) bool { + field := fl.Field() + kind := field.Kind() + + topField, topKind, ok := fl.GetStructFieldOK() + if !ok || topKind != kind { + return false + } + + switch kind { + + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return field.Int() <= topField.Int() + + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + return field.Uint() <= topField.Uint() + + case reflect.Float32, reflect.Float64: + return field.Float() <= topField.Float() + + case reflect.Slice, reflect.Map, reflect.Array: + return int64(field.Len()) <= int64(topField.Len()) + + case reflect.Struct: + + fieldType := field.Type() + + if fieldType.ConvertibleTo(timeType) && topField.Type().ConvertibleTo(timeType) { + + fieldTime := field.Convert(timeType).Interface().(time.Time) + topTime := topField.Convert(timeType).Interface().(time.Time) + + return fieldTime.Before(topTime) || fieldTime.Equal(topTime) + } + + // Not Same underlying type i.e. struct and time + if fieldType != topField.Type() { + return false + } + } + + // default reflect.String: + return field.String() <= topField.String() +} + +// isLtCrossStructField is the validation function for validating if the current field's value is less than the field, within a separate struct, specified by the param's value. +// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. +func isLtCrossStructField(fl FieldLevel) bool { + field := fl.Field() + kind := field.Kind() + + topField, topKind, ok := fl.GetStructFieldOK() + if !ok || topKind != kind { + return false + } + + switch kind { + + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return field.Int() < topField.Int() + + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + return field.Uint() < topField.Uint() + + case reflect.Float32, reflect.Float64: + return field.Float() < topField.Float() + + case reflect.Slice, reflect.Map, reflect.Array: + return int64(field.Len()) < int64(topField.Len()) + + case reflect.Struct: + + fieldType := field.Type() + + if fieldType.ConvertibleTo(timeType) && topField.Type().ConvertibleTo(timeType) { + + fieldTime := field.Convert(timeType).Interface().(time.Time) + topTime := topField.Convert(timeType).Interface().(time.Time) + + return fieldTime.Before(topTime) + } + + // Not Same underlying type i.e. struct and time + if fieldType != topField.Type() { + return false + } + } + + // default reflect.String: + return field.String() < topField.String() +} + +// isGteCrossStructField is the validation function for validating if the current field's value is greater than or equal to the field, within a separate struct, specified by the param's value. +func isGteCrossStructField(fl FieldLevel) bool { + field := fl.Field() + kind := field.Kind() + + topField, topKind, ok := fl.GetStructFieldOK() + if !ok || topKind != kind { + return false + } + + switch kind { + + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return field.Int() >= topField.Int() + + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + return field.Uint() >= topField.Uint() + + case reflect.Float32, reflect.Float64: + return field.Float() >= topField.Float() + + case reflect.Slice, reflect.Map, reflect.Array: + return int64(field.Len()) >= int64(topField.Len()) + + case reflect.Struct: + + fieldType := field.Type() + + if fieldType.ConvertibleTo(timeType) && topField.Type().ConvertibleTo(timeType) { + + fieldTime := field.Convert(timeType).Interface().(time.Time) + topTime := topField.Convert(timeType).Interface().(time.Time) + + return fieldTime.After(topTime) || fieldTime.Equal(topTime) + } + + // Not Same underlying type i.e. struct and time + if fieldType != topField.Type() { + return false + } + } + + // default reflect.String: + return field.String() >= topField.String() +} + +// isGtCrossStructField is the validation function for validating if the current field's value is greater than the field, within a separate struct, specified by the param's value. +func isGtCrossStructField(fl FieldLevel) bool { + field := fl.Field() + kind := field.Kind() + + topField, topKind, ok := fl.GetStructFieldOK() + if !ok || topKind != kind { + return false + } + + switch kind { + + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return field.Int() > topField.Int() + + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + return field.Uint() > topField.Uint() + + case reflect.Float32, reflect.Float64: + return field.Float() > topField.Float() + + case reflect.Slice, reflect.Map, reflect.Array: + return int64(field.Len()) > int64(topField.Len()) + + case reflect.Struct: + + fieldType := field.Type() + + if fieldType.ConvertibleTo(timeType) && topField.Type().ConvertibleTo(timeType) { + + fieldTime := field.Convert(timeType).Interface().(time.Time) + topTime := topField.Convert(timeType).Interface().(time.Time) + + return fieldTime.After(topTime) + } + + // Not Same underlying type i.e. struct and time + if fieldType != topField.Type() { + return false + } + } + + // default reflect.String: + return field.String() > topField.String() +} + +// isNeCrossStructField is the validation function for validating that the current field's value is not equal to the field, within a separate struct, specified by the param's value. +func isNeCrossStructField(fl FieldLevel) bool { + field := fl.Field() + kind := field.Kind() + + topField, currentKind, ok := fl.GetStructFieldOK() + if !ok || currentKind != kind { + return true + } + + switch kind { + + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return topField.Int() != field.Int() + + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + return topField.Uint() != field.Uint() + + case reflect.Float32, reflect.Float64: + return topField.Float() != field.Float() + + case reflect.Slice, reflect.Map, reflect.Array: + return int64(topField.Len()) != int64(field.Len()) + + case reflect.Bool: + return topField.Bool() != field.Bool() + + case reflect.Struct: + + fieldType := field.Type() + + if fieldType.ConvertibleTo(timeType) && topField.Type().ConvertibleTo(timeType) { + + t := field.Convert(timeType).Interface().(time.Time) + fieldTime := topField.Convert(timeType).Interface().(time.Time) + + return !fieldTime.Equal(t) + } + + // Not Same underlying type i.e. struct and time + if fieldType != topField.Type() { + return true + } + } + + // default reflect.String: + return topField.String() != field.String() +} + +// isEqCrossStructField is the validation function for validating that the current field's value is equal to the field, within a separate struct, specified by the param's value. +func isEqCrossStructField(fl FieldLevel) bool { + field := fl.Field() + kind := field.Kind() + + topField, topKind, ok := fl.GetStructFieldOK() + if !ok || topKind != kind { + return false + } + + switch kind { + + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return topField.Int() == field.Int() + + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + return topField.Uint() == field.Uint() + + case reflect.Float32, reflect.Float64: + return topField.Float() == field.Float() + + case reflect.Slice, reflect.Map, reflect.Array: + return int64(topField.Len()) == int64(field.Len()) + + case reflect.Bool: + return topField.Bool() == field.Bool() + + case reflect.Struct: + + fieldType := field.Type() + + if fieldType.ConvertibleTo(timeType) && topField.Type().ConvertibleTo(timeType) { + + t := field.Convert(timeType).Interface().(time.Time) + fieldTime := topField.Convert(timeType).Interface().(time.Time) + + return fieldTime.Equal(t) + } + + // Not Same underlying type i.e. struct and time + if fieldType != topField.Type() { + return false + } + } + + // default reflect.String: + return topField.String() == field.String() +} + +// isEqField is the validation function for validating if the current field's value is equal to the field specified by the param's value. +func isEqField(fl FieldLevel) bool { + field := fl.Field() + kind := field.Kind() + + currentField, currentKind, ok := fl.GetStructFieldOK() + if !ok || currentKind != kind { + return false + } + + switch kind { + + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return field.Int() == currentField.Int() + + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + return field.Uint() == currentField.Uint() + + case reflect.Float32, reflect.Float64: + return field.Float() == currentField.Float() + + case reflect.Slice, reflect.Map, reflect.Array: + return int64(field.Len()) == int64(currentField.Len()) + + case reflect.Bool: + return field.Bool() == currentField.Bool() + + case reflect.Struct: + + fieldType := field.Type() + + if fieldType.ConvertibleTo(timeType) && currentField.Type().ConvertibleTo(timeType) { + + t := currentField.Convert(timeType).Interface().(time.Time) + fieldTime := field.Convert(timeType).Interface().(time.Time) + + return fieldTime.Equal(t) + } + + // Not Same underlying type i.e. struct and time + if fieldType != currentField.Type() { + return false + } + } + + // default reflect.String: + return field.String() == currentField.String() +} + +// isEq is the validation function for validating if the current field's value is equal to the param's value. +func isEq(fl FieldLevel) bool { + field := fl.Field() + param := fl.Param() + + switch field.Kind() { + + case reflect.String: + return field.String() == param + + case reflect.Slice, reflect.Map, reflect.Array: + p := asInt(param) + + return int64(field.Len()) == p + + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + p := asIntFromType(field.Type(), param) + + return field.Int() == p + + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + p := asUint(param) + + return field.Uint() == p + + case reflect.Float32, reflect.Float64: + p := asFloat(param) + + return field.Float() == p + + case reflect.Bool: + p := asBool(param) + + return field.Bool() == p + } + + panic(fmt.Sprintf("Bad field type %T", field.Interface())) +} + +// isPostcodeByIso3166Alpha2 validates by value which is country code in iso 3166 alpha 2 +// example: `postcode_iso3166_alpha2=US` +func isPostcodeByIso3166Alpha2(fl FieldLevel) bool { + field := fl.Field() + param := fl.Param() + + reg, found := postCodeRegexDict[param] + if !found { + return false + } + + return reg.MatchString(field.String()) +} + +// isPostcodeByIso3166Alpha2Field validates by field which represents for a value of country code in iso 3166 alpha 2 +// example: `postcode_iso3166_alpha2_field=CountryCode` +func isPostcodeByIso3166Alpha2Field(fl FieldLevel) bool { + field := fl.Field() + params := parseOneOfParam2(fl.Param()) + + if len(params) != 1 { + return false + } + + currentField, kind, _, found := fl.GetStructFieldOKAdvanced2(fl.Parent(), params[0]) + if !found { + return false + } + + if kind != reflect.String { + panic(fmt.Sprintf("Bad field type %T", currentField.Interface())) + } + + reg, found := postCodeRegexDict[currentField.String()] + if !found { + return false + } + + return reg.MatchString(field.String()) +} + +// isBase64 is the validation function for validating if the current field's value is a valid base 64. +func isBase64(fl FieldLevel) bool { + return base64Regex.MatchString(fl.Field().String()) +} + +// isBase64URL is the validation function for validating if the current field's value is a valid base64 URL safe string. +func isBase64URL(fl FieldLevel) bool { + return base64URLRegex.MatchString(fl.Field().String()) +} + +// isURI is the validation function for validating if the current field's value is a valid URI. +func isURI(fl FieldLevel) bool { + field := fl.Field() + + switch field.Kind() { + case reflect.String: + + s := field.String() + + // checks needed as of Go 1.6 because of change https://github.com/golang/go/commit/617c93ce740c3c3cc28cdd1a0d712be183d0b328#diff-6c2d018290e298803c0c9419d8739885L195 + // emulate browser and strip the '#' suffix prior to validation. see issue-#237 + if i := strings.Index(s, "#"); i > -1 { + s = s[:i] + } + + if len(s) == 0 { + return false + } + + _, err := url.ParseRequestURI(s) + + return err == nil + } + + panic(fmt.Sprintf("Bad field type %T", field.Interface())) +} + +// isURL is the validation function for validating if the current field's value is a valid URL. +func isURL(fl FieldLevel) bool { + field := fl.Field() + + switch field.Kind() { + case reflect.String: + + var i int + s := field.String() + + // checks needed as of Go 1.6 because of change https://github.com/golang/go/commit/617c93ce740c3c3cc28cdd1a0d712be183d0b328#diff-6c2d018290e298803c0c9419d8739885L195 + // emulate browser and strip the '#' suffix prior to validation. see issue-#237 + if i = strings.Index(s, "#"); i > -1 { + s = s[:i] + } + + if len(s) == 0 { + return false + } + + url, err := url.ParseRequestURI(s) + + if err != nil || url.Scheme == "" { + return false + } + + return true + } + + panic(fmt.Sprintf("Bad field type %T", field.Interface())) +} + +// isUrnRFC2141 is the validation function for validating if the current field's value is a valid URN as per RFC 2141. +func isUrnRFC2141(fl FieldLevel) bool { + field := fl.Field() + + switch field.Kind() { + case reflect.String: + + str := field.String() + + _, match := urn.Parse([]byte(str)) + + return match + } + + panic(fmt.Sprintf("Bad field type %T", field.Interface())) +} + +// isFile is the validation function for validating if the current field's value is a valid file path. +func isFile(fl FieldLevel) bool { + field := fl.Field() + + switch field.Kind() { + case reflect.String: + fileInfo, err := os.Stat(field.String()) + if err != nil { + return false + } + + return !fileInfo.IsDir() + } + + panic(fmt.Sprintf("Bad field type %T", field.Interface())) +} + +// isE164 is the validation function for validating if the current field's value is a valid e.164 formatted phone number. +func isE164(fl FieldLevel) bool { + return e164Regex.MatchString(fl.Field().String()) +} + +// isEmail is the validation function for validating if the current field's value is a valid email address. +func isEmail(fl FieldLevel) bool { + return emailRegex.MatchString(fl.Field().String()) +} + +// isHSLA is the validation function for validating if the current field's value is a valid HSLA color. +func isHSLA(fl FieldLevel) bool { + return hslaRegex.MatchString(fl.Field().String()) +} + +// isHSL is the validation function for validating if the current field's value is a valid HSL color. +func isHSL(fl FieldLevel) bool { + return hslRegex.MatchString(fl.Field().String()) +} + +// isRGBA is the validation function for validating if the current field's value is a valid RGBA color. +func isRGBA(fl FieldLevel) bool { + return rgbaRegex.MatchString(fl.Field().String()) +} + +// isRGB is the validation function for validating if the current field's value is a valid RGB color. +func isRGB(fl FieldLevel) bool { + return rgbRegex.MatchString(fl.Field().String()) +} + +// isHEXColor is the validation function for validating if the current field's value is a valid HEX color. +func isHEXColor(fl FieldLevel) bool { + return hexColorRegex.MatchString(fl.Field().String()) +} + +// isHexadecimal is the validation function for validating if the current field's value is a valid hexadecimal. +func isHexadecimal(fl FieldLevel) bool { + return hexadecimalRegex.MatchString(fl.Field().String()) +} + +// isNumber is the validation function for validating if the current field's value is a valid number. +func isNumber(fl FieldLevel) bool { + switch fl.Field().Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, reflect.Float32, reflect.Float64: + return true + default: + return numberRegex.MatchString(fl.Field().String()) + } +} + +// isNumeric is the validation function for validating if the current field's value is a valid numeric value. +func isNumeric(fl FieldLevel) bool { + switch fl.Field().Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, reflect.Float32, reflect.Float64: + return true + default: + return numericRegex.MatchString(fl.Field().String()) + } +} + +// isAlphanum is the validation function for validating if the current field's value is a valid alphanumeric value. +func isAlphanum(fl FieldLevel) bool { + return alphaNumericRegex.MatchString(fl.Field().String()) +} + +// isAlpha is the validation function for validating if the current field's value is a valid alpha value. +func isAlpha(fl FieldLevel) bool { + return alphaRegex.MatchString(fl.Field().String()) +} + +// isAlphanumUnicode is the validation function for validating if the current field's value is a valid alphanumeric unicode value. +func isAlphanumUnicode(fl FieldLevel) bool { + return alphaUnicodeNumericRegex.MatchString(fl.Field().String()) +} + +// isAlphaUnicode is the validation function for validating if the current field's value is a valid alpha unicode value. +func isAlphaUnicode(fl FieldLevel) bool { + return alphaUnicodeRegex.MatchString(fl.Field().String()) +} + +// isBoolean is the validation function for validating if the current field's value is a valid boolean value or can be safely converted to a boolean value. +func isBoolean(fl FieldLevel) bool { + switch fl.Field().Kind() { + case reflect.Bool: + return true + default: + _, err := strconv.ParseBool(fl.Field().String()) + return err == nil + } +} + +// isDefault is the opposite of required aka hasValue +func isDefault(fl FieldLevel) bool { + return !hasValue(fl) +} + +// hasValue is the validation function for validating if the current field's value is not the default static value. +func hasValue(fl FieldLevel) bool { + field := fl.Field() + switch field.Kind() { + case reflect.Slice, reflect.Map, reflect.Ptr, reflect.Interface, reflect.Chan, reflect.Func: + return !field.IsNil() + default: + if fl.(*validate).fldIsPointer && field.Interface() != nil { + return true + } + return field.IsValid() && field.Interface() != reflect.Zero(field.Type()).Interface() + } +} + +// requireCheckField is a func for check field kind +func requireCheckFieldKind(fl FieldLevel, param string, defaultNotFoundValue bool) bool { + field := fl.Field() + kind := field.Kind() + var nullable, found bool + if len(param) > 0 { + field, kind, nullable, found = fl.GetStructFieldOKAdvanced2(fl.Parent(), param) + if !found { + return defaultNotFoundValue + } + } + switch kind { + case reflect.Invalid: + return defaultNotFoundValue + case reflect.Slice, reflect.Map, reflect.Ptr, reflect.Interface, reflect.Chan, reflect.Func: + return field.IsNil() + default: + if nullable && field.Interface() != nil { + return false + } + return field.IsValid() && field.Interface() == reflect.Zero(field.Type()).Interface() + } +} + +// requireCheckFieldValue is a func for check field value +func requireCheckFieldValue(fl FieldLevel, param string, value string, defaultNotFoundValue bool) bool { + field, kind, _, found := fl.GetStructFieldOKAdvanced2(fl.Parent(), param) + if !found { + return defaultNotFoundValue + } + + switch kind { + + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return field.Int() == asInt(value) + + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + return field.Uint() == asUint(value) + + case reflect.Float32, reflect.Float64: + return field.Float() == asFloat(value) + + case reflect.Slice, reflect.Map, reflect.Array: + return int64(field.Len()) == asInt(value) + + case reflect.Bool: + return field.Bool() == asBool(value) + } + + // default reflect.String: + return field.String() == value +} + +// requiredIf is the validation function +// The field under validation must be present and not empty only if all the other specified fields are equal to the value following with the specified field. +func requiredIf(fl FieldLevel) bool { + params := parseOneOfParam2(fl.Param()) + if len(params)%2 != 0 { + panic(fmt.Sprintf("Bad param number for required_if %s", fl.FieldName())) + } + for i := 0; i < len(params); i += 2 { + if !requireCheckFieldValue(fl, params[i], params[i+1], false) { + return true + } + } + return hasValue(fl) +} + +// excludedIf is the validation function +// The field under validation must not be present or is empty only if all the other specified fields are equal to the value following with the specified field. +func excludedIf(fl FieldLevel) bool { + params := parseOneOfParam2(fl.Param()) + if len(params)%2 != 0 { + panic(fmt.Sprintf("Bad param number for excluded_if %s", fl.FieldName())) + } + + for i := 0; i < len(params); i += 2 { + if !requireCheckFieldValue(fl, params[i], params[i+1], false) { + return false + } + } + return true +} + +// requiredUnless is the validation function +// The field under validation must be present and not empty only unless all the other specified fields are equal to the value following with the specified field. +func requiredUnless(fl FieldLevel) bool { + params := parseOneOfParam2(fl.Param()) + if len(params)%2 != 0 { + panic(fmt.Sprintf("Bad param number for required_unless %s", fl.FieldName())) + } + + for i := 0; i < len(params); i += 2 { + if requireCheckFieldValue(fl, params[i], params[i+1], false) { + return true + } + } + return hasValue(fl) +} + +// excludedUnless is the validation function +// The field under validation must not be present or is empty unless all the other specified fields are equal to the value following with the specified field. +func excludedUnless(fl FieldLevel) bool { + params := parseOneOfParam2(fl.Param()) + if len(params)%2 != 0 { + panic(fmt.Sprintf("Bad param number for excluded_unless %s", fl.FieldName())) + } + for i := 0; i < len(params); i += 2 { + if !requireCheckFieldValue(fl, params[i], params[i+1], false) { + return true + } + } + return !hasValue(fl) +} + +// excludedWith is the validation function +// The field under validation must not be present or is empty if any of the other specified fields are present. +func excludedWith(fl FieldLevel) bool { + params := parseOneOfParam2(fl.Param()) + for _, param := range params { + if !requireCheckFieldKind(fl, param, true) { + return !hasValue(fl) + } + } + return true +} + +// requiredWith is the validation function +// The field under validation must be present and not empty only if any of the other specified fields are present. +func requiredWith(fl FieldLevel) bool { + params := parseOneOfParam2(fl.Param()) + for _, param := range params { + if !requireCheckFieldKind(fl, param, true) { + return hasValue(fl) + } + } + return true +} + +// excludedWithAll is the validation function +// The field under validation must not be present or is empty if all of the other specified fields are present. +func excludedWithAll(fl FieldLevel) bool { + params := parseOneOfParam2(fl.Param()) + for _, param := range params { + if requireCheckFieldKind(fl, param, true) { + return true + } + } + return !hasValue(fl) +} + +// requiredWithAll is the validation function +// The field under validation must be present and not empty only if all of the other specified fields are present. +func requiredWithAll(fl FieldLevel) bool { + params := parseOneOfParam2(fl.Param()) + for _, param := range params { + if requireCheckFieldKind(fl, param, true) { + return true + } + } + return hasValue(fl) +} + +// excludedWithout is the validation function +// The field under validation must not be present or is empty when any of the other specified fields are not present. +func excludedWithout(fl FieldLevel) bool { + if requireCheckFieldKind(fl, strings.TrimSpace(fl.Param()), true) { + return !hasValue(fl) + } + return true +} + +// requiredWithout is the validation function +// The field under validation must be present and not empty only when any of the other specified fields are not present. +func requiredWithout(fl FieldLevel) bool { + if requireCheckFieldKind(fl, strings.TrimSpace(fl.Param()), true) { + return hasValue(fl) + } + return true +} + +// excludedWithoutAll is the validation function +// The field under validation must not be present or is empty when all of the other specified fields are not present. +func excludedWithoutAll(fl FieldLevel) bool { + params := parseOneOfParam2(fl.Param()) + for _, param := range params { + if !requireCheckFieldKind(fl, param, true) { + return true + } + } + return !hasValue(fl) +} + +// requiredWithoutAll is the validation function +// The field under validation must be present and not empty only when all of the other specified fields are not present. +func requiredWithoutAll(fl FieldLevel) bool { + params := parseOneOfParam2(fl.Param()) + for _, param := range params { + if !requireCheckFieldKind(fl, param, true) { + return true + } + } + return hasValue(fl) +} + +// isGteField is the validation function for validating if the current field's value is greater than or equal to the field specified by the param's value. +func isGteField(fl FieldLevel) bool { + field := fl.Field() + kind := field.Kind() + + currentField, currentKind, ok := fl.GetStructFieldOK() + if !ok || currentKind != kind { + return false + } + + switch kind { + + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + + return field.Int() >= currentField.Int() + + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + + return field.Uint() >= currentField.Uint() + + case reflect.Float32, reflect.Float64: + + return field.Float() >= currentField.Float() + + case reflect.Struct: + + fieldType := field.Type() + + if fieldType.ConvertibleTo(timeType) && currentField.Type().ConvertibleTo(timeType) { + + t := currentField.Convert(timeType).Interface().(time.Time) + fieldTime := field.Convert(timeType).Interface().(time.Time) + + return fieldTime.After(t) || fieldTime.Equal(t) + } + + // Not Same underlying type i.e. struct and time + if fieldType != currentField.Type() { + return false + } + } + + // default reflect.String + return len(field.String()) >= len(currentField.String()) +} + +// isGtField is the validation function for validating if the current field's value is greater than the field specified by the param's value. +func isGtField(fl FieldLevel) bool { + field := fl.Field() + kind := field.Kind() + + currentField, currentKind, ok := fl.GetStructFieldOK() + if !ok || currentKind != kind { + return false + } + + switch kind { + + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + + return field.Int() > currentField.Int() + + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + + return field.Uint() > currentField.Uint() + + case reflect.Float32, reflect.Float64: + + return field.Float() > currentField.Float() + + case reflect.Struct: + + fieldType := field.Type() + + if fieldType.ConvertibleTo(timeType) && currentField.Type().ConvertibleTo(timeType) { + + t := currentField.Convert(timeType).Interface().(time.Time) + fieldTime := field.Convert(timeType).Interface().(time.Time) + + return fieldTime.After(t) + } + + // Not Same underlying type i.e. struct and time + if fieldType != currentField.Type() { + return false + } + } + + // default reflect.String + return len(field.String()) > len(currentField.String()) +} + +// isGte is the validation function for validating if the current field's value is greater than or equal to the param's value. +func isGte(fl FieldLevel) bool { + field := fl.Field() + param := fl.Param() + + switch field.Kind() { + + case reflect.String: + p := asInt(param) + + return int64(utf8.RuneCountInString(field.String())) >= p + + case reflect.Slice, reflect.Map, reflect.Array: + p := asInt(param) + + return int64(field.Len()) >= p + + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + p := asIntFromType(field.Type(), param) + + return field.Int() >= p + + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + p := asUint(param) + + return field.Uint() >= p + + case reflect.Float32, reflect.Float64: + p := asFloat(param) + + return field.Float() >= p + + case reflect.Struct: + + if field.Type().ConvertibleTo(timeType) { + + now := time.Now().UTC() + t := field.Convert(timeType).Interface().(time.Time) + + return t.After(now) || t.Equal(now) + } + } + + panic(fmt.Sprintf("Bad field type %T", field.Interface())) +} + +// isGt is the validation function for validating if the current field's value is greater than the param's value. +func isGt(fl FieldLevel) bool { + field := fl.Field() + param := fl.Param() + + switch field.Kind() { + + case reflect.String: + p := asInt(param) + + return int64(utf8.RuneCountInString(field.String())) > p + + case reflect.Slice, reflect.Map, reflect.Array: + p := asInt(param) + + return int64(field.Len()) > p + + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + p := asIntFromType(field.Type(), param) + + return field.Int() > p + + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + p := asUint(param) + + return field.Uint() > p + + case reflect.Float32, reflect.Float64: + p := asFloat(param) + + return field.Float() > p + case reflect.Struct: + + if field.Type().ConvertibleTo(timeType) { + + return field.Convert(timeType).Interface().(time.Time).After(time.Now().UTC()) + } + } + + panic(fmt.Sprintf("Bad field type %T", field.Interface())) +} + +// hasLengthOf is the validation function for validating if the current field's value is equal to the param's value. +func hasLengthOf(fl FieldLevel) bool { + field := fl.Field() + param := fl.Param() + + switch field.Kind() { + + case reflect.String: + p := asInt(param) + + return int64(utf8.RuneCountInString(field.String())) == p + + case reflect.Slice, reflect.Map, reflect.Array: + p := asInt(param) + + return int64(field.Len()) == p + + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + p := asIntFromType(field.Type(), param) + + return field.Int() == p + + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + p := asUint(param) + + return field.Uint() == p + + case reflect.Float32, reflect.Float64: + p := asFloat(param) + + return field.Float() == p + } + + panic(fmt.Sprintf("Bad field type %T", field.Interface())) +} + +// hasMinOf is the validation function for validating if the current field's value is greater than or equal to the param's value. +func hasMinOf(fl FieldLevel) bool { + return isGte(fl) +} + +// isLteField is the validation function for validating if the current field's value is less than or equal to the field specified by the param's value. +func isLteField(fl FieldLevel) bool { + field := fl.Field() + kind := field.Kind() + + currentField, currentKind, ok := fl.GetStructFieldOK() + if !ok || currentKind != kind { + return false + } + + switch kind { + + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + + return field.Int() <= currentField.Int() + + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + + return field.Uint() <= currentField.Uint() + + case reflect.Float32, reflect.Float64: + + return field.Float() <= currentField.Float() + + case reflect.Struct: + + fieldType := field.Type() + + if fieldType.ConvertibleTo(timeType) && currentField.Type().ConvertibleTo(timeType) { + + t := currentField.Convert(timeType).Interface().(time.Time) + fieldTime := field.Convert(timeType).Interface().(time.Time) + + return fieldTime.Before(t) || fieldTime.Equal(t) + } + + // Not Same underlying type i.e. struct and time + if fieldType != currentField.Type() { + return false + } + } + + // default reflect.String + return len(field.String()) <= len(currentField.String()) +} + +// isLtField is the validation function for validating if the current field's value is less than the field specified by the param's value. +func isLtField(fl FieldLevel) bool { + field := fl.Field() + kind := field.Kind() + + currentField, currentKind, ok := fl.GetStructFieldOK() + if !ok || currentKind != kind { + return false + } + + switch kind { + + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + + return field.Int() < currentField.Int() + + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + + return field.Uint() < currentField.Uint() + + case reflect.Float32, reflect.Float64: + + return field.Float() < currentField.Float() + + case reflect.Struct: + + fieldType := field.Type() + + if fieldType.ConvertibleTo(timeType) && currentField.Type().ConvertibleTo(timeType) { + + t := currentField.Convert(timeType).Interface().(time.Time) + fieldTime := field.Convert(timeType).Interface().(time.Time) + + return fieldTime.Before(t) + } + + // Not Same underlying type i.e. struct and time + if fieldType != currentField.Type() { + return false + } + } + + // default reflect.String + return len(field.String()) < len(currentField.String()) +} + +// isLte is the validation function for validating if the current field's value is less than or equal to the param's value. +func isLte(fl FieldLevel) bool { + field := fl.Field() + param := fl.Param() + + switch field.Kind() { + + case reflect.String: + p := asInt(param) + + return int64(utf8.RuneCountInString(field.String())) <= p + + case reflect.Slice, reflect.Map, reflect.Array: + p := asInt(param) + + return int64(field.Len()) <= p + + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + p := asIntFromType(field.Type(), param) + + return field.Int() <= p + + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + p := asUint(param) + + return field.Uint() <= p + + case reflect.Float32, reflect.Float64: + p := asFloat(param) + + return field.Float() <= p + + case reflect.Struct: + + if field.Type().ConvertibleTo(timeType) { + + now := time.Now().UTC() + t := field.Convert(timeType).Interface().(time.Time) + + return t.Before(now) || t.Equal(now) + } + } + + panic(fmt.Sprintf("Bad field type %T", field.Interface())) +} + +// isLt is the validation function for validating if the current field's value is less than the param's value. +func isLt(fl FieldLevel) bool { + field := fl.Field() + param := fl.Param() + + switch field.Kind() { + + case reflect.String: + p := asInt(param) + + return int64(utf8.RuneCountInString(field.String())) < p + + case reflect.Slice, reflect.Map, reflect.Array: + p := asInt(param) + + return int64(field.Len()) < p + + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + p := asIntFromType(field.Type(), param) + + return field.Int() < p + + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + p := asUint(param) + + return field.Uint() < p + + case reflect.Float32, reflect.Float64: + p := asFloat(param) + + return field.Float() < p + + case reflect.Struct: + + if field.Type().ConvertibleTo(timeType) { + + return field.Convert(timeType).Interface().(time.Time).Before(time.Now().UTC()) + } + } + + panic(fmt.Sprintf("Bad field type %T", field.Interface())) +} + +// hasMaxOf is the validation function for validating if the current field's value is less than or equal to the param's value. +func hasMaxOf(fl FieldLevel) bool { + return isLte(fl) +} + +// isTCP4AddrResolvable is the validation function for validating if the field's value is a resolvable tcp4 address. +func isTCP4AddrResolvable(fl FieldLevel) bool { + if !isIP4Addr(fl) { + return false + } + + _, err := net.ResolveTCPAddr("tcp4", fl.Field().String()) + return err == nil +} + +// isTCP6AddrResolvable is the validation function for validating if the field's value is a resolvable tcp6 address. +func isTCP6AddrResolvable(fl FieldLevel) bool { + if !isIP6Addr(fl) { + return false + } + + _, err := net.ResolveTCPAddr("tcp6", fl.Field().String()) + + return err == nil +} + +// isTCPAddrResolvable is the validation function for validating if the field's value is a resolvable tcp address. +func isTCPAddrResolvable(fl FieldLevel) bool { + if !isIP4Addr(fl) && !isIP6Addr(fl) { + return false + } + + _, err := net.ResolveTCPAddr("tcp", fl.Field().String()) + + return err == nil +} + +// isUDP4AddrResolvable is the validation function for validating if the field's value is a resolvable udp4 address. +func isUDP4AddrResolvable(fl FieldLevel) bool { + if !isIP4Addr(fl) { + return false + } + + _, err := net.ResolveUDPAddr("udp4", fl.Field().String()) + + return err == nil +} + +// isUDP6AddrResolvable is the validation function for validating if the field's value is a resolvable udp6 address. +func isUDP6AddrResolvable(fl FieldLevel) bool { + if !isIP6Addr(fl) { + return false + } + + _, err := net.ResolveUDPAddr("udp6", fl.Field().String()) + + return err == nil +} + +// isUDPAddrResolvable is the validation function for validating if the field's value is a resolvable udp address. +func isUDPAddrResolvable(fl FieldLevel) bool { + if !isIP4Addr(fl) && !isIP6Addr(fl) { + return false + } + + _, err := net.ResolveUDPAddr("udp", fl.Field().String()) + + return err == nil +} + +// isIP4AddrResolvable is the validation function for validating if the field's value is a resolvable ip4 address. +func isIP4AddrResolvable(fl FieldLevel) bool { + if !isIPv4(fl) { + return false + } + + _, err := net.ResolveIPAddr("ip4", fl.Field().String()) + + return err == nil +} + +// isIP6AddrResolvable is the validation function for validating if the field's value is a resolvable ip6 address. +func isIP6AddrResolvable(fl FieldLevel) bool { + if !isIPv6(fl) { + return false + } + + _, err := net.ResolveIPAddr("ip6", fl.Field().String()) + + return err == nil +} + +// isIPAddrResolvable is the validation function for validating if the field's value is a resolvable ip address. +func isIPAddrResolvable(fl FieldLevel) bool { + if !isIP(fl) { + return false + } + + _, err := net.ResolveIPAddr("ip", fl.Field().String()) + + return err == nil +} + +// isUnixAddrResolvable is the validation function for validating if the field's value is a resolvable unix address. +func isUnixAddrResolvable(fl FieldLevel) bool { + _, err := net.ResolveUnixAddr("unix", fl.Field().String()) + + return err == nil +} + +func isIP4Addr(fl FieldLevel) bool { + val := fl.Field().String() + + if idx := strings.LastIndex(val, ":"); idx != -1 { + val = val[0:idx] + } + + ip := net.ParseIP(val) + + return ip != nil && ip.To4() != nil +} + +func isIP6Addr(fl FieldLevel) bool { + val := fl.Field().String() + + if idx := strings.LastIndex(val, ":"); idx != -1 { + if idx != 0 && val[idx-1:idx] == "]" { + val = val[1 : idx-1] + } + } + + ip := net.ParseIP(val) + + return ip != nil && ip.To4() == nil +} + +func isHostnameRFC952(fl FieldLevel) bool { + return hostnameRegexRFC952.MatchString(fl.Field().String()) +} + +func isHostnameRFC1123(fl FieldLevel) bool { + return hostnameRegexRFC1123.MatchString(fl.Field().String()) +} + +func isFQDN(fl FieldLevel) bool { + val := fl.Field().String() + + if val == "" { + return false + } + + return fqdnRegexRFC1123.MatchString(val) +} + +// isDir is the validation function for validating if the current field's value is a valid directory. +func isDir(fl FieldLevel) bool { + field := fl.Field() + + if field.Kind() == reflect.String { + fileInfo, err := os.Stat(field.String()) + if err != nil { + return false + } + + return fileInfo.IsDir() + } + + panic(fmt.Sprintf("Bad field type %T", field.Interface())) +} + +// isJSON is the validation function for validating if the current field's value is a valid json string. +func isJSON(fl FieldLevel) bool { + field := fl.Field() + + if field.Kind() == reflect.String { + val := field.String() + return json.Valid([]byte(val)) + } + + panic(fmt.Sprintf("Bad field type %T", field.Interface())) +} + +// isJWT is the validation function for validating if the current field's value is a valid JWT string. +func isJWT(fl FieldLevel) bool { + return jWTRegex.MatchString(fl.Field().String()) +} + +// isHostnamePort validates a : combination for fields typically used for socket address. +func isHostnamePort(fl FieldLevel) bool { + val := fl.Field().String() + host, port, err := net.SplitHostPort(val) + if err != nil { + return false + } + // Port must be a iny <= 65535. + if portNum, err := strconv.ParseInt(port, 10, 32); err != nil || portNum > 65535 || portNum < 1 { + return false + } + + // If host is specified, it should match a DNS name + if host != "" { + return hostnameRegexRFC1123.MatchString(host) + } + return true +} + +// isLowercase is the validation function for validating if the current field's value is a lowercase string. +func isLowercase(fl FieldLevel) bool { + field := fl.Field() + + if field.Kind() == reflect.String { + if field.String() == "" { + return false + } + return field.String() == strings.ToLower(field.String()) + } + + panic(fmt.Sprintf("Bad field type %T", field.Interface())) +} + +// isUppercase is the validation function for validating if the current field's value is an uppercase string. +func isUppercase(fl FieldLevel) bool { + field := fl.Field() + + if field.Kind() == reflect.String { + if field.String() == "" { + return false + } + return field.String() == strings.ToUpper(field.String()) + } + + panic(fmt.Sprintf("Bad field type %T", field.Interface())) +} + +// isDatetime is the validation function for validating if the current field's value is a valid datetime string. +func isDatetime(fl FieldLevel) bool { + field := fl.Field() + param := fl.Param() + + if field.Kind() == reflect.String { + _, err := time.Parse(param, field.String()) + + return err == nil + } + + panic(fmt.Sprintf("Bad field type %T", field.Interface())) +} + +// isTimeZone is the validation function for validating if the current field's value is a valid time zone string. +func isTimeZone(fl FieldLevel) bool { + field := fl.Field() + + if field.Kind() == reflect.String { + // empty value is converted to UTC by time.LoadLocation but disallow it as it is not a valid time zone name + if field.String() == "" { + return false + } + + // Local value is converted to the current system time zone by time.LoadLocation but disallow it as it is not a valid time zone name + if strings.ToLower(field.String()) == "local" { + return false + } + + _, err := time.LoadLocation(field.String()) + return err == nil + } + + panic(fmt.Sprintf("Bad field type %T", field.Interface())) +} + +// isIso3166Alpha2 is the validation function for validating if the current field's value is a valid iso3166-1 alpha-2 country code. +func isIso3166Alpha2(fl FieldLevel) bool { + val := fl.Field().String() + return iso3166_1_alpha2[val] +} + +// isIso3166Alpha2 is the validation function for validating if the current field's value is a valid iso3166-1 alpha-3 country code. +func isIso3166Alpha3(fl FieldLevel) bool { + val := fl.Field().String() + return iso3166_1_alpha3[val] +} + +// isIso3166Alpha2 is the validation function for validating if the current field's value is a valid iso3166-1 alpha-numeric country code. +func isIso3166AlphaNumeric(fl FieldLevel) bool { + field := fl.Field() + + var code int + switch field.Kind() { + case reflect.String: + i, err := strconv.Atoi(field.String()) + if err != nil { + return false + } + code = i % 1000 + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + code = int(field.Int() % 1000) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + code = int(field.Uint() % 1000) + default: + panic(fmt.Sprintf("Bad field type %T", field.Interface())) + } + return iso3166_1_alpha_numeric[code] +} + +// isIso31662 is the validation function for validating if the current field's value is a valid iso3166-2 code. +func isIso31662(fl FieldLevel) bool { + val := fl.Field().String() + return iso3166_2[val] +} + +// isIso4217 is the validation function for validating if the current field's value is a valid iso4217 currency code. +func isIso4217(fl FieldLevel) bool { + val := fl.Field().String() + return iso4217[val] +} + +// isIso4217Numeric is the validation function for validating if the current field's value is a valid iso4217 numeric currency code. +func isIso4217Numeric(fl FieldLevel) bool { + field := fl.Field() + + var code int + switch field.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + code = int(field.Int()) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + code = int(field.Uint()) + default: + panic(fmt.Sprintf("Bad field type %T", field.Interface())) + } + return iso4217_numeric[code] +} + +// isBCP47LanguageTag is the validation function for validating if the current field's value is a valid BCP 47 language tag, as parsed by language.Parse +func isBCP47LanguageTag(fl FieldLevel) bool { + field := fl.Field() + + if field.Kind() == reflect.String { + _, err := language.Parse(field.String()) + return err == nil + } + + panic(fmt.Sprintf("Bad field type %T", field.Interface())) +} + +// isIsoBicFormat is the validation function for validating if the current field's value is a valid Business Identifier Code (SWIFT code), defined in ISO 9362 +func isIsoBicFormat(fl FieldLevel) bool { + bicString := fl.Field().String() + + return bicRegex.MatchString(bicString) +} + +// isSemverFormat is the validation function for validating if the current field's value is a valid semver version, defined in Semantic Versioning 2.0.0 +func isSemverFormat(fl FieldLevel) bool { + semverString := fl.Field().String() + + return semverRegex.MatchString(semverString) +} + +// isDnsRFC1035LabelFormat is the validation function +// for validating if the current field's value is +// a valid dns RFC 1035 label, defined in RFC 1035. +func isDnsRFC1035LabelFormat(fl FieldLevel) bool { + val := fl.Field().String() + return dnsRegexRFC1035Label.MatchString(val) +} + +// isCreditCard is the validation function for validating if the current field's value is a valid credit card number +func isCreditCard(fl FieldLevel) bool { + val := fl.Field().String() + var creditCard bytes.Buffer + segments := strings.Split(val, " ") + for _, segment := range segments { + if len(segment) < 3 { + return false + } + creditCard.WriteString(segment) + } + + ccDigits := strings.Split(creditCard.String(), "") + size := len(ccDigits) + if size < 12 || size > 19 { + return false + } + + sum := 0 + for i, digit := range ccDigits { + value, err := strconv.Atoi(digit) + if err != nil { + return false + } + if size%2 == 0 && i%2 == 0 || size%2 == 1 && i%2 == 1 { + v := value * 2 + if v >= 10 { + sum += 1 + (v % 10) + } else { + sum += v + } + } else { + sum += value + } + } + return (sum % 10) == 0 +} diff --git a/vendor/github.com/go-playground/validator/v10/cache.go b/vendor/github.com/go-playground/validator/v10/cache.go new file mode 100644 index 0000000000..7b84c91fe5 --- /dev/null +++ b/vendor/github.com/go-playground/validator/v10/cache.go @@ -0,0 +1,327 @@ +package validator + +import ( + "fmt" + "reflect" + "strings" + "sync" + "sync/atomic" +) + +type tagType uint8 + +const ( + typeDefault tagType = iota + typeOmitEmpty + typeIsDefault + typeNoStructLevel + typeStructOnly + typeDive + typeOr + typeKeys + typeEndKeys +) + +const ( + invalidValidation = "Invalid validation tag on field '%s'" + undefinedValidation = "Undefined validation function '%s' on field '%s'" + keysTagNotDefined = "'" + endKeysTag + "' tag encountered without a corresponding '" + keysTag + "' tag" +) + +type structCache struct { + lock sync.Mutex + m atomic.Value // map[reflect.Type]*cStruct +} + +func (sc *structCache) Get(key reflect.Type) (c *cStruct, found bool) { + c, found = sc.m.Load().(map[reflect.Type]*cStruct)[key] + return +} + +func (sc *structCache) Set(key reflect.Type, value *cStruct) { + m := sc.m.Load().(map[reflect.Type]*cStruct) + nm := make(map[reflect.Type]*cStruct, len(m)+1) + for k, v := range m { + nm[k] = v + } + nm[key] = value + sc.m.Store(nm) +} + +type tagCache struct { + lock sync.Mutex + m atomic.Value // map[string]*cTag +} + +func (tc *tagCache) Get(key string) (c *cTag, found bool) { + c, found = tc.m.Load().(map[string]*cTag)[key] + return +} + +func (tc *tagCache) Set(key string, value *cTag) { + m := tc.m.Load().(map[string]*cTag) + nm := make(map[string]*cTag, len(m)+1) + for k, v := range m { + nm[k] = v + } + nm[key] = value + tc.m.Store(nm) +} + +type cStruct struct { + name string + fields []*cField + fn StructLevelFuncCtx +} + +type cField struct { + idx int + name string + altName string + namesEqual bool + cTags *cTag +} + +type cTag struct { + tag string + aliasTag string + actualAliasTag string + param string + keys *cTag // only populated when using tag's 'keys' and 'endkeys' for map key validation + next *cTag + fn FuncCtx + typeof tagType + hasTag bool + hasAlias bool + hasParam bool // true if parameter used eg. eq= where the equal sign has been set + isBlockEnd bool // indicates the current tag represents the last validation in the block + runValidationWhenNil bool +} + +func (v *Validate) extractStructCache(current reflect.Value, sName string) *cStruct { + v.structCache.lock.Lock() + defer v.structCache.lock.Unlock() // leave as defer! because if inner panics, it will never get unlocked otherwise! + + typ := current.Type() + + // could have been multiple trying to access, but once first is done this ensures struct + // isn't parsed again. + cs, ok := v.structCache.Get(typ) + if ok { + return cs + } + + cs = &cStruct{name: sName, fields: make([]*cField, 0), fn: v.structLevelFuncs[typ]} + + numFields := current.NumField() + rules := v.rules[typ] + + var ctag *cTag + var fld reflect.StructField + var tag string + var customName string + + for i := 0; i < numFields; i++ { + + fld = typ.Field(i) + + if !fld.Anonymous && len(fld.PkgPath) > 0 { + continue + } + + if rtag, ok := rules[fld.Name]; ok { + tag = rtag + } else { + tag = fld.Tag.Get(v.tagName) + } + + if tag == skipValidationTag { + continue + } + + customName = fld.Name + + if v.hasTagNameFunc { + name := v.tagNameFunc(fld) + if len(name) > 0 { + customName = name + } + } + + // NOTE: cannot use shared tag cache, because tags may be equal, but things like alias may be different + // and so only struct level caching can be used instead of combined with Field tag caching + + if len(tag) > 0 { + ctag, _ = v.parseFieldTagsRecursive(tag, fld.Name, "", false) + } else { + // even if field doesn't have validations need cTag for traversing to potential inner/nested + // elements of the field. + ctag = new(cTag) + } + + cs.fields = append(cs.fields, &cField{ + idx: i, + name: fld.Name, + altName: customName, + cTags: ctag, + namesEqual: fld.Name == customName, + }) + } + v.structCache.Set(typ, cs) + return cs +} + +func (v *Validate) parseFieldTagsRecursive(tag string, fieldName string, alias string, hasAlias bool) (firstCtag *cTag, current *cTag) { + var t string + noAlias := len(alias) == 0 + tags := strings.Split(tag, tagSeparator) + + for i := 0; i < len(tags); i++ { + t = tags[i] + if noAlias { + alias = t + } + + // check map for alias and process new tags, otherwise process as usual + if tagsVal, found := v.aliases[t]; found { + if i == 0 { + firstCtag, current = v.parseFieldTagsRecursive(tagsVal, fieldName, t, true) + } else { + next, curr := v.parseFieldTagsRecursive(tagsVal, fieldName, t, true) + current.next, current = next, curr + + } + continue + } + + var prevTag tagType + + if i == 0 { + current = &cTag{aliasTag: alias, hasAlias: hasAlias, hasTag: true, typeof: typeDefault} + firstCtag = current + } else { + prevTag = current.typeof + current.next = &cTag{aliasTag: alias, hasAlias: hasAlias, hasTag: true} + current = current.next + } + + switch t { + case diveTag: + current.typeof = typeDive + continue + + case keysTag: + current.typeof = typeKeys + + if i == 0 || prevTag != typeDive { + panic(fmt.Sprintf("'%s' tag must be immediately preceded by the '%s' tag", keysTag, diveTag)) + } + + current.typeof = typeKeys + + // need to pass along only keys tag + // need to increment i to skip over the keys tags + b := make([]byte, 0, 64) + + i++ + + for ; i < len(tags); i++ { + + b = append(b, tags[i]...) + b = append(b, ',') + + if tags[i] == endKeysTag { + break + } + } + + current.keys, _ = v.parseFieldTagsRecursive(string(b[:len(b)-1]), fieldName, "", false) + continue + + case endKeysTag: + current.typeof = typeEndKeys + + // if there are more in tags then there was no keysTag defined + // and an error should be thrown + if i != len(tags)-1 { + panic(keysTagNotDefined) + } + return + + case omitempty: + current.typeof = typeOmitEmpty + continue + + case structOnlyTag: + current.typeof = typeStructOnly + continue + + case noStructLevelTag: + current.typeof = typeNoStructLevel + continue + + default: + if t == isdefault { + current.typeof = typeIsDefault + } + // if a pipe character is needed within the param you must use the utf8Pipe representation "0x7C" + orVals := strings.Split(t, orSeparator) + + for j := 0; j < len(orVals); j++ { + vals := strings.SplitN(orVals[j], tagKeySeparator, 2) + if noAlias { + alias = vals[0] + current.aliasTag = alias + } else { + current.actualAliasTag = t + } + + if j > 0 { + current.next = &cTag{aliasTag: alias, actualAliasTag: current.actualAliasTag, hasAlias: hasAlias, hasTag: true} + current = current.next + } + current.hasParam = len(vals) > 1 + + current.tag = vals[0] + if len(current.tag) == 0 { + panic(strings.TrimSpace(fmt.Sprintf(invalidValidation, fieldName))) + } + + if wrapper, ok := v.validations[current.tag]; ok { + current.fn = wrapper.fn + current.runValidationWhenNil = wrapper.runValidatinOnNil + } else { + panic(strings.TrimSpace(fmt.Sprintf(undefinedValidation, current.tag, fieldName))) + } + + if len(orVals) > 1 { + current.typeof = typeOr + } + + if len(vals) > 1 { + current.param = strings.Replace(strings.Replace(vals[1], utf8HexComma, ",", -1), utf8Pipe, "|", -1) + } + } + current.isBlockEnd = true + } + } + return +} + +func (v *Validate) fetchCacheTag(tag string) *cTag { + // find cached tag + ctag, found := v.tagCache.Get(tag) + if !found { + v.tagCache.lock.Lock() + defer v.tagCache.lock.Unlock() + + // could have been multiple trying to access, but once first is done this ensures tag + // isn't parsed again. + ctag, found = v.tagCache.Get(tag) + if !found { + ctag, _ = v.parseFieldTagsRecursive(tag, "", "", false) + v.tagCache.Set(tag, ctag) + } + } + return ctag +} diff --git a/vendor/github.com/go-playground/validator/v10/country_codes.go b/vendor/github.com/go-playground/validator/v10/country_codes.go new file mode 100644 index 0000000000..0d9eda0338 --- /dev/null +++ b/vendor/github.com/go-playground/validator/v10/country_codes.go @@ -0,0 +1,1132 @@ +package validator + +var iso3166_1_alpha2 = map[string]bool{ + // see: https://www.iso.org/iso-3166-country-codes.html + "AF": true, "AX": true, "AL": true, "DZ": true, "AS": true, + "AD": true, "AO": true, "AI": true, "AQ": true, "AG": true, + "AR": true, "AM": true, "AW": true, "AU": true, "AT": true, + "AZ": true, "BS": true, "BH": true, "BD": true, "BB": true, + "BY": true, "BE": true, "BZ": true, "BJ": true, "BM": true, + "BT": true, "BO": true, "BQ": true, "BA": true, "BW": true, + "BV": true, "BR": true, "IO": true, "BN": true, "BG": true, + "BF": true, "BI": true, "KH": true, "CM": true, "CA": true, + "CV": true, "KY": true, "CF": true, "TD": true, "CL": true, + "CN": true, "CX": true, "CC": true, "CO": true, "KM": true, + "CG": true, "CD": true, "CK": true, "CR": true, "CI": true, + "HR": true, "CU": true, "CW": true, "CY": true, "CZ": true, + "DK": true, "DJ": true, "DM": true, "DO": true, "EC": true, + "EG": true, "SV": true, "GQ": true, "ER": true, "EE": true, + "ET": true, "FK": true, "FO": true, "FJ": true, "FI": true, + "FR": true, "GF": true, "PF": true, "TF": true, "GA": true, + "GM": true, "GE": true, "DE": true, "GH": true, "GI": true, + "GR": true, "GL": true, "GD": true, "GP": true, "GU": true, + "GT": true, "GG": true, "GN": true, "GW": true, "GY": true, + "HT": true, "HM": true, "VA": true, "HN": true, "HK": true, + "HU": true, "IS": true, "IN": true, "ID": true, "IR": true, + "IQ": true, "IE": true, "IM": true, "IL": true, "IT": true, + "JM": true, "JP": true, "JE": true, "JO": true, "KZ": true, + "KE": true, "KI": true, "KP": true, "KR": true, "KW": true, + "KG": true, "LA": true, "LV": true, "LB": true, "LS": true, + "LR": true, "LY": true, "LI": true, "LT": true, "LU": true, + "MO": true, "MK": true, "MG": true, "MW": true, "MY": true, + "MV": true, "ML": true, "MT": true, "MH": true, "MQ": true, + "MR": true, "MU": true, "YT": true, "MX": true, "FM": true, + "MD": true, "MC": true, "MN": true, "ME": true, "MS": true, + "MA": true, "MZ": true, "MM": true, "NA": true, "NR": true, + "NP": true, "NL": true, "NC": true, "NZ": true, "NI": true, + "NE": true, "NG": true, "NU": true, "NF": true, "MP": true, + "NO": true, "OM": true, "PK": true, "PW": true, "PS": true, + "PA": true, "PG": true, "PY": true, "PE": true, "PH": true, + "PN": true, "PL": true, "PT": true, "PR": true, "QA": true, + "RE": true, "RO": true, "RU": true, "RW": true, "BL": true, + "SH": true, "KN": true, "LC": true, "MF": true, "PM": true, + "VC": true, "WS": true, "SM": true, "ST": true, "SA": true, + "SN": true, "RS": true, "SC": true, "SL": true, "SG": true, + "SX": true, "SK": true, "SI": true, "SB": true, "SO": true, + "ZA": true, "GS": true, "SS": true, "ES": true, "LK": true, + "SD": true, "SR": true, "SJ": true, "SZ": true, "SE": true, + "CH": true, "SY": true, "TW": true, "TJ": true, "TZ": true, + "TH": true, "TL": true, "TG": true, "TK": true, "TO": true, + "TT": true, "TN": true, "TR": true, "TM": true, "TC": true, + "TV": true, "UG": true, "UA": true, "AE": true, "GB": true, + "US": true, "UM": true, "UY": true, "UZ": true, "VU": true, + "VE": true, "VN": true, "VG": true, "VI": true, "WF": true, + "EH": true, "YE": true, "ZM": true, "ZW": true, +} + +var iso3166_1_alpha3 = map[string]bool{ + // see: https://www.iso.org/iso-3166-country-codes.html + "AFG": true, "ALB": true, "DZA": true, "ASM": true, "AND": true, + "AGO": true, "AIA": true, "ATA": true, "ATG": true, "ARG": true, + "ARM": true, "ABW": true, "AUS": true, "AUT": true, "AZE": true, + "BHS": true, "BHR": true, "BGD": true, "BRB": true, "BLR": true, + "BEL": true, "BLZ": true, "BEN": true, "BMU": true, "BTN": true, + "BOL": true, "BES": true, "BIH": true, "BWA": true, "BVT": true, + "BRA": true, "IOT": true, "BRN": true, "BGR": true, "BFA": true, + "BDI": true, "CPV": true, "KHM": true, "CMR": true, "CAN": true, + "CYM": true, "CAF": true, "TCD": true, "CHL": true, "CHN": true, + "CXR": true, "CCK": true, "COL": true, "COM": true, "COD": true, + "COG": true, "COK": true, "CRI": true, "HRV": true, "CUB": true, + "CUW": true, "CYP": true, "CZE": true, "CIV": true, "DNK": true, + "DJI": true, "DMA": true, "DOM": true, "ECU": true, "EGY": true, + "SLV": true, "GNQ": true, "ERI": true, "EST": true, "SWZ": true, + "ETH": true, "FLK": true, "FRO": true, "FJI": true, "FIN": true, + "FRA": true, "GUF": true, "PYF": true, "ATF": true, "GAB": true, + "GMB": true, "GEO": true, "DEU": true, "GHA": true, "GIB": true, + "GRC": true, "GRL": true, "GRD": true, "GLP": true, "GUM": true, + "GTM": true, "GGY": true, "GIN": true, "GNB": true, "GUY": true, + "HTI": true, "HMD": true, "VAT": true, "HND": true, "HKG": true, + "HUN": true, "ISL": true, "IND": true, "IDN": true, "IRN": true, + "IRQ": true, "IRL": true, "IMN": true, "ISR": true, "ITA": true, + "JAM": true, "JPN": true, "JEY": true, "JOR": true, "KAZ": true, + "KEN": true, "KIR": true, "PRK": true, "KOR": true, "KWT": true, + "KGZ": true, "LAO": true, "LVA": true, "LBN": true, "LSO": true, + "LBR": true, "LBY": true, "LIE": true, "LTU": true, "LUX": true, + "MAC": true, "MDG": true, "MWI": true, "MYS": true, "MDV": true, + "MLI": true, "MLT": true, "MHL": true, "MTQ": true, "MRT": true, + "MUS": true, "MYT": true, "MEX": true, "FSM": true, "MDA": true, + "MCO": true, "MNG": true, "MNE": true, "MSR": true, "MAR": true, + "MOZ": true, "MMR": true, "NAM": true, "NRU": true, "NPL": true, + "NLD": true, "NCL": true, "NZL": true, "NIC": true, "NER": true, + "NGA": true, "NIU": true, "NFK": true, "MKD": true, "MNP": true, + "NOR": true, "OMN": true, "PAK": true, "PLW": true, "PSE": true, + "PAN": true, "PNG": true, "PRY": true, "PER": true, "PHL": true, + "PCN": true, "POL": true, "PRT": true, "PRI": true, "QAT": true, + "ROU": true, "RUS": true, "RWA": true, "REU": true, "BLM": true, + "SHN": true, "KNA": true, "LCA": true, "MAF": true, "SPM": true, + "VCT": true, "WSM": true, "SMR": true, "STP": true, "SAU": true, + "SEN": true, "SRB": true, "SYC": true, "SLE": true, "SGP": true, + "SXM": true, "SVK": true, "SVN": true, "SLB": true, "SOM": true, + "ZAF": true, "SGS": true, "SSD": true, "ESP": true, "LKA": true, + "SDN": true, "SUR": true, "SJM": true, "SWE": true, "CHE": true, + "SYR": true, "TWN": true, "TJK": true, "TZA": true, "THA": true, + "TLS": true, "TGO": true, "TKL": true, "TON": true, "TTO": true, + "TUN": true, "TUR": true, "TKM": true, "TCA": true, "TUV": true, + "UGA": true, "UKR": true, "ARE": true, "GBR": true, "UMI": true, + "USA": true, "URY": true, "UZB": true, "VUT": true, "VEN": true, + "VNM": true, "VGB": true, "VIR": true, "WLF": true, "ESH": true, + "YEM": true, "ZMB": true, "ZWE": true, "ALA": true, +} +var iso3166_1_alpha_numeric = map[int]bool{ + // see: https://www.iso.org/iso-3166-country-codes.html + 4: true, 8: true, 12: true, 16: true, 20: true, + 24: true, 660: true, 10: true, 28: true, 32: true, + 51: true, 533: true, 36: true, 40: true, 31: true, + 44: true, 48: true, 50: true, 52: true, 112: true, + 56: true, 84: true, 204: true, 60: true, 64: true, + 68: true, 535: true, 70: true, 72: true, 74: true, + 76: true, 86: true, 96: true, 100: true, 854: true, + 108: true, 132: true, 116: true, 120: true, 124: true, + 136: true, 140: true, 148: true, 152: true, 156: true, + 162: true, 166: true, 170: true, 174: true, 180: true, + 178: true, 184: true, 188: true, 191: true, 192: true, + 531: true, 196: true, 203: true, 384: true, 208: true, + 262: true, 212: true, 214: true, 218: true, 818: true, + 222: true, 226: true, 232: true, 233: true, 748: true, + 231: true, 238: true, 234: true, 242: true, 246: true, + 250: true, 254: true, 258: true, 260: true, 266: true, + 270: true, 268: true, 276: true, 288: true, 292: true, + 300: true, 304: true, 308: true, 312: true, 316: true, + 320: true, 831: true, 324: true, 624: true, 328: true, + 332: true, 334: true, 336: true, 340: true, 344: true, + 348: true, 352: true, 356: true, 360: true, 364: true, + 368: true, 372: true, 833: true, 376: true, 380: true, + 388: true, 392: true, 832: true, 400: true, 398: true, + 404: true, 296: true, 408: true, 410: true, 414: true, + 417: true, 418: true, 428: true, 422: true, 426: true, + 430: true, 434: true, 438: true, 440: true, 442: true, + 446: true, 450: true, 454: true, 458: true, 462: true, + 466: true, 470: true, 584: true, 474: true, 478: true, + 480: true, 175: true, 484: true, 583: true, 498: true, + 492: true, 496: true, 499: true, 500: true, 504: true, + 508: true, 104: true, 516: true, 520: true, 524: true, + 528: true, 540: true, 554: true, 558: true, 562: true, + 566: true, 570: true, 574: true, 807: true, 580: true, + 578: true, 512: true, 586: true, 585: true, 275: true, + 591: true, 598: true, 600: true, 604: true, 608: true, + 612: true, 616: true, 620: true, 630: true, 634: true, + 642: true, 643: true, 646: true, 638: true, 652: true, + 654: true, 659: true, 662: true, 663: true, 666: true, + 670: true, 882: true, 674: true, 678: true, 682: true, + 686: true, 688: true, 690: true, 694: true, 702: true, + 534: true, 703: true, 705: true, 90: true, 706: true, + 710: true, 239: true, 728: true, 724: true, 144: true, + 729: true, 740: true, 744: true, 752: true, 756: true, + 760: true, 158: true, 762: true, 834: true, 764: true, + 626: true, 768: true, 772: true, 776: true, 780: true, + 788: true, 792: true, 795: true, 796: true, 798: true, + 800: true, 804: true, 784: true, 826: true, 581: true, + 840: true, 858: true, 860: true, 548: true, 862: true, + 704: true, 92: true, 850: true, 876: true, 732: true, + 887: true, 894: true, 716: true, 248: true, +} + +var iso3166_2 = map[string]bool{ + "AD-02" : true, "AD-03" : true, "AD-04" : true, "AD-05" : true, "AD-06" : true, + "AD-07" : true, "AD-08" : true, "AE-AJ" : true, "AE-AZ" : true, "AE-DU" : true, + "AE-FU" : true, "AE-RK" : true, "AE-SH" : true, "AE-UQ" : true, "AF-BAL" : true, + "AF-BAM" : true, "AF-BDG" : true, "AF-BDS" : true, "AF-BGL" : true, "AF-DAY" : true, + "AF-FRA" : true, "AF-FYB" : true, "AF-GHA" : true, "AF-GHO" : true, "AF-HEL" : true, + "AF-HER" : true, "AF-JOW" : true, "AF-KAB" : true, "AF-KAN" : true, "AF-KAP" : true, + "AF-KDZ" : true, "AF-KHO" : true, "AF-KNR" : true, "AF-LAG" : true, "AF-LOG" : true, + "AF-NAN" : true, "AF-NIM" : true, "AF-NUR" : true, "AF-PAN" : true, "AF-PAR" : true, + "AF-PIA" : true, "AF-PKA" : true, "AF-SAM" : true, "AF-SAR" : true, "AF-TAK" : true, + "AF-URU" : true, "AF-WAR" : true, "AF-ZAB" : true, "AG-03" : true, "AG-04" : true, + "AG-05" : true, "AG-06" : true, "AG-07" : true, "AG-08" : true, "AG-10" : true, + "AG-11" : true, "AL-01" : true, "AL-02" : true, "AL-03" : true, "AL-04" : true, + "AL-05" : true, "AL-06" : true, "AL-07" : true, "AL-08" : true, "AL-09" : true, + "AL-10" : true, "AL-11" : true, "AL-12" : true, "AL-BR" : true, "AL-BU" : true, + "AL-DI" : true, "AL-DL" : true, "AL-DR" : true, "AL-DV" : true, "AL-EL" : true, + "AL-ER" : true, "AL-FR" : true, "AL-GJ" : true, "AL-GR" : true, "AL-HA" : true, + "AL-KA" : true, "AL-KB" : true, "AL-KC" : true, "AL-KO" : true, "AL-KR" : true, + "AL-KU" : true, "AL-LB" : true, "AL-LE" : true, "AL-LU" : true, "AL-MK" : true, + "AL-MM" : true, "AL-MR" : true, "AL-MT" : true, "AL-PG" : true, "AL-PQ" : true, + "AL-PR" : true, "AL-PU" : true, "AL-SH" : true, "AL-SK" : true, "AL-SR" : true, + "AL-TE" : true, "AL-TP" : true, "AL-TR" : true, "AL-VL" : true, "AM-AG" : true, + "AM-AR" : true, "AM-AV" : true, "AM-ER" : true, "AM-GR" : true, "AM-KT" : true, + "AM-LO" : true, "AM-SH" : true, "AM-SU" : true, "AM-TV" : true, "AM-VD" : true, + "AO-BGO" : true, "AO-BGU" : true, "AO-BIE" : true, "AO-CAB" : true, "AO-CCU" : true, + "AO-CNN" : true, "AO-CNO" : true, "AO-CUS" : true, "AO-HUA" : true, "AO-HUI" : true, + "AO-LNO" : true, "AO-LSU" : true, "AO-LUA" : true, "AO-MAL" : true, "AO-MOX" : true, + "AO-NAM" : true, "AO-UIG" : true, "AO-ZAI" : true, "AR-A" : true, "AR-B" : true, + "AR-C" : true, "AR-D" : true, "AR-E" : true, "AR-G" : true, "AR-H" : true, + "AR-J" : true, "AR-K" : true, "AR-L" : true, "AR-M" : true, "AR-N" : true, + "AR-P" : true, "AR-Q" : true, "AR-R" : true, "AR-S" : true, "AR-T" : true, + "AR-U" : true, "AR-V" : true, "AR-W" : true, "AR-X" : true, "AR-Y" : true, + "AR-Z" : true, "AT-1" : true, "AT-2" : true, "AT-3" : true, "AT-4" : true, + "AT-5" : true, "AT-6" : true, "AT-7" : true, "AT-8" : true, "AT-9" : true, + "AU-ACT" : true, "AU-NSW" : true, "AU-NT" : true, "AU-QLD" : true, "AU-SA" : true, + "AU-TAS" : true, "AU-VIC" : true, "AU-WA" : true, "AZ-ABS" : true, "AZ-AGA" : true, + "AZ-AGC" : true, "AZ-AGM" : true, "AZ-AGS" : true, "AZ-AGU" : true, "AZ-AST" : true, + "AZ-BA" : true, "AZ-BAB" : true, "AZ-BAL" : true, "AZ-BAR" : true, "AZ-BEY" : true, + "AZ-BIL" : true, "AZ-CAB" : true, "AZ-CAL" : true, "AZ-CUL" : true, "AZ-DAS" : true, + "AZ-FUZ" : true, "AZ-GA" : true, "AZ-GAD" : true, "AZ-GOR" : true, "AZ-GOY" : true, + "AZ-GYG" : true, "AZ-HAC" : true, "AZ-IMI" : true, "AZ-ISM" : true, "AZ-KAL" : true, + "AZ-KAN" : true, "AZ-KUR" : true, "AZ-LA" : true, "AZ-LAC" : true, "AZ-LAN" : true, + "AZ-LER" : true, "AZ-MAS" : true, "AZ-MI" : true, "AZ-NA" : true, "AZ-NEF" : true, + "AZ-NV" : true, "AZ-NX" : true, "AZ-OGU" : true, "AZ-ORD" : true, "AZ-QAB" : true, + "AZ-QAX" : true, "AZ-QAZ" : true, "AZ-QBA" : true, "AZ-QBI" : true, "AZ-QOB" : true, + "AZ-QUS" : true, "AZ-SA" : true, "AZ-SAB" : true, "AZ-SAD" : true, "AZ-SAH" : true, + "AZ-SAK" : true, "AZ-SAL" : true, "AZ-SAR" : true, "AZ-SAT" : true, "AZ-SBN" : true, + "AZ-SIY" : true, "AZ-SKR" : true, "AZ-SM" : true, "AZ-SMI" : true, "AZ-SMX" : true, + "AZ-SR" : true, "AZ-SUS" : true, "AZ-TAR" : true, "AZ-TOV" : true, "AZ-UCA" : true, + "AZ-XA" : true, "AZ-XAC" : true, "AZ-XCI" : true, "AZ-XIZ" : true, "AZ-XVD" : true, + "AZ-YAR" : true, "AZ-YE" : true, "AZ-YEV" : true, "AZ-ZAN" : true, "AZ-ZAQ" : true, + "AZ-ZAR" : true, "BA-01" : true, "BA-02" : true, "BA-03" : true, "BA-04" : true, + "BA-05" : true, "BA-06" : true, "BA-07" : true, "BA-08" : true, "BA-09" : true, + "BA-10" : true, "BA-BIH" : true, "BA-BRC" : true, "BA-SRP" : true, "BB-01" : true, + "BB-02" : true, "BB-03" : true, "BB-04" : true, "BB-05" : true, "BB-06" : true, + "BB-07" : true, "BB-08" : true, "BB-09" : true, "BB-10" : true, "BB-11" : true, + "BD-01" : true, "BD-02" : true, "BD-03" : true, "BD-04" : true, "BD-05" : true, + "BD-06" : true, "BD-07" : true, "BD-08" : true, "BD-09" : true, "BD-10" : true, + "BD-11" : true, "BD-12" : true, "BD-13" : true, "BD-14" : true, "BD-15" : true, + "BD-16" : true, "BD-17" : true, "BD-18" : true, "BD-19" : true, "BD-20" : true, + "BD-21" : true, "BD-22" : true, "BD-23" : true, "BD-24" : true, "BD-25" : true, + "BD-26" : true, "BD-27" : true, "BD-28" : true, "BD-29" : true, "BD-30" : true, + "BD-31" : true, "BD-32" : true, "BD-33" : true, "BD-34" : true, "BD-35" : true, + "BD-36" : true, "BD-37" : true, "BD-38" : true, "BD-39" : true, "BD-40" : true, + "BD-41" : true, "BD-42" : true, "BD-43" : true, "BD-44" : true, "BD-45" : true, + "BD-46" : true, "BD-47" : true, "BD-48" : true, "BD-49" : true, "BD-50" : true, + "BD-51" : true, "BD-52" : true, "BD-53" : true, "BD-54" : true, "BD-55" : true, + "BD-56" : true, "BD-57" : true, "BD-58" : true, "BD-59" : true, "BD-60" : true, + "BD-61" : true, "BD-62" : true, "BD-63" : true, "BD-64" : true, "BD-A" : true, + "BD-B" : true, "BD-C" : true, "BD-D" : true, "BD-E" : true, "BD-F" : true, + "BD-G" : true, "BE-BRU" : true, "BE-VAN" : true, "BE-VBR" : true, "BE-VLG" : true, + "BE-VLI" : true, "BE-VOV" : true, "BE-VWV" : true, "BE-WAL" : true, "BE-WBR" : true, + "BE-WHT" : true, "BE-WLG" : true, "BE-WLX" : true, "BE-WNA" : true, "BF-01" : true, + "BF-02" : true, "BF-03" : true, "BF-04" : true, "BF-05" : true, "BF-06" : true, + "BF-07" : true, "BF-08" : true, "BF-09" : true, "BF-10" : true, "BF-11" : true, + "BF-12" : true, "BF-13" : true, "BF-BAL" : true, "BF-BAM" : true, "BF-BAN" : true, + "BF-BAZ" : true, "BF-BGR" : true, "BF-BLG" : true, "BF-BLK" : true, "BF-COM" : true, + "BF-GAN" : true, "BF-GNA" : true, "BF-GOU" : true, "BF-HOU" : true, "BF-IOB" : true, + "BF-KAD" : true, "BF-KEN" : true, "BF-KMD" : true, "BF-KMP" : true, "BF-KOP" : true, + "BF-KOS" : true, "BF-KOT" : true, "BF-KOW" : true, "BF-LER" : true, "BF-LOR" : true, + "BF-MOU" : true, "BF-NAM" : true, "BF-NAO" : true, "BF-NAY" : true, "BF-NOU" : true, + "BF-OUB" : true, "BF-OUD" : true, "BF-PAS" : true, "BF-PON" : true, "BF-SEN" : true, + "BF-SIS" : true, "BF-SMT" : true, "BF-SNG" : true, "BF-SOM" : true, "BF-SOR" : true, + "BF-TAP" : true, "BF-TUI" : true, "BF-YAG" : true, "BF-YAT" : true, "BF-ZIR" : true, + "BF-ZON" : true, "BF-ZOU" : true, "BG-01" : true, "BG-02" : true, "BG-03" : true, + "BG-04" : true, "BG-05" : true, "BG-06" : true, "BG-07" : true, "BG-08" : true, + "BG-09" : true, "BG-10" : true, "BG-11" : true, "BG-12" : true, "BG-13" : true, + "BG-14" : true, "BG-15" : true, "BG-16" : true, "BG-17" : true, "BG-18" : true, + "BG-19" : true, "BG-20" : true, "BG-21" : true, "BG-22" : true, "BG-23" : true, + "BG-24" : true, "BG-25" : true, "BG-26" : true, "BG-27" : true, "BG-28" : true, + "BH-13" : true, "BH-14" : true, "BH-15" : true, "BH-16" : true, "BH-17" : true, + "BI-BB" : true, "BI-BL" : true, "BI-BM" : true, "BI-BR" : true, "BI-CA" : true, + "BI-CI" : true, "BI-GI" : true, "BI-KI" : true, "BI-KR" : true, "BI-KY" : true, + "BI-MA" : true, "BI-MU" : true, "BI-MW" : true, "BI-NG" : true, "BI-RT" : true, + "BI-RY" : true, "BJ-AK" : true, "BJ-AL" : true, "BJ-AQ" : true, "BJ-BO" : true, + "BJ-CO" : true, "BJ-DO" : true, "BJ-KO" : true, "BJ-LI" : true, "BJ-MO" : true, + "BJ-OU" : true, "BJ-PL" : true, "BJ-ZO" : true, "BN-BE" : true, "BN-BM" : true, + "BN-TE" : true, "BN-TU" : true, "BO-B" : true, "BO-C" : true, "BO-H" : true, + "BO-L" : true, "BO-N" : true, "BO-O" : true, "BO-P" : true, "BO-S" : true, + "BO-T" : true, "BQ-BO" : true, "BQ-SA" : true, "BQ-SE" : true, "BR-AC" : true, + "BR-AL" : true, "BR-AM" : true, "BR-AP" : true, "BR-BA" : true, "BR-CE" : true, + "BR-DF" : true, "BR-ES" : true, "BR-FN" : true, "BR-GO" : true, "BR-MA" : true, + "BR-MG" : true, "BR-MS" : true, "BR-MT" : true, "BR-PA" : true, "BR-PB" : true, + "BR-PE" : true, "BR-PI" : true, "BR-PR" : true, "BR-RJ" : true, "BR-RN" : true, + "BR-RO" : true, "BR-RR" : true, "BR-RS" : true, "BR-SC" : true, "BR-SE" : true, + "BR-SP" : true, "BR-TO" : true, "BS-AK" : true, "BS-BI" : true, "BS-BP" : true, + "BS-BY" : true, "BS-CE" : true, "BS-CI" : true, "BS-CK" : true, "BS-CO" : true, + "BS-CS" : true, "BS-EG" : true, "BS-EX" : true, "BS-FP" : true, "BS-GC" : true, + "BS-HI" : true, "BS-HT" : true, "BS-IN" : true, "BS-LI" : true, "BS-MC" : true, + "BS-MG" : true, "BS-MI" : true, "BS-NE" : true, "BS-NO" : true, "BS-NS" : true, + "BS-RC" : true, "BS-RI" : true, "BS-SA" : true, "BS-SE" : true, "BS-SO" : true, + "BS-SS" : true, "BS-SW" : true, "BS-WG" : true, "BT-11" : true, "BT-12" : true, + "BT-13" : true, "BT-14" : true, "BT-15" : true, "BT-21" : true, "BT-22" : true, + "BT-23" : true, "BT-24" : true, "BT-31" : true, "BT-32" : true, "BT-33" : true, + "BT-34" : true, "BT-41" : true, "BT-42" : true, "BT-43" : true, "BT-44" : true, + "BT-45" : true, "BT-GA" : true, "BT-TY" : true, "BW-CE" : true, "BW-GH" : true, + "BW-KG" : true, "BW-KL" : true, "BW-KW" : true, "BW-NE" : true, "BW-NW" : true, + "BW-SE" : true, "BW-SO" : true, "BY-BR" : true, "BY-HM" : true, "BY-HO" : true, + "BY-HR" : true, "BY-MA" : true, "BY-MI" : true, "BY-VI" : true, "BZ-BZ" : true, + "BZ-CY" : true, "BZ-CZL" : true, "BZ-OW" : true, "BZ-SC" : true, "BZ-TOL" : true, + "CA-AB" : true, "CA-BC" : true, "CA-MB" : true, "CA-NB" : true, "CA-NL" : true, + "CA-NS" : true, "CA-NT" : true, "CA-NU" : true, "CA-ON" : true, "CA-PE" : true, + "CA-QC" : true, "CA-SK" : true, "CA-YT" : true, "CD-BC" : true, "CD-BN" : true, + "CD-EQ" : true, "CD-KA" : true, "CD-KE" : true, "CD-KN" : true, "CD-KW" : true, + "CD-MA" : true, "CD-NK" : true, "CD-OR" : true, "CD-SK" : true, "CF-AC" : true, + "CF-BB" : true, "CF-BGF" : true, "CF-BK" : true, "CF-HK" : true, "CF-HM" : true, + "CF-HS" : true, "CF-KB" : true, "CF-KG" : true, "CF-LB" : true, "CF-MB" : true, + "CF-MP" : true, "CF-NM" : true, "CF-OP" : true, "CF-SE" : true, "CF-UK" : true, + "CF-VK" : true, "CG-11" : true, "CG-12" : true, "CG-13" : true, "CG-14" : true, + "CG-15" : true, "CG-2" : true, "CG-5" : true, "CG-7" : true, "CG-8" : true, + "CG-9" : true, "CG-BZV" : true, "CH-AG" : true, "CH-AI" : true, "CH-AR" : true, + "CH-BE" : true, "CH-BL" : true, "CH-BS" : true, "CH-FR" : true, "CH-GE" : true, + "CH-GL" : true, "CH-GR" : true, "CH-JU" : true, "CH-LU" : true, "CH-NE" : true, + "CH-NW" : true, "CH-OW" : true, "CH-SG" : true, "CH-SH" : true, "CH-SO" : true, + "CH-SZ" : true, "CH-TG" : true, "CH-TI" : true, "CH-UR" : true, "CH-VD" : true, + "CH-VS" : true, "CH-ZG" : true, "CH-ZH" : true, "CI-01" : true, "CI-02" : true, + "CI-03" : true, "CI-04" : true, "CI-05" : true, "CI-06" : true, "CI-07" : true, + "CI-08" : true, "CI-09" : true, "CI-10" : true, "CI-11" : true, "CI-12" : true, + "CI-13" : true, "CI-14" : true, "CI-15" : true, "CI-16" : true, "CI-17" : true, + "CI-18" : true, "CI-19" : true, "CL-AI" : true, "CL-AN" : true, "CL-AP" : true, + "CL-AR" : true, "CL-AT" : true, "CL-BI" : true, "CL-CO" : true, "CL-LI" : true, + "CL-LL" : true, "CL-LR" : true, "CL-MA" : true, "CL-ML" : true, "CL-RM" : true, + "CL-TA" : true, "CL-VS" : true, "CM-AD" : true, "CM-CE" : true, "CM-EN" : true, + "CM-ES" : true, "CM-LT" : true, "CM-NO" : true, "CM-NW" : true, "CM-OU" : true, + "CM-SU" : true, "CM-SW" : true, "CN-11" : true, "CN-12" : true, "CN-13" : true, + "CN-14" : true, "CN-15" : true, "CN-21" : true, "CN-22" : true, "CN-23" : true, + "CN-31" : true, "CN-32" : true, "CN-33" : true, "CN-34" : true, "CN-35" : true, + "CN-36" : true, "CN-37" : true, "CN-41" : true, "CN-42" : true, "CN-43" : true, + "CN-44" : true, "CN-45" : true, "CN-46" : true, "CN-50" : true, "CN-51" : true, + "CN-52" : true, "CN-53" : true, "CN-54" : true, "CN-61" : true, "CN-62" : true, + "CN-63" : true, "CN-64" : true, "CN-65" : true, "CN-71" : true, "CN-91" : true, + "CN-92" : true, "CO-AMA" : true, "CO-ANT" : true, "CO-ARA" : true, "CO-ATL" : true, + "CO-BOL" : true, "CO-BOY" : true, "CO-CAL" : true, "CO-CAQ" : true, "CO-CAS" : true, + "CO-CAU" : true, "CO-CES" : true, "CO-CHO" : true, "CO-COR" : true, "CO-CUN" : true, + "CO-DC" : true, "CO-GUA" : true, "CO-GUV" : true, "CO-HUI" : true, "CO-LAG" : true, + "CO-MAG" : true, "CO-MET" : true, "CO-NAR" : true, "CO-NSA" : true, "CO-PUT" : true, + "CO-QUI" : true, "CO-RIS" : true, "CO-SAN" : true, "CO-SAP" : true, "CO-SUC" : true, + "CO-TOL" : true, "CO-VAC" : true, "CO-VAU" : true, "CO-VID" : true, "CR-A" : true, + "CR-C" : true, "CR-G" : true, "CR-H" : true, "CR-L" : true, "CR-P" : true, + "CR-SJ" : true, "CU-01" : true, "CU-02" : true, "CU-03" : true, "CU-04" : true, + "CU-05" : true, "CU-06" : true, "CU-07" : true, "CU-08" : true, "CU-09" : true, + "CU-10" : true, "CU-11" : true, "CU-12" : true, "CU-13" : true, "CU-14" : true, + "CU-99" : true, "CV-B" : true, "CV-BR" : true, "CV-BV" : true, "CV-CA" : true, + "CV-CF" : true, "CV-CR" : true, "CV-MA" : true, "CV-MO" : true, "CV-PA" : true, + "CV-PN" : true, "CV-PR" : true, "CV-RB" : true, "CV-RG" : true, "CV-RS" : true, + "CV-S" : true, "CV-SD" : true, "CV-SF" : true, "CV-SL" : true, "CV-SM" : true, + "CV-SO" : true, "CV-SS" : true, "CV-SV" : true, "CV-TA" : true, "CV-TS" : true, + "CY-01" : true, "CY-02" : true, "CY-03" : true, "CY-04" : true, "CY-05" : true, + "CY-06" : true, "CZ-10" : true, "CZ-101" : true, "CZ-102" : true, "CZ-103" : true, + "CZ-104" : true, "CZ-105" : true, "CZ-106" : true, "CZ-107" : true, "CZ-108" : true, + "CZ-109" : true, "CZ-110" : true, "CZ-111" : true, "CZ-112" : true, "CZ-113" : true, + "CZ-114" : true, "CZ-115" : true, "CZ-116" : true, "CZ-117" : true, "CZ-118" : true, + "CZ-119" : true, "CZ-120" : true, "CZ-121" : true, "CZ-122" : true, "CZ-20" : true, + "CZ-201" : true, "CZ-202" : true, "CZ-203" : true, "CZ-204" : true, "CZ-205" : true, + "CZ-206" : true, "CZ-207" : true, "CZ-208" : true, "CZ-209" : true, "CZ-20A" : true, + "CZ-20B" : true, "CZ-20C" : true, "CZ-31" : true, "CZ-311" : true, "CZ-312" : true, + "CZ-313" : true, "CZ-314" : true, "CZ-315" : true, "CZ-316" : true, "CZ-317" : true, + "CZ-32" : true, "CZ-321" : true, "CZ-322" : true, "CZ-323" : true, "CZ-324" : true, + "CZ-325" : true, "CZ-326" : true, "CZ-327" : true, "CZ-41" : true, "CZ-411" : true, + "CZ-412" : true, "CZ-413" : true, "CZ-42" : true, "CZ-421" : true, "CZ-422" : true, + "CZ-423" : true, "CZ-424" : true, "CZ-425" : true, "CZ-426" : true, "CZ-427" : true, + "CZ-51" : true, "CZ-511" : true, "CZ-512" : true, "CZ-513" : true, "CZ-514" : true, + "CZ-52" : true, "CZ-521" : true, "CZ-522" : true, "CZ-523" : true, "CZ-524" : true, + "CZ-525" : true, "CZ-53" : true, "CZ-531" : true, "CZ-532" : true, "CZ-533" : true, + "CZ-534" : true, "CZ-63" : true, "CZ-631" : true, "CZ-632" : true, "CZ-633" : true, + "CZ-634" : true, "CZ-635" : true, "CZ-64" : true, "CZ-641" : true, "CZ-642" : true, + "CZ-643" : true, "CZ-644" : true, "CZ-645" : true, "CZ-646" : true, "CZ-647" : true, + "CZ-71" : true, "CZ-711" : true, "CZ-712" : true, "CZ-713" : true, "CZ-714" : true, + "CZ-715" : true, "CZ-72" : true, "CZ-721" : true, "CZ-722" : true, "CZ-723" : true, + "CZ-724" : true, "CZ-80" : true, "CZ-801" : true, "CZ-802" : true, "CZ-803" : true, + "CZ-804" : true, "CZ-805" : true, "CZ-806" : true, "DE-BB" : true, "DE-BE" : true, + "DE-BW" : true, "DE-BY" : true, "DE-HB" : true, "DE-HE" : true, "DE-HH" : true, + "DE-MV" : true, "DE-NI" : true, "DE-NW" : true, "DE-RP" : true, "DE-SH" : true, + "DE-SL" : true, "DE-SN" : true, "DE-ST" : true, "DE-TH" : true, "DJ-AR" : true, + "DJ-AS" : true, "DJ-DI" : true, "DJ-DJ" : true, "DJ-OB" : true, "DJ-TA" : true, + "DK-81" : true, "DK-82" : true, "DK-83" : true, "DK-84" : true, "DK-85" : true, + "DM-01" : true, "DM-02" : true, "DM-03" : true, "DM-04" : true, "DM-05" : true, + "DM-06" : true, "DM-07" : true, "DM-08" : true, "DM-09" : true, "DM-10" : true, + "DO-01" : true, "DO-02" : true, "DO-03" : true, "DO-04" : true, "DO-05" : true, + "DO-06" : true, "DO-07" : true, "DO-08" : true, "DO-09" : true, "DO-10" : true, + "DO-11" : true, "DO-12" : true, "DO-13" : true, "DO-14" : true, "DO-15" : true, + "DO-16" : true, "DO-17" : true, "DO-18" : true, "DO-19" : true, "DO-20" : true, + "DO-21" : true, "DO-22" : true, "DO-23" : true, "DO-24" : true, "DO-25" : true, + "DO-26" : true, "DO-27" : true, "DO-28" : true, "DO-29" : true, "DO-30" : true, + "DZ-01" : true, "DZ-02" : true, "DZ-03" : true, "DZ-04" : true, "DZ-05" : true, + "DZ-06" : true, "DZ-07" : true, "DZ-08" : true, "DZ-09" : true, "DZ-10" : true, + "DZ-11" : true, "DZ-12" : true, "DZ-13" : true, "DZ-14" : true, "DZ-15" : true, + "DZ-16" : true, "DZ-17" : true, "DZ-18" : true, "DZ-19" : true, "DZ-20" : true, + "DZ-21" : true, "DZ-22" : true, "DZ-23" : true, "DZ-24" : true, "DZ-25" : true, + "DZ-26" : true, "DZ-27" : true, "DZ-28" : true, "DZ-29" : true, "DZ-30" : true, + "DZ-31" : true, "DZ-32" : true, "DZ-33" : true, "DZ-34" : true, "DZ-35" : true, + "DZ-36" : true, "DZ-37" : true, "DZ-38" : true, "DZ-39" : true, "DZ-40" : true, + "DZ-41" : true, "DZ-42" : true, "DZ-43" : true, "DZ-44" : true, "DZ-45" : true, + "DZ-46" : true, "DZ-47" : true, "DZ-48" : true, "EC-A" : true, "EC-B" : true, + "EC-C" : true, "EC-D" : true, "EC-E" : true, "EC-F" : true, "EC-G" : true, + "EC-H" : true, "EC-I" : true, "EC-L" : true, "EC-M" : true, "EC-N" : true, + "EC-O" : true, "EC-P" : true, "EC-R" : true, "EC-S" : true, "EC-SD" : true, + "EC-SE" : true, "EC-T" : true, "EC-U" : true, "EC-W" : true, "EC-X" : true, + "EC-Y" : true, "EC-Z" : true, "EE-37" : true, "EE-39" : true, "EE-44" : true, + "EE-49" : true, "EE-51" : true, "EE-57" : true, "EE-59" : true, "EE-65" : true, + "EE-67" : true, "EE-70" : true, "EE-74" : true, "EE-78" : true, "EE-82" : true, + "EE-84" : true, "EE-86" : true, "EG-ALX" : true, "EG-ASN" : true, "EG-AST" : true, + "EG-BA" : true, "EG-BH" : true, "EG-BNS" : true, "EG-C" : true, "EG-DK" : true, + "EG-DT" : true, "EG-FYM" : true, "EG-GH" : true, "EG-GZ" : true, "EG-HU" : true, + "EG-IS" : true, "EG-JS" : true, "EG-KB" : true, "EG-KFS" : true, "EG-KN" : true, + "EG-MN" : true, "EG-MNF" : true, "EG-MT" : true, "EG-PTS" : true, "EG-SHG" : true, + "EG-SHR" : true, "EG-SIN" : true, "EG-SU" : true, "EG-SUZ" : true, "EG-WAD" : true, + "ER-AN" : true, "ER-DK" : true, "ER-DU" : true, "ER-GB" : true, "ER-MA" : true, + "ER-SK" : true, "ES-A" : true, "ES-AB" : true, "ES-AL" : true, "ES-AN" : true, + "ES-AR" : true, "ES-AS" : true, "ES-AV" : true, "ES-B" : true, "ES-BA" : true, + "ES-BI" : true, "ES-BU" : true, "ES-C" : true, "ES-CA" : true, "ES-CB" : true, + "ES-CC" : true, "ES-CE" : true, "ES-CL" : true, "ES-CM" : true, "ES-CN" : true, + "ES-CO" : true, "ES-CR" : true, "ES-CS" : true, "ES-CT" : true, "ES-CU" : true, + "ES-EX" : true, "ES-GA" : true, "ES-GC" : true, "ES-GI" : true, "ES-GR" : true, + "ES-GU" : true, "ES-H" : true, "ES-HU" : true, "ES-IB" : true, "ES-J" : true, + "ES-L" : true, "ES-LE" : true, "ES-LO" : true, "ES-LU" : true, "ES-M" : true, + "ES-MA" : true, "ES-MC" : true, "ES-MD" : true, "ES-ML" : true, "ES-MU" : true, + "ES-NA" : true, "ES-NC" : true, "ES-O" : true, "ES-OR" : true, "ES-P" : true, + "ES-PM" : true, "ES-PO" : true, "ES-PV" : true, "ES-RI" : true, "ES-S" : true, + "ES-SA" : true, "ES-SE" : true, "ES-SG" : true, "ES-SO" : true, "ES-SS" : true, + "ES-T" : true, "ES-TE" : true, "ES-TF" : true, "ES-TO" : true, "ES-V" : true, + "ES-VA" : true, "ES-VC" : true, "ES-VI" : true, "ES-Z" : true, "ES-ZA" : true, + "ET-AA" : true, "ET-AF" : true, "ET-AM" : true, "ET-BE" : true, "ET-DD" : true, + "ET-GA" : true, "ET-HA" : true, "ET-OR" : true, "ET-SN" : true, "ET-SO" : true, + "ET-TI" : true, "FI-01" : true, "FI-02" : true, "FI-03" : true, "FI-04" : true, + "FI-05" : true, "FI-06" : true, "FI-07" : true, "FI-08" : true, "FI-09" : true, + "FI-10" : true, "FI-11" : true, "FI-12" : true, "FI-13" : true, "FI-14" : true, + "FI-15" : true, "FI-16" : true, "FI-17" : true, "FI-18" : true, "FI-19" : true, + "FJ-C" : true, "FJ-E" : true, "FJ-N" : true, "FJ-R" : true, "FJ-W" : true, + "FM-KSA" : true, "FM-PNI" : true, "FM-TRK" : true, "FM-YAP" : true, "FR-01" : true, + "FR-02" : true, "FR-03" : true, "FR-04" : true, "FR-05" : true, "FR-06" : true, + "FR-07" : true, "FR-08" : true, "FR-09" : true, "FR-10" : true, "FR-11" : true, + "FR-12" : true, "FR-13" : true, "FR-14" : true, "FR-15" : true, "FR-16" : true, + "FR-17" : true, "FR-18" : true, "FR-19" : true, "FR-21" : true, "FR-22" : true, + "FR-23" : true, "FR-24" : true, "FR-25" : true, "FR-26" : true, "FR-27" : true, + "FR-28" : true, "FR-29" : true, "FR-2A" : true, "FR-2B" : true, "FR-30" : true, + "FR-31" : true, "FR-32" : true, "FR-33" : true, "FR-34" : true, "FR-35" : true, + "FR-36" : true, "FR-37" : true, "FR-38" : true, "FR-39" : true, "FR-40" : true, + "FR-41" : true, "FR-42" : true, "FR-43" : true, "FR-44" : true, "FR-45" : true, + "FR-46" : true, "FR-47" : true, "FR-48" : true, "FR-49" : true, "FR-50" : true, + "FR-51" : true, "FR-52" : true, "FR-53" : true, "FR-54" : true, "FR-55" : true, + "FR-56" : true, "FR-57" : true, "FR-58" : true, "FR-59" : true, "FR-60" : true, + "FR-61" : true, "FR-62" : true, "FR-63" : true, "FR-64" : true, "FR-65" : true, + "FR-66" : true, "FR-67" : true, "FR-68" : true, "FR-69" : true, "FR-70" : true, + "FR-71" : true, "FR-72" : true, "FR-73" : true, "FR-74" : true, "FR-75" : true, + "FR-76" : true, "FR-77" : true, "FR-78" : true, "FR-79" : true, "FR-80" : true, + "FR-81" : true, "FR-82" : true, "FR-83" : true, "FR-84" : true, "FR-85" : true, + "FR-86" : true, "FR-87" : true, "FR-88" : true, "FR-89" : true, "FR-90" : true, + "FR-91" : true, "FR-92" : true, "FR-93" : true, "FR-94" : true, "FR-95" : true, + "FR-ARA" : true, "FR-BFC" : true, "FR-BL" : true, "FR-BRE" : true, "FR-COR" : true, + "FR-CP" : true, "FR-CVL" : true, "FR-GES" : true, "FR-GF" : true, "FR-GP" : true, + "FR-GUA" : true, "FR-HDF" : true, "FR-IDF" : true, "FR-LRE" : true, "FR-MAY" : true, + "FR-MF" : true, "FR-MQ" : true, "FR-NAQ" : true, "FR-NC" : true, "FR-NOR" : true, + "FR-OCC" : true, "FR-PAC" : true, "FR-PDL" : true, "FR-PF" : true, "FR-PM" : true, + "FR-RE" : true, "FR-TF" : true, "FR-WF" : true, "FR-YT" : true, "GA-1" : true, + "GA-2" : true, "GA-3" : true, "GA-4" : true, "GA-5" : true, "GA-6" : true, + "GA-7" : true, "GA-8" : true, "GA-9" : true, "GB-ABC" : true, "GB-ABD" : true, + "GB-ABE" : true, "GB-AGB" : true, "GB-AGY" : true, "GB-AND" : true, "GB-ANN" : true, + "GB-ANS" : true, "GB-BAS" : true, "GB-BBD" : true, "GB-BDF" : true, "GB-BDG" : true, + "GB-BEN" : true, "GB-BEX" : true, "GB-BFS" : true, "GB-BGE" : true, "GB-BGW" : true, + "GB-BIR" : true, "GB-BKM" : true, "GB-BMH" : true, "GB-BNE" : true, "GB-BNH" : true, + "GB-BNS" : true, "GB-BOL" : true, "GB-BPL" : true, "GB-BRC" : true, "GB-BRD" : true, + "GB-BRY" : true, "GB-BST" : true, "GB-BUR" : true, "GB-CAM" : true, "GB-CAY" : true, + "GB-CBF" : true, "GB-CCG" : true, "GB-CGN" : true, "GB-CHE" : true, "GB-CHW" : true, + "GB-CLD" : true, "GB-CLK" : true, "GB-CMA" : true, "GB-CMD" : true, "GB-CMN" : true, + "GB-CON" : true, "GB-COV" : true, "GB-CRF" : true, "GB-CRY" : true, "GB-CWY" : true, + "GB-DAL" : true, "GB-DBY" : true, "GB-DEN" : true, "GB-DER" : true, "GB-DEV" : true, + "GB-DGY" : true, "GB-DNC" : true, "GB-DND" : true, "GB-DOR" : true, "GB-DRS" : true, + "GB-DUD" : true, "GB-DUR" : true, "GB-EAL" : true, "GB-EAW" : true, "GB-EAY" : true, + "GB-EDH" : true, "GB-EDU" : true, "GB-ELN" : true, "GB-ELS" : true, "GB-ENF" : true, + "GB-ENG" : true, "GB-ERW" : true, "GB-ERY" : true, "GB-ESS" : true, "GB-ESX" : true, + "GB-FAL" : true, "GB-FIF" : true, "GB-FLN" : true, "GB-FMO" : true, "GB-GAT" : true, + "GB-GBN" : true, "GB-GLG" : true, "GB-GLS" : true, "GB-GRE" : true, "GB-GWN" : true, + "GB-HAL" : true, "GB-HAM" : true, "GB-HAV" : true, "GB-HCK" : true, "GB-HEF" : true, + "GB-HIL" : true, "GB-HLD" : true, "GB-HMF" : true, "GB-HNS" : true, "GB-HPL" : true, + "GB-HRT" : true, "GB-HRW" : true, "GB-HRY" : true, "GB-IOS" : true, "GB-IOW" : true, + "GB-ISL" : true, "GB-IVC" : true, "GB-KEC" : true, "GB-KEN" : true, "GB-KHL" : true, + "GB-KIR" : true, "GB-KTT" : true, "GB-KWL" : true, "GB-LAN" : true, "GB-LBC" : true, + "GB-LBH" : true, "GB-LCE" : true, "GB-LDS" : true, "GB-LEC" : true, "GB-LEW" : true, + "GB-LIN" : true, "GB-LIV" : true, "GB-LND" : true, "GB-LUT" : true, "GB-MAN" : true, + "GB-MDB" : true, "GB-MDW" : true, "GB-MEA" : true, "GB-MIK" : true, "GD-01" : true, + "GB-MLN" : true, "GB-MON" : true, "GB-MRT" : true, "GB-MRY" : true, "GB-MTY" : true, + "GB-MUL" : true, "GB-NAY" : true, "GB-NBL" : true, "GB-NEL" : true, "GB-NET" : true, + "GB-NFK" : true, "GB-NGM" : true, "GB-NIR" : true, "GB-NLK" : true, "GB-NLN" : true, + "GB-NMD" : true, "GB-NSM" : true, "GB-NTH" : true, "GB-NTL" : true, "GB-NTT" : true, + "GB-NTY" : true, "GB-NWM" : true, "GB-NWP" : true, "GB-NYK" : true, "GB-OLD" : true, + "GB-ORK" : true, "GB-OXF" : true, "GB-PEM" : true, "GB-PKN" : true, "GB-PLY" : true, + "GB-POL" : true, "GB-POR" : true, "GB-POW" : true, "GB-PTE" : true, "GB-RCC" : true, + "GB-RCH" : true, "GB-RCT" : true, "GB-RDB" : true, "GB-RDG" : true, "GB-RFW" : true, + "GB-RIC" : true, "GB-ROT" : true, "GB-RUT" : true, "GB-SAW" : true, "GB-SAY" : true, + "GB-SCB" : true, "GB-SCT" : true, "GB-SFK" : true, "GB-SFT" : true, "GB-SGC" : true, + "GB-SHF" : true, "GB-SHN" : true, "GB-SHR" : true, "GB-SKP" : true, "GB-SLF" : true, + "GB-SLG" : true, "GB-SLK" : true, "GB-SND" : true, "GB-SOL" : true, "GB-SOM" : true, + "GB-SOS" : true, "GB-SRY" : true, "GB-STE" : true, "GB-STG" : true, "GB-STH" : true, + "GB-STN" : true, "GB-STS" : true, "GB-STT" : true, "GB-STY" : true, "GB-SWA" : true, + "GB-SWD" : true, "GB-SWK" : true, "GB-TAM" : true, "GB-TFW" : true, "GB-THR" : true, + "GB-TOB" : true, "GB-TOF" : true, "GB-TRF" : true, "GB-TWH" : true, "GB-UKM" : true, + "GB-VGL" : true, "GB-WAR" : true, "GB-WBK" : true, "GB-WDU" : true, "GB-WFT" : true, + "GB-WGN" : true, "GB-WIL" : true, "GB-WKF" : true, "GB-WLL" : true, "GB-WLN" : true, + "GB-WLS" : true, "GB-WLV" : true, "GB-WND" : true, "GB-WNM" : true, "GB-WOK" : true, + "GB-WOR" : true, "GB-WRL" : true, "GB-WRT" : true, "GB-WRX" : true, "GB-WSM" : true, + "GB-WSX" : true, "GB-YOR" : true, "GB-ZET" : true, "GD-02" : true, "GD-03" : true, + "GD-04" : true, "GD-05" : true, "GD-06" : true, "GD-10" : true, "GE-AB" : true, + "GE-AJ" : true, "GE-GU" : true, "GE-IM" : true, "GE-KA" : true, "GE-KK" : true, + "GE-MM" : true, "GE-RL" : true, "GE-SJ" : true, "GE-SK" : true, "GE-SZ" : true, + "GE-TB" : true, "GH-AA" : true, "GH-AH" : true, "GH-BA" : true, "GH-CP" : true, + "GH-EP" : true, "GH-NP" : true, "GH-TV" : true, "GH-UE" : true, "GH-UW" : true, + "GH-WP" : true, "GL-KU" : true, "GL-QA" : true, "GL-QE" : true, "GL-SM" : true, + "GM-B" : true, "GM-L" : true, "GM-M" : true, "GM-N" : true, "GM-U" : true, + "GM-W" : true, "GN-B" : true, "GN-BE" : true, "GN-BF" : true, "GN-BK" : true, + "GN-C" : true, "GN-CO" : true, "GN-D" : true, "GN-DB" : true, "GN-DI" : true, + "GN-DL" : true, "GN-DU" : true, "GN-F" : true, "GN-FA" : true, "GN-FO" : true, + "GN-FR" : true, "GN-GA" : true, "GN-GU" : true, "GN-K" : true, "GN-KA" : true, + "GN-KB" : true, "GN-KD" : true, "GN-KE" : true, "GN-KN" : true, "GN-KO" : true, + "GN-KS" : true, "GN-L" : true, "GN-LA" : true, "GN-LE" : true, "GN-LO" : true, + "GN-M" : true, "GN-MC" : true, "GN-MD" : true, "GN-ML" : true, "GN-MM" : true, + "GN-N" : true, "GN-NZ" : true, "GN-PI" : true, "GN-SI" : true, "GN-TE" : true, + "GN-TO" : true, "GN-YO" : true, "GQ-AN" : true, "GQ-BN" : true, "GQ-BS" : true, + "GQ-C" : true, "GQ-CS" : true, "GQ-I" : true, "GQ-KN" : true, "GQ-LI" : true, + "GQ-WN" : true, "GR-01" : true, "GR-03" : true, "GR-04" : true, "GR-05" : true, + "GR-06" : true, "GR-07" : true, "GR-11" : true, "GR-12" : true, "GR-13" : true, + "GR-14" : true, "GR-15" : true, "GR-16" : true, "GR-17" : true, "GR-21" : true, + "GR-22" : true, "GR-23" : true, "GR-24" : true, "GR-31" : true, "GR-32" : true, + "GR-33" : true, "GR-34" : true, "GR-41" : true, "GR-42" : true, "GR-43" : true, + "GR-44" : true, "GR-51" : true, "GR-52" : true, "GR-53" : true, "GR-54" : true, + "GR-55" : true, "GR-56" : true, "GR-57" : true, "GR-58" : true, "GR-59" : true, + "GR-61" : true, "GR-62" : true, "GR-63" : true, "GR-64" : true, "GR-69" : true, + "GR-71" : true, "GR-72" : true, "GR-73" : true, "GR-81" : true, "GR-82" : true, + "GR-83" : true, "GR-84" : true, "GR-85" : true, "GR-91" : true, "GR-92" : true, + "GR-93" : true, "GR-94" : true, "GR-A" : true, "GR-A1" : true, "GR-B" : true, + "GR-C" : true, "GR-D" : true, "GR-E" : true, "GR-F" : true, "GR-G" : true, + "GR-H" : true, "GR-I" : true, "GR-J" : true, "GR-K" : true, "GR-L" : true, + "GR-M" : true, "GT-AV" : true, "GT-BV" : true, "GT-CM" : true, "GT-CQ" : true, + "GT-ES" : true, "GT-GU" : true, "GT-HU" : true, "GT-IZ" : true, "GT-JA" : true, + "GT-JU" : true, "GT-PE" : true, "GT-PR" : true, "GT-QC" : true, "GT-QZ" : true, + "GT-RE" : true, "GT-SA" : true, "GT-SM" : true, "GT-SO" : true, "GT-SR" : true, + "GT-SU" : true, "GT-TO" : true, "GT-ZA" : true, "GW-BA" : true, "GW-BL" : true, + "GW-BM" : true, "GW-BS" : true, "GW-CA" : true, "GW-GA" : true, "GW-L" : true, + "GW-N" : true, "GW-OI" : true, "GW-QU" : true, "GW-S" : true, "GW-TO" : true, + "GY-BA" : true, "GY-CU" : true, "GY-DE" : true, "GY-EB" : true, "GY-ES" : true, + "GY-MA" : true, "GY-PM" : true, "GY-PT" : true, "GY-UD" : true, "GY-UT" : true, + "HN-AT" : true, "HN-CH" : true, "HN-CL" : true, "HN-CM" : true, "HN-CP" : true, + "HN-CR" : true, "HN-EP" : true, "HN-FM" : true, "HN-GD" : true, "HN-IB" : true, + "HN-IN" : true, "HN-LE" : true, "HN-LP" : true, "HN-OC" : true, "HN-OL" : true, + "HN-SB" : true, "HN-VA" : true, "HN-YO" : true, "HR-01" : true, "HR-02" : true, + "HR-03" : true, "HR-04" : true, "HR-05" : true, "HR-06" : true, "HR-07" : true, + "HR-08" : true, "HR-09" : true, "HR-10" : true, "HR-11" : true, "HR-12" : true, + "HR-13" : true, "HR-14" : true, "HR-15" : true, "HR-16" : true, "HR-17" : true, + "HR-18" : true, "HR-19" : true, "HR-20" : true, "HR-21" : true, "HT-AR" : true, + "HT-CE" : true, "HT-GA" : true, "HT-ND" : true, "HT-NE" : true, "HT-NO" : true, + "HT-OU" : true, "HT-SD" : true, "HT-SE" : true, "HU-BA" : true, "HU-BC" : true, + "HU-BE" : true, "HU-BK" : true, "HU-BU" : true, "HU-BZ" : true, "HU-CS" : true, + "HU-DE" : true, "HU-DU" : true, "HU-EG" : true, "HU-ER" : true, "HU-FE" : true, + "HU-GS" : true, "HU-GY" : true, "HU-HB" : true, "HU-HE" : true, "HU-HV" : true, + "HU-JN" : true, "HU-KE" : true, "HU-KM" : true, "HU-KV" : true, "HU-MI" : true, + "HU-NK" : true, "HU-NO" : true, "HU-NY" : true, "HU-PE" : true, "HU-PS" : true, + "HU-SD" : true, "HU-SF" : true, "HU-SH" : true, "HU-SK" : true, "HU-SN" : true, + "HU-SO" : true, "HU-SS" : true, "HU-ST" : true, "HU-SZ" : true, "HU-TB" : true, + "HU-TO" : true, "HU-VA" : true, "HU-VE" : true, "HU-VM" : true, "HU-ZA" : true, + "HU-ZE" : true, "ID-AC" : true, "ID-BA" : true, "ID-BB" : true, "ID-BE" : true, + "ID-BT" : true, "ID-GO" : true, "ID-IJ" : true, "ID-JA" : true, "ID-JB" : true, + "ID-JI" : true, "ID-JK" : true, "ID-JT" : true, "ID-JW" : true, "ID-KA" : true, + "ID-KB" : true, "ID-KI" : true, "ID-KR" : true, "ID-KS" : true, "ID-KT" : true, + "ID-LA" : true, "ID-MA" : true, "ID-ML" : true, "ID-MU" : true, "ID-NB" : true, + "ID-NT" : true, "ID-NU" : true, "ID-PA" : true, "ID-PB" : true, "ID-RI" : true, + "ID-SA" : true, "ID-SB" : true, "ID-SG" : true, "ID-SL" : true, "ID-SM" : true, + "ID-SN" : true, "ID-SR" : true, "ID-SS" : true, "ID-ST" : true, "ID-SU" : true, + "ID-YO" : true, "IE-C" : true, "IE-CE" : true, "IE-CN" : true, "IE-CO" : true, + "IE-CW" : true, "IE-D" : true, "IE-DL" : true, "IE-G" : true, "IE-KE" : true, + "IE-KK" : true, "IE-KY" : true, "IE-L" : true, "IE-LD" : true, "IE-LH" : true, + "IE-LK" : true, "IE-LM" : true, "IE-LS" : true, "IE-M" : true, "IE-MH" : true, + "IE-MN" : true, "IE-MO" : true, "IE-OY" : true, "IE-RN" : true, "IE-SO" : true, + "IE-TA" : true, "IE-U" : true, "IE-WD" : true, "IE-WH" : true, "IE-WW" : true, + "IE-WX" : true, "IL-D" : true, "IL-HA" : true, "IL-JM" : true, "IL-M" : true, + "IL-TA" : true, "IL-Z" : true, "IN-AN" : true, "IN-AP" : true, "IN-AR" : true, + "IN-AS" : true, "IN-BR" : true, "IN-CH" : true, "IN-CT" : true, "IN-DD" : true, + "IN-DL" : true, "IN-DN" : true, "IN-GA" : true, "IN-GJ" : true, "IN-HP" : true, + "IN-HR" : true, "IN-JH" : true, "IN-JK" : true, "IN-KA" : true, "IN-KL" : true, + "IN-LD" : true, "IN-MH" : true, "IN-ML" : true, "IN-MN" : true, "IN-MP" : true, + "IN-MZ" : true, "IN-NL" : true, "IN-OR" : true, "IN-PB" : true, "IN-PY" : true, + "IN-RJ" : true, "IN-SK" : true, "IN-TN" : true, "IN-TR" : true, "IN-UP" : true, + "IN-UT" : true, "IN-WB" : true, "IQ-AN" : true, "IQ-AR" : true, "IQ-BA" : true, + "IQ-BB" : true, "IQ-BG" : true, "IQ-DA" : true, "IQ-DI" : true, "IQ-DQ" : true, + "IQ-KA" : true, "IQ-MA" : true, "IQ-MU" : true, "IQ-NA" : true, "IQ-NI" : true, + "IQ-QA" : true, "IQ-SD" : true, "IQ-SW" : true, "IQ-TS" : true, "IQ-WA" : true, + "IR-01" : true, "IR-02" : true, "IR-03" : true, "IR-04" : true, "IR-05" : true, + "IR-06" : true, "IR-07" : true, "IR-08" : true, "IR-10" : true, "IR-11" : true, + "IR-12" : true, "IR-13" : true, "IR-14" : true, "IR-15" : true, "IR-16" : true, + "IR-17" : true, "IR-18" : true, "IR-19" : true, "IR-20" : true, "IR-21" : true, + "IR-22" : true, "IR-23" : true, "IR-24" : true, "IR-25" : true, "IR-26" : true, + "IR-27" : true, "IR-28" : true, "IR-29" : true, "IR-30" : true, "IR-31" : true, + "IS-0" : true, "IS-1" : true, "IS-2" : true, "IS-3" : true, "IS-4" : true, + "IS-5" : true, "IS-6" : true, "IS-7" : true, "IS-8" : true, "IT-21" : true, + "IT-23" : true, "IT-25" : true, "IT-32" : true, "IT-34" : true, "IT-36" : true, + "IT-42" : true, "IT-45" : true, "IT-52" : true, "IT-55" : true, "IT-57" : true, + "IT-62" : true, "IT-65" : true, "IT-67" : true, "IT-72" : true, "IT-75" : true, + "IT-77" : true, "IT-78" : true, "IT-82" : true, "IT-88" : true, "IT-AG" : true, + "IT-AL" : true, "IT-AN" : true, "IT-AO" : true, "IT-AP" : true, "IT-AQ" : true, + "IT-AR" : true, "IT-AT" : true, "IT-AV" : true, "IT-BA" : true, "IT-BG" : true, + "IT-BI" : true, "IT-BL" : true, "IT-BN" : true, "IT-BO" : true, "IT-BR" : true, + "IT-BS" : true, "IT-BT" : true, "IT-BZ" : true, "IT-CA" : true, "IT-CB" : true, + "IT-CE" : true, "IT-CH" : true, "IT-CI" : true, "IT-CL" : true, "IT-CN" : true, + "IT-CO" : true, "IT-CR" : true, "IT-CS" : true, "IT-CT" : true, "IT-CZ" : true, + "IT-EN" : true, "IT-FC" : true, "IT-FE" : true, "IT-FG" : true, "IT-FI" : true, + "IT-FM" : true, "IT-FR" : true, "IT-GE" : true, "IT-GO" : true, "IT-GR" : true, + "IT-IM" : true, "IT-IS" : true, "IT-KR" : true, "IT-LC" : true, "IT-LE" : true, + "IT-LI" : true, "IT-LO" : true, "IT-LT" : true, "IT-LU" : true, "IT-MB" : true, + "IT-MC" : true, "IT-ME" : true, "IT-MI" : true, "IT-MN" : true, "IT-MO" : true, + "IT-MS" : true, "IT-MT" : true, "IT-NA" : true, "IT-NO" : true, "IT-NU" : true, + "IT-OG" : true, "IT-OR" : true, "IT-OT" : true, "IT-PA" : true, "IT-PC" : true, + "IT-PD" : true, "IT-PE" : true, "IT-PG" : true, "IT-PI" : true, "IT-PN" : true, + "IT-PO" : true, "IT-PR" : true, "IT-PT" : true, "IT-PU" : true, "IT-PV" : true, + "IT-PZ" : true, "IT-RA" : true, "IT-RC" : true, "IT-RE" : true, "IT-RG" : true, + "IT-RI" : true, "IT-RM" : true, "IT-RN" : true, "IT-RO" : true, "IT-SA" : true, + "IT-SI" : true, "IT-SO" : true, "IT-SP" : true, "IT-SR" : true, "IT-SS" : true, + "IT-SV" : true, "IT-TA" : true, "IT-TE" : true, "IT-TN" : true, "IT-TO" : true, + "IT-TP" : true, "IT-TR" : true, "IT-TS" : true, "IT-TV" : true, "IT-UD" : true, + "IT-VA" : true, "IT-VB" : true, "IT-VC" : true, "IT-VE" : true, "IT-VI" : true, + "IT-VR" : true, "IT-VS" : true, "IT-VT" : true, "IT-VV" : true, "JM-01" : true, + "JM-02" : true, "JM-03" : true, "JM-04" : true, "JM-05" : true, "JM-06" : true, + "JM-07" : true, "JM-08" : true, "JM-09" : true, "JM-10" : true, "JM-11" : true, + "JM-12" : true, "JM-13" : true, "JM-14" : true, "JO-AJ" : true, "JO-AM" : true, + "JO-AQ" : true, "JO-AT" : true, "JO-AZ" : true, "JO-BA" : true, "JO-IR" : true, + "JO-JA" : true, "JO-KA" : true, "JO-MA" : true, "JO-MD" : true, "JO-MN" : true, + "JP-01" : true, "JP-02" : true, "JP-03" : true, "JP-04" : true, "JP-05" : true, + "JP-06" : true, "JP-07" : true, "JP-08" : true, "JP-09" : true, "JP-10" : true, + "JP-11" : true, "JP-12" : true, "JP-13" : true, "JP-14" : true, "JP-15" : true, + "JP-16" : true, "JP-17" : true, "JP-18" : true, "JP-19" : true, "JP-20" : true, + "JP-21" : true, "JP-22" : true, "JP-23" : true, "JP-24" : true, "JP-25" : true, + "JP-26" : true, "JP-27" : true, "JP-28" : true, "JP-29" : true, "JP-30" : true, + "JP-31" : true, "JP-32" : true, "JP-33" : true, "JP-34" : true, "JP-35" : true, + "JP-36" : true, "JP-37" : true, "JP-38" : true, "JP-39" : true, "JP-40" : true, + "JP-41" : true, "JP-42" : true, "JP-43" : true, "JP-44" : true, "JP-45" : true, + "JP-46" : true, "JP-47" : true, "KE-110" : true, "KE-200" : true, "KE-300" : true, + "KE-400" : true, "KE-500" : true, "KE-700" : true, "KE-800" : true, "KG-B" : true, + "KG-C" : true, "KG-GB" : true, "KG-J" : true, "KG-N" : true, "KG-O" : true, + "KG-T" : true, "KG-Y" : true, "KH-1" : true, "KH-10" : true, "KH-11" : true, + "KH-12" : true, "KH-13" : true, "KH-14" : true, "KH-15" : true, "KH-16" : true, + "KH-17" : true, "KH-18" : true, "KH-19" : true, "KH-2" : true, "KH-20" : true, + "KH-21" : true, "KH-22" : true, "KH-23" : true, "KH-24" : true, "KH-3" : true, + "KH-4" : true, "KH-5" : true, "KH-6" : true, "KH-7" : true, "KH-8" : true, + "KH-9" : true, "KI-G" : true, "KI-L" : true, "KI-P" : true, "KM-A" : true, + "KM-G" : true, "KM-M" : true, "KN-01" : true, "KN-02" : true, "KN-03" : true, + "KN-04" : true, "KN-05" : true, "KN-06" : true, "KN-07" : true, "KN-08" : true, + "KN-09" : true, "KN-10" : true, "KN-11" : true, "KN-12" : true, "KN-13" : true, + "KN-15" : true, "KN-K" : true, "KN-N" : true, "KP-01" : true, "KP-02" : true, + "KP-03" : true, "KP-04" : true, "KP-05" : true, "KP-06" : true, "KP-07" : true, + "KP-08" : true, "KP-09" : true, "KP-10" : true, "KP-13" : true, "KR-11" : true, + "KR-26" : true, "KR-27" : true, "KR-28" : true, "KR-29" : true, "KR-30" : true, + "KR-31" : true, "KR-41" : true, "KR-42" : true, "KR-43" : true, "KR-44" : true, + "KR-45" : true, "KR-46" : true, "KR-47" : true, "KR-48" : true, "KR-49" : true, + "KW-AH" : true, "KW-FA" : true, "KW-HA" : true, "KW-JA" : true, "KW-KU" : true, + "KW-MU" : true, "KZ-AKM" : true, "KZ-AKT" : true, "KZ-ALA" : true, "KZ-ALM" : true, + "KZ-AST" : true, "KZ-ATY" : true, "KZ-KAR" : true, "KZ-KUS" : true, "KZ-KZY" : true, + "KZ-MAN" : true, "KZ-PAV" : true, "KZ-SEV" : true, "KZ-VOS" : true, "KZ-YUZ" : true, + "KZ-ZAP" : true, "KZ-ZHA" : true, "LA-AT" : true, "LA-BK" : true, "LA-BL" : true, + "LA-CH" : true, "LA-HO" : true, "LA-KH" : true, "LA-LM" : true, "LA-LP" : true, + "LA-OU" : true, "LA-PH" : true, "LA-SL" : true, "LA-SV" : true, "LA-VI" : true, + "LA-VT" : true, "LA-XA" : true, "LA-XE" : true, "LA-XI" : true, "LA-XS" : true, + "LB-AK" : true, "LB-AS" : true, "LB-BA" : true, "LB-BH" : true, "LB-BI" : true, + "LB-JA" : true, "LB-JL" : true, "LB-NA" : true, "LI-01" : true, "LI-02" : true, + "LI-03" : true, "LI-04" : true, "LI-05" : true, "LI-06" : true, "LI-07" : true, + "LI-08" : true, "LI-09" : true, "LI-10" : true, "LI-11" : true, "LK-1" : true, + "LK-11" : true, "LK-12" : true, "LK-13" : true, "LK-2" : true, "LK-21" : true, + "LK-22" : true, "LK-23" : true, "LK-3" : true, "LK-31" : true, "LK-32" : true, + "LK-33" : true, "LK-4" : true, "LK-41" : true, "LK-42" : true, "LK-43" : true, + "LK-44" : true, "LK-45" : true, "LK-5" : true, "LK-51" : true, "LK-52" : true, + "LK-53" : true, "LK-6" : true, "LK-61" : true, "LK-62" : true, "LK-7" : true, + "LK-71" : true, "LK-72" : true, "LK-8" : true, "LK-81" : true, "LK-82" : true, + "LK-9" : true, "LK-91" : true, "LK-92" : true, "LR-BG" : true, "LR-BM" : true, + "LR-CM" : true, "LR-GB" : true, "LR-GG" : true, "LR-GK" : true, "LR-LO" : true, + "LR-MG" : true, "LR-MO" : true, "LR-MY" : true, "LR-NI" : true, "LR-RI" : true, + "LR-SI" : true, "LS-A" : true, "LS-B" : true, "LS-C" : true, "LS-D" : true, + "LS-E" : true, "LS-F" : true, "LS-G" : true, "LS-H" : true, "LS-J" : true, + "LS-K" : true, "LT-AL" : true, "LT-KL" : true, "LT-KU" : true, "LT-MR" : true, + "LT-PN" : true, "LT-SA" : true, "LT-TA" : true, "LT-TE" : true, "LT-UT" : true, + "LT-VL" : true, "LU-D" : true, "LU-G" : true, "LU-L" : true, "LV-001" : true, + "LV-002" : true, "LV-003" : true, "LV-004" : true, "LV-005" : true, "LV-006" : true, + "LV-007" : true, "LV-008" : true, "LV-009" : true, "LV-010" : true, "LV-011" : true, + "LV-012" : true, "LV-013" : true, "LV-014" : true, "LV-015" : true, "LV-016" : true, + "LV-017" : true, "LV-018" : true, "LV-019" : true, "LV-020" : true, "LV-021" : true, + "LV-022" : true, "LV-023" : true, "LV-024" : true, "LV-025" : true, "LV-026" : true, + "LV-027" : true, "LV-028" : true, "LV-029" : true, "LV-030" : true, "LV-031" : true, + "LV-032" : true, "LV-033" : true, "LV-034" : true, "LV-035" : true, "LV-036" : true, + "LV-037" : true, "LV-038" : true, "LV-039" : true, "LV-040" : true, "LV-041" : true, + "LV-042" : true, "LV-043" : true, "LV-044" : true, "LV-045" : true, "LV-046" : true, + "LV-047" : true, "LV-048" : true, "LV-049" : true, "LV-050" : true, "LV-051" : true, + "LV-052" : true, "LV-053" : true, "LV-054" : true, "LV-055" : true, "LV-056" : true, + "LV-057" : true, "LV-058" : true, "LV-059" : true, "LV-060" : true, "LV-061" : true, + "LV-062" : true, "LV-063" : true, "LV-064" : true, "LV-065" : true, "LV-066" : true, + "LV-067" : true, "LV-068" : true, "LV-069" : true, "LV-070" : true, "LV-071" : true, + "LV-072" : true, "LV-073" : true, "LV-074" : true, "LV-075" : true, "LV-076" : true, + "LV-077" : true, "LV-078" : true, "LV-079" : true, "LV-080" : true, "LV-081" : true, + "LV-082" : true, "LV-083" : true, "LV-084" : true, "LV-085" : true, "LV-086" : true, + "LV-087" : true, "LV-088" : true, "LV-089" : true, "LV-090" : true, "LV-091" : true, + "LV-092" : true, "LV-093" : true, "LV-094" : true, "LV-095" : true, "LV-096" : true, + "LV-097" : true, "LV-098" : true, "LV-099" : true, "LV-100" : true, "LV-101" : true, + "LV-102" : true, "LV-103" : true, "LV-104" : true, "LV-105" : true, "LV-106" : true, + "LV-107" : true, "LV-108" : true, "LV-109" : true, "LV-110" : true, "LV-DGV" : true, + "LV-JEL" : true, "LV-JKB" : true, "LV-JUR" : true, "LV-LPX" : true, "LV-REZ" : true, + "LV-RIX" : true, "LV-VEN" : true, "LV-VMR" : true, "LY-BA" : true, "LY-BU" : true, + "LY-DR" : true, "LY-GT" : true, "LY-JA" : true, "LY-JB" : true, "LY-JG" : true, + "LY-JI" : true, "LY-JU" : true, "LY-KF" : true, "LY-MB" : true, "LY-MI" : true, + "LY-MJ" : true, "LY-MQ" : true, "LY-NL" : true, "LY-NQ" : true, "LY-SB" : true, + "LY-SR" : true, "LY-TB" : true, "LY-WA" : true, "LY-WD" : true, "LY-WS" : true, + "LY-ZA" : true, "MA-01" : true, "MA-02" : true, "MA-03" : true, "MA-04" : true, + "MA-05" : true, "MA-06" : true, "MA-07" : true, "MA-08" : true, "MA-09" : true, + "MA-10" : true, "MA-11" : true, "MA-12" : true, "MA-13" : true, "MA-14" : true, + "MA-15" : true, "MA-16" : true, "MA-AGD" : true, "MA-AOU" : true, "MA-ASZ" : true, + "MA-AZI" : true, "MA-BEM" : true, "MA-BER" : true, "MA-BES" : true, "MA-BOD" : true, + "MA-BOM" : true, "MA-CAS" : true, "MA-CHE" : true, "MA-CHI" : true, "MA-CHT" : true, + "MA-ERR" : true, "MA-ESI" : true, "MA-ESM" : true, "MA-FAH" : true, "MA-FES" : true, + "MA-FIG" : true, "MA-GUE" : true, "MA-HAJ" : true, "MA-HAO" : true, "MA-HOC" : true, + "MA-IFR" : true, "MA-INE" : true, "MA-JDI" : true, "MA-JRA" : true, "MA-KEN" : true, + "MA-KES" : true, "MA-KHE" : true, "MA-KHN" : true, "MA-KHO" : true, "MA-LAA" : true, + "MA-LAR" : true, "MA-MED" : true, "MA-MEK" : true, "MA-MMD" : true, "MA-MMN" : true, + "MA-MOH" : true, "MA-MOU" : true, "MA-NAD" : true, "MA-NOU" : true, "MA-OUA" : true, + "MA-OUD" : true, "MA-OUJ" : true, "MA-RAB" : true, "MA-SAF" : true, "MA-SAL" : true, + "MA-SEF" : true, "MA-SET" : true, "MA-SIK" : true, "MA-SKH" : true, "MA-SYB" : true, + "MA-TAI" : true, "MA-TAO" : true, "MA-TAR" : true, "MA-TAT" : true, "MA-TAZ" : true, + "MA-TET" : true, "MA-TIZ" : true, "MA-TNG" : true, "MA-TNT" : true, "MA-ZAG" : true, + "MC-CL" : true, "MC-CO" : true, "MC-FO" : true, "MC-GA" : true, "MC-JE" : true, + "MC-LA" : true, "MC-MA" : true, "MC-MC" : true, "MC-MG" : true, "MC-MO" : true, + "MC-MU" : true, "MC-PH" : true, "MC-SD" : true, "MC-SO" : true, "MC-SP" : true, + "MC-SR" : true, "MC-VR" : true, "MD-AN" : true, "MD-BA" : true, "MD-BD" : true, + "MD-BR" : true, "MD-BS" : true, "MD-CA" : true, "MD-CL" : true, "MD-CM" : true, + "MD-CR" : true, "MD-CS" : true, "MD-CT" : true, "MD-CU" : true, "MD-DO" : true, + "MD-DR" : true, "MD-DU" : true, "MD-ED" : true, "MD-FA" : true, "MD-FL" : true, + "MD-GA" : true, "MD-GL" : true, "MD-HI" : true, "MD-IA" : true, "MD-LE" : true, + "MD-NI" : true, "MD-OC" : true, "MD-OR" : true, "MD-RE" : true, "MD-RI" : true, + "MD-SD" : true, "MD-SI" : true, "MD-SN" : true, "MD-SO" : true, "MD-ST" : true, + "MD-SV" : true, "MD-TA" : true, "MD-TE" : true, "MD-UN" : true, "ME-01" : true, + "ME-02" : true, "ME-03" : true, "ME-04" : true, "ME-05" : true, "ME-06" : true, + "ME-07" : true, "ME-08" : true, "ME-09" : true, "ME-10" : true, "ME-11" : true, + "ME-12" : true, "ME-13" : true, "ME-14" : true, "ME-15" : true, "ME-16" : true, + "ME-17" : true, "ME-18" : true, "ME-19" : true, "ME-20" : true, "ME-21" : true, + "MG-A" : true, "MG-D" : true, "MG-F" : true, "MG-M" : true, "MG-T" : true, + "MG-U" : true, "MH-ALK" : true, "MH-ALL" : true, "MH-ARN" : true, "MH-AUR" : true, + "MH-EBO" : true, "MH-ENI" : true, "MH-JAB" : true, "MH-JAL" : true, "MH-KIL" : true, + "MH-KWA" : true, "MH-L" : true, "MH-LAE" : true, "MH-LIB" : true, "MH-LIK" : true, + "MH-MAJ" : true, "MH-MAL" : true, "MH-MEJ" : true, "MH-MIL" : true, "MH-NMK" : true, + "MH-NMU" : true, "MH-RON" : true, "MH-T" : true, "MH-UJA" : true, "MH-UTI" : true, + "MH-WTJ" : true, "MH-WTN" : true, "MK-01" : true, "MK-02" : true, "MK-03" : true, + "MK-04" : true, "MK-05" : true, "MK-06" : true, "MK-07" : true, "MK-08" : true, + "MK-09" : true, "MK-10" : true, "MK-11" : true, "MK-12" : true, "MK-13" : true, + "MK-14" : true, "MK-15" : true, "MK-16" : true, "MK-17" : true, "MK-18" : true, + "MK-19" : true, "MK-20" : true, "MK-21" : true, "MK-22" : true, "MK-23" : true, + "MK-24" : true, "MK-25" : true, "MK-26" : true, "MK-27" : true, "MK-28" : true, + "MK-29" : true, "MK-30" : true, "MK-31" : true, "MK-32" : true, "MK-33" : true, + "MK-34" : true, "MK-35" : true, "MK-36" : true, "MK-37" : true, "MK-38" : true, + "MK-39" : true, "MK-40" : true, "MK-41" : true, "MK-42" : true, "MK-43" : true, + "MK-44" : true, "MK-45" : true, "MK-46" : true, "MK-47" : true, "MK-48" : true, + "MK-49" : true, "MK-50" : true, "MK-51" : true, "MK-52" : true, "MK-53" : true, + "MK-54" : true, "MK-55" : true, "MK-56" : true, "MK-57" : true, "MK-58" : true, + "MK-59" : true, "MK-60" : true, "MK-61" : true, "MK-62" : true, "MK-63" : true, + "MK-64" : true, "MK-65" : true, "MK-66" : true, "MK-67" : true, "MK-68" : true, + "MK-69" : true, "MK-70" : true, "MK-71" : true, "MK-72" : true, "MK-73" : true, + "MK-74" : true, "MK-75" : true, "MK-76" : true, "MK-77" : true, "MK-78" : true, + "MK-79" : true, "MK-80" : true, "MK-81" : true, "MK-82" : true, "MK-83" : true, + "MK-84" : true, "ML-1" : true, "ML-2" : true, "ML-3" : true, "ML-4" : true, + "ML-5" : true, "ML-6" : true, "ML-7" : true, "ML-8" : true, "ML-BK0" : true, + "MM-01" : true, "MM-02" : true, "MM-03" : true, "MM-04" : true, "MM-05" : true, + "MM-06" : true, "MM-07" : true, "MM-11" : true, "MM-12" : true, "MM-13" : true, + "MM-14" : true, "MM-15" : true, "MM-16" : true, "MM-17" : true, "MN-035" : true, + "MN-037" : true, "MN-039" : true, "MN-041" : true, "MN-043" : true, "MN-046" : true, + "MN-047" : true, "MN-049" : true, "MN-051" : true, "MN-053" : true, "MN-055" : true, + "MN-057" : true, "MN-059" : true, "MN-061" : true, "MN-063" : true, "MN-064" : true, + "MN-065" : true, "MN-067" : true, "MN-069" : true, "MN-071" : true, "MN-073" : true, + "MN-1" : true, "MR-01" : true, "MR-02" : true, "MR-03" : true, "MR-04" : true, + "MR-05" : true, "MR-06" : true, "MR-07" : true, "MR-08" : true, "MR-09" : true, + "MR-10" : true, "MR-11" : true, "MR-12" : true, "MR-NKC" : true, "MT-01" : true, + "MT-02" : true, "MT-03" : true, "MT-04" : true, "MT-05" : true, "MT-06" : true, + "MT-07" : true, "MT-08" : true, "MT-09" : true, "MT-10" : true, "MT-11" : true, + "MT-12" : true, "MT-13" : true, "MT-14" : true, "MT-15" : true, "MT-16" : true, + "MT-17" : true, "MT-18" : true, "MT-19" : true, "MT-20" : true, "MT-21" : true, + "MT-22" : true, "MT-23" : true, "MT-24" : true, "MT-25" : true, "MT-26" : true, + "MT-27" : true, "MT-28" : true, "MT-29" : true, "MT-30" : true, "MT-31" : true, + "MT-32" : true, "MT-33" : true, "MT-34" : true, "MT-35" : true, "MT-36" : true, + "MT-37" : true, "MT-38" : true, "MT-39" : true, "MT-40" : true, "MT-41" : true, + "MT-42" : true, "MT-43" : true, "MT-44" : true, "MT-45" : true, "MT-46" : true, + "MT-47" : true, "MT-48" : true, "MT-49" : true, "MT-50" : true, "MT-51" : true, + "MT-52" : true, "MT-53" : true, "MT-54" : true, "MT-55" : true, "MT-56" : true, + "MT-57" : true, "MT-58" : true, "MT-59" : true, "MT-60" : true, "MT-61" : true, + "MT-62" : true, "MT-63" : true, "MT-64" : true, "MT-65" : true, "MT-66" : true, + "MT-67" : true, "MT-68" : true, "MU-AG" : true, "MU-BL" : true, "MU-BR" : true, + "MU-CC" : true, "MU-CU" : true, "MU-FL" : true, "MU-GP" : true, "MU-MO" : true, + "MU-PA" : true, "MU-PL" : true, "MU-PU" : true, "MU-PW" : true, "MU-QB" : true, + "MU-RO" : true, "MU-RP" : true, "MU-SA" : true, "MU-VP" : true, "MV-00" : true, + "MV-01" : true, "MV-02" : true, "MV-03" : true, "MV-04" : true, "MV-05" : true, + "MV-07" : true, "MV-08" : true, "MV-12" : true, "MV-13" : true, "MV-14" : true, + "MV-17" : true, "MV-20" : true, "MV-23" : true, "MV-24" : true, "MV-25" : true, + "MV-26" : true, "MV-27" : true, "MV-28" : true, "MV-29" : true, "MV-CE" : true, + "MV-MLE" : true, "MV-NC" : true, "MV-NO" : true, "MV-SC" : true, "MV-SU" : true, + "MV-UN" : true, "MV-US" : true, "MW-BA" : true, "MW-BL" : true, "MW-C" : true, + "MW-CK" : true, "MW-CR" : true, "MW-CT" : true, "MW-DE" : true, "MW-DO" : true, + "MW-KR" : true, "MW-KS" : true, "MW-LI" : true, "MW-LK" : true, "MW-MC" : true, + "MW-MG" : true, "MW-MH" : true, "MW-MU" : true, "MW-MW" : true, "MW-MZ" : true, + "MW-N" : true, "MW-NB" : true, "MW-NE" : true, "MW-NI" : true, "MW-NK" : true, + "MW-NS" : true, "MW-NU" : true, "MW-PH" : true, "MW-RU" : true, "MW-S" : true, + "MW-SA" : true, "MW-TH" : true, "MW-ZO" : true, "MX-AGU" : true, "MX-BCN" : true, + "MX-BCS" : true, "MX-CAM" : true, "MX-CHH" : true, "MX-CHP" : true, "MX-COA" : true, + "MX-COL" : true, "MX-DIF" : true, "MX-DUR" : true, "MX-GRO" : true, "MX-GUA" : true, + "MX-HID" : true, "MX-JAL" : true, "MX-MEX" : true, "MX-MIC" : true, "MX-MOR" : true, + "MX-NAY" : true, "MX-NLE" : true, "MX-OAX" : true, "MX-PUE" : true, "MX-QUE" : true, + "MX-ROO" : true, "MX-SIN" : true, "MX-SLP" : true, "MX-SON" : true, "MX-TAB" : true, + "MX-TAM" : true, "MX-TLA" : true, "MX-VER" : true, "MX-YUC" : true, "MX-ZAC" : true, + "MY-01" : true, "MY-02" : true, "MY-03" : true, "MY-04" : true, "MY-05" : true, + "MY-06" : true, "MY-07" : true, "MY-08" : true, "MY-09" : true, "MY-10" : true, + "MY-11" : true, "MY-12" : true, "MY-13" : true, "MY-14" : true, "MY-15" : true, + "MY-16" : true, "MZ-A" : true, "MZ-B" : true, "MZ-G" : true, "MZ-I" : true, + "MZ-L" : true, "MZ-MPM" : true, "MZ-N" : true, "MZ-P" : true, "MZ-Q" : true, + "MZ-S" : true, "MZ-T" : true, "NA-CA" : true, "NA-ER" : true, "NA-HA" : true, + "NA-KA" : true, "NA-KH" : true, "NA-KU" : true, "NA-OD" : true, "NA-OH" : true, + "NA-OK" : true, "NA-ON" : true, "NA-OS" : true, "NA-OT" : true, "NA-OW" : true, + "NE-1" : true, "NE-2" : true, "NE-3" : true, "NE-4" : true, "NE-5" : true, + "NE-6" : true, "NE-7" : true, "NE-8" : true, "NG-AB" : true, "NG-AD" : true, + "NG-AK" : true, "NG-AN" : true, "NG-BA" : true, "NG-BE" : true, "NG-BO" : true, + "NG-BY" : true, "NG-CR" : true, "NG-DE" : true, "NG-EB" : true, "NG-ED" : true, + "NG-EK" : true, "NG-EN" : true, "NG-FC" : true, "NG-GO" : true, "NG-IM" : true, + "NG-JI" : true, "NG-KD" : true, "NG-KE" : true, "NG-KN" : true, "NG-KO" : true, + "NG-KT" : true, "NG-KW" : true, "NG-LA" : true, "NG-NA" : true, "NG-NI" : true, + "NG-OG" : true, "NG-ON" : true, "NG-OS" : true, "NG-OY" : true, "NG-PL" : true, + "NG-RI" : true, "NG-SO" : true, "NG-TA" : true, "NG-YO" : true, "NG-ZA" : true, + "NI-AN" : true, "NI-AS" : true, "NI-BO" : true, "NI-CA" : true, "NI-CI" : true, + "NI-CO" : true, "NI-ES" : true, "NI-GR" : true, "NI-JI" : true, "NI-LE" : true, + "NI-MD" : true, "NI-MN" : true, "NI-MS" : true, "NI-MT" : true, "NI-NS" : true, + "NI-RI" : true, "NI-SJ" : true, "NL-AW" : true, "NL-BQ1" : true, "NL-BQ2" : true, + "NL-BQ3" : true, "NL-CW" : true, "NL-DR" : true, "NL-FL" : true, "NL-FR" : true, + "NL-GE" : true, "NL-GR" : true, "NL-LI" : true, "NL-NB" : true, "NL-NH" : true, + "NL-OV" : true, "NL-SX" : true, "NL-UT" : true, "NL-ZE" : true, "NL-ZH" : true, + "NO-01" : true, "NO-02" : true, "NO-03" : true, "NO-04" : true, "NO-05" : true, + "NO-06" : true, "NO-07" : true, "NO-08" : true, "NO-09" : true, "NO-10" : true, + "NO-11" : true, "NO-12" : true, "NO-14" : true, "NO-15" : true, "NO-16" : true, + "NO-17" : true, "NO-18" : true, "NO-19" : true, "NO-20" : true, "NO-21" : true, + "NO-22" : true, "NP-1" : true, "NP-2" : true, "NP-3" : true, "NP-4" : true, + "NP-5" : true, "NP-BA" : true, "NP-BH" : true, "NP-DH" : true, "NP-GA" : true, + "NP-JA" : true, "NP-KA" : true, "NP-KO" : true, "NP-LU" : true, "NP-MA" : true, + "NP-ME" : true, "NP-NA" : true, "NP-RA" : true, "NP-SA" : true, "NP-SE" : true, + "NR-01" : true, "NR-02" : true, "NR-03" : true, "NR-04" : true, "NR-05" : true, + "NR-06" : true, "NR-07" : true, "NR-08" : true, "NR-09" : true, "NR-10" : true, + "NR-11" : true, "NR-12" : true, "NR-13" : true, "NR-14" : true, "NZ-AUK" : true, + "NZ-BOP" : true, "NZ-CAN" : true, "NZ-CIT" : true, "NZ-GIS" : true, "NZ-HKB" : true, + "NZ-MBH" : true, "NZ-MWT" : true, "NZ-N" : true, "NZ-NSN" : true, "NZ-NTL" : true, + "NZ-OTA" : true, "NZ-S" : true, "NZ-STL" : true, "NZ-TAS" : true, "NZ-TKI" : true, + "NZ-WGN" : true, "NZ-WKO" : true, "NZ-WTC" : true, "OM-BA" : true, "OM-BU" : true, + "OM-DA" : true, "OM-MA" : true, "OM-MU" : true, "OM-SH" : true, "OM-WU" : true, + "OM-ZA" : true, "OM-ZU" : true, "PA-1" : true, "PA-2" : true, "PA-3" : true, + "PA-4" : true, "PA-5" : true, "PA-6" : true, "PA-7" : true, "PA-8" : true, + "PA-9" : true, "PA-EM" : true, "PA-KY" : true, "PA-NB" : true, "PE-AMA" : true, + "PE-ANC" : true, "PE-APU" : true, "PE-ARE" : true, "PE-AYA" : true, "PE-CAJ" : true, + "PE-CAL" : true, "PE-CUS" : true, "PE-HUC" : true, "PE-HUV" : true, "PE-ICA" : true, + "PE-JUN" : true, "PE-LAL" : true, "PE-LAM" : true, "PE-LIM" : true, "PE-LMA" : true, + "PE-LOR" : true, "PE-MDD" : true, "PE-MOQ" : true, "PE-PAS" : true, "PE-PIU" : true, + "PE-PUN" : true, "PE-SAM" : true, "PE-TAC" : true, "PE-TUM" : true, "PE-UCA" : true, + "PG-CPK" : true, "PG-CPM" : true, "PG-EBR" : true, "PG-EHG" : true, "PG-EPW" : true, + "PG-ESW" : true, "PG-GPK" : true, "PG-MBA" : true, "PG-MPL" : true, "PG-MPM" : true, + "PG-MRL" : true, "PG-NCD" : true, "PG-NIK" : true, "PG-NPP" : true, "PG-NSB" : true, + "PG-SAN" : true, "PG-SHM" : true, "PG-WBK" : true, "PG-WHM" : true, "PG-WPD" : true, + "PH-00" : true, "PH-01" : true, "PH-02" : true, "PH-03" : true, "PH-05" : true, + "PH-06" : true, "PH-07" : true, "PH-08" : true, "PH-09" : true, "PH-10" : true, + "PH-11" : true, "PH-12" : true, "PH-13" : true, "PH-14" : true, "PH-15" : true, + "PH-40" : true, "PH-41" : true, "PH-ABR" : true, "PH-AGN" : true, "PH-AGS" : true, + "PH-AKL" : true, "PH-ALB" : true, "PH-ANT" : true, "PH-APA" : true, "PH-AUR" : true, + "PH-BAN" : true, "PH-BAS" : true, "PH-BEN" : true, "PH-BIL" : true, "PH-BOH" : true, + "PH-BTG" : true, "PH-BTN" : true, "PH-BUK" : true, "PH-BUL" : true, "PH-CAG" : true, + "PH-CAM" : true, "PH-CAN" : true, "PH-CAP" : true, "PH-CAS" : true, "PH-CAT" : true, + "PH-CAV" : true, "PH-CEB" : true, "PH-COM" : true, "PH-DAO" : true, "PH-DAS" : true, + "PH-DAV" : true, "PH-DIN" : true, "PH-EAS" : true, "PH-GUI" : true, "PH-IFU" : true, + "PH-ILI" : true, "PH-ILN" : true, "PH-ILS" : true, "PH-ISA" : true, "PH-KAL" : true, + "PH-LAG" : true, "PH-LAN" : true, "PH-LAS" : true, "PH-LEY" : true, "PH-LUN" : true, + "PH-MAD" : true, "PH-MAG" : true, "PH-MAS" : true, "PH-MDC" : true, "PH-MDR" : true, + "PH-MOU" : true, "PH-MSC" : true, "PH-MSR" : true, "PH-NCO" : true, "PH-NEC" : true, + "PH-NER" : true, "PH-NSA" : true, "PH-NUE" : true, "PH-NUV" : true, "PH-PAM" : true, + "PH-PAN" : true, "PH-PLW" : true, "PH-QUE" : true, "PH-QUI" : true, "PH-RIZ" : true, + "PH-ROM" : true, "PH-SAR" : true, "PH-SCO" : true, "PH-SIG" : true, "PH-SLE" : true, + "PH-SLU" : true, "PH-SOR" : true, "PH-SUK" : true, "PH-SUN" : true, "PH-SUR" : true, + "PH-TAR" : true, "PH-TAW" : true, "PH-WSA" : true, "PH-ZAN" : true, "PH-ZAS" : true, + "PH-ZMB" : true, "PH-ZSI" : true, "PK-BA" : true, "PK-GB" : true, "PK-IS" : true, + "PK-JK" : true, "PK-KP" : true, "PK-PB" : true, "PK-SD" : true, "PK-TA" : true, + "PL-DS" : true, "PL-KP" : true, "PL-LB" : true, "PL-LD" : true, "PL-LU" : true, + "PL-MA" : true, "PL-MZ" : true, "PL-OP" : true, "PL-PD" : true, "PL-PK" : true, + "PL-PM" : true, "PL-SK" : true, "PL-SL" : true, "PL-WN" : true, "PL-WP" : true, + "PL-ZP" : true, "PS-BTH" : true, "PS-DEB" : true, "PS-GZA" : true, "PS-HBN" : true, + "PS-JEM" : true, "PS-JEN" : true, "PS-JRH" : true, "PS-KYS" : true, "PS-NBS" : true, + "PS-NGZ" : true, "PS-QQA" : true, "PS-RBH" : true, "PS-RFH" : true, "PS-SLT" : true, + "PS-TBS" : true, "PS-TKM" : true, "PT-01" : true, "PT-02" : true, "PT-03" : true, + "PT-04" : true, "PT-05" : true, "PT-06" : true, "PT-07" : true, "PT-08" : true, + "PT-09" : true, "PT-10" : true, "PT-11" : true, "PT-12" : true, "PT-13" : true, + "PT-14" : true, "PT-15" : true, "PT-16" : true, "PT-17" : true, "PT-18" : true, + "PT-20" : true, "PT-30" : true, "PW-002" : true, "PW-004" : true, "PW-010" : true, + "PW-050" : true, "PW-100" : true, "PW-150" : true, "PW-212" : true, "PW-214" : true, + "PW-218" : true, "PW-222" : true, "PW-224" : true, "PW-226" : true, "PW-227" : true, + "PW-228" : true, "PW-350" : true, "PW-370" : true, "PY-1" : true, "PY-10" : true, + "PY-11" : true, "PY-12" : true, "PY-13" : true, "PY-14" : true, "PY-15" : true, + "PY-16" : true, "PY-19" : true, "PY-2" : true, "PY-3" : true, "PY-4" : true, + "PY-5" : true, "PY-6" : true, "PY-7" : true, "PY-8" : true, "PY-9" : true, + "PY-ASU" : true, "QA-DA" : true, "QA-KH" : true, "QA-MS" : true, "QA-RA" : true, + "QA-US" : true, "QA-WA" : true, "QA-ZA" : true, "RO-AB" : true, "RO-AG" : true, + "RO-AR" : true, "RO-B" : true, "RO-BC" : true, "RO-BH" : true, "RO-BN" : true, + "RO-BR" : true, "RO-BT" : true, "RO-BV" : true, "RO-BZ" : true, "RO-CJ" : true, + "RO-CL" : true, "RO-CS" : true, "RO-CT" : true, "RO-CV" : true, "RO-DB" : true, + "RO-DJ" : true, "RO-GJ" : true, "RO-GL" : true, "RO-GR" : true, "RO-HD" : true, + "RO-HR" : true, "RO-IF" : true, "RO-IL" : true, "RO-IS" : true, "RO-MH" : true, + "RO-MM" : true, "RO-MS" : true, "RO-NT" : true, "RO-OT" : true, "RO-PH" : true, + "RO-SB" : true, "RO-SJ" : true, "RO-SM" : true, "RO-SV" : true, "RO-TL" : true, + "RO-TM" : true, "RO-TR" : true, "RO-VL" : true, "RO-VN" : true, "RO-VS" : true, + "RS-00" : true, "RS-01" : true, "RS-02" : true, "RS-03" : true, "RS-04" : true, + "RS-05" : true, "RS-06" : true, "RS-07" : true, "RS-08" : true, "RS-09" : true, + "RS-10" : true, "RS-11" : true, "RS-12" : true, "RS-13" : true, "RS-14" : true, + "RS-15" : true, "RS-16" : true, "RS-17" : true, "RS-18" : true, "RS-19" : true, + "RS-20" : true, "RS-21" : true, "RS-22" : true, "RS-23" : true, "RS-24" : true, + "RS-25" : true, "RS-26" : true, "RS-27" : true, "RS-28" : true, "RS-29" : true, + "RS-KM" : true, "RS-VO" : true, "RU-AD" : true, "RU-AL" : true, "RU-ALT" : true, + "RU-AMU" : true, "RU-ARK" : true, "RU-AST" : true, "RU-BA" : true, "RU-BEL" : true, + "RU-BRY" : true, "RU-BU" : true, "RU-CE" : true, "RU-CHE" : true, "RU-CHU" : true, + "RU-CU" : true, "RU-DA" : true, "RU-IN" : true, "RU-IRK" : true, "RU-IVA" : true, + "RU-KAM" : true, "RU-KB" : true, "RU-KC" : true, "RU-KDA" : true, "RU-KEM" : true, + "RU-KGD" : true, "RU-KGN" : true, "RU-KHA" : true, "RU-KHM" : true, "RU-KIR" : true, + "RU-KK" : true, "RU-KL" : true, "RU-KLU" : true, "RU-KO" : true, "RU-KOS" : true, + "RU-KR" : true, "RU-KRS" : true, "RU-KYA" : true, "RU-LEN" : true, "RU-LIP" : true, + "RU-MAG" : true, "RU-ME" : true, "RU-MO" : true, "RU-MOS" : true, "RU-MOW" : true, + "RU-MUR" : true, "RU-NEN" : true, "RU-NGR" : true, "RU-NIZ" : true, "RU-NVS" : true, + "RU-OMS" : true, "RU-ORE" : true, "RU-ORL" : true, "RU-PER" : true, "RU-PNZ" : true, + "RU-PRI" : true, "RU-PSK" : true, "RU-ROS" : true, "RU-RYA" : true, "RU-SA" : true, + "RU-SAK" : true, "RU-SAM" : true, "RU-SAR" : true, "RU-SE" : true, "RU-SMO" : true, + "RU-SPE" : true, "RU-STA" : true, "RU-SVE" : true, "RU-TA" : true, "RU-TAM" : true, + "RU-TOM" : true, "RU-TUL" : true, "RU-TVE" : true, "RU-TY" : true, "RU-TYU" : true, + "RU-UD" : true, "RU-ULY" : true, "RU-VGG" : true, "RU-VLA" : true, "RU-VLG" : true, + "RU-VOR" : true, "RU-YAN" : true, "RU-YAR" : true, "RU-YEV" : true, "RU-ZAB" : true, + "RW-01" : true, "RW-02" : true, "RW-03" : true, "RW-04" : true, "RW-05" : true, + "SA-01" : true, "SA-02" : true, "SA-03" : true, "SA-04" : true, "SA-05" : true, + "SA-06" : true, "SA-07" : true, "SA-08" : true, "SA-09" : true, "SA-10" : true, + "SA-11" : true, "SA-12" : true, "SA-14" : true, "SB-CE" : true, "SB-CH" : true, + "SB-CT" : true, "SB-GU" : true, "SB-IS" : true, "SB-MK" : true, "SB-ML" : true, + "SB-RB" : true, "SB-TE" : true, "SB-WE" : true, "SC-01" : true, "SC-02" : true, + "SC-03" : true, "SC-04" : true, "SC-05" : true, "SC-06" : true, "SC-07" : true, + "SC-08" : true, "SC-09" : true, "SC-10" : true, "SC-11" : true, "SC-12" : true, + "SC-13" : true, "SC-14" : true, "SC-15" : true, "SC-16" : true, "SC-17" : true, + "SC-18" : true, "SC-19" : true, "SC-20" : true, "SC-21" : true, "SC-22" : true, + "SC-23" : true, "SC-24" : true, "SC-25" : true, "SD-DC" : true, "SD-DE" : true, + "SD-DN" : true, "SD-DS" : true, "SD-DW" : true, "SD-GD" : true, "SD-GZ" : true, + "SD-KA" : true, "SD-KH" : true, "SD-KN" : true, "SD-KS" : true, "SD-NB" : true, + "SD-NO" : true, "SD-NR" : true, "SD-NW" : true, "SD-RS" : true, "SD-SI" : true, + "SE-AB" : true, "SE-AC" : true, "SE-BD" : true, "SE-C" : true, "SE-D" : true, + "SE-E" : true, "SE-F" : true, "SE-G" : true, "SE-H" : true, "SE-I" : true, + "SE-K" : true, "SE-M" : true, "SE-N" : true, "SE-O" : true, "SE-S" : true, + "SE-T" : true, "SE-U" : true, "SE-W" : true, "SE-X" : true, "SE-Y" : true, + "SE-Z" : true, "SG-01" : true, "SG-02" : true, "SG-03" : true, "SG-04" : true, + "SG-05" : true, "SH-AC" : true, "SH-HL" : true, "SH-TA" : true, "SI-001" : true, + "SI-002" : true, "SI-003" : true, "SI-004" : true, "SI-005" : true, "SI-006" : true, + "SI-007" : true, "SI-008" : true, "SI-009" : true, "SI-010" : true, "SI-011" : true, + "SI-012" : true, "SI-013" : true, "SI-014" : true, "SI-015" : true, "SI-016" : true, + "SI-017" : true, "SI-018" : true, "SI-019" : true, "SI-020" : true, "SI-021" : true, + "SI-022" : true, "SI-023" : true, "SI-024" : true, "SI-025" : true, "SI-026" : true, + "SI-027" : true, "SI-028" : true, "SI-029" : true, "SI-030" : true, "SI-031" : true, + "SI-032" : true, "SI-033" : true, "SI-034" : true, "SI-035" : true, "SI-036" : true, + "SI-037" : true, "SI-038" : true, "SI-039" : true, "SI-040" : true, "SI-041" : true, + "SI-042" : true, "SI-043" : true, "SI-044" : true, "SI-045" : true, "SI-046" : true, + "SI-047" : true, "SI-048" : true, "SI-049" : true, "SI-050" : true, "SI-051" : true, + "SI-052" : true, "SI-053" : true, "SI-054" : true, "SI-055" : true, "SI-056" : true, + "SI-057" : true, "SI-058" : true, "SI-059" : true, "SI-060" : true, "SI-061" : true, + "SI-062" : true, "SI-063" : true, "SI-064" : true, "SI-065" : true, "SI-066" : true, + "SI-067" : true, "SI-068" : true, "SI-069" : true, "SI-070" : true, "SI-071" : true, + "SI-072" : true, "SI-073" : true, "SI-074" : true, "SI-075" : true, "SI-076" : true, + "SI-077" : true, "SI-078" : true, "SI-079" : true, "SI-080" : true, "SI-081" : true, + "SI-082" : true, "SI-083" : true, "SI-084" : true, "SI-085" : true, "SI-086" : true, + "SI-087" : true, "SI-088" : true, "SI-089" : true, "SI-090" : true, "SI-091" : true, + "SI-092" : true, "SI-093" : true, "SI-094" : true, "SI-095" : true, "SI-096" : true, + "SI-097" : true, "SI-098" : true, "SI-099" : true, "SI-100" : true, "SI-101" : true, + "SI-102" : true, "SI-103" : true, "SI-104" : true, "SI-105" : true, "SI-106" : true, + "SI-107" : true, "SI-108" : true, "SI-109" : true, "SI-110" : true, "SI-111" : true, + "SI-112" : true, "SI-113" : true, "SI-114" : true, "SI-115" : true, "SI-116" : true, + "SI-117" : true, "SI-118" : true, "SI-119" : true, "SI-120" : true, "SI-121" : true, + "SI-122" : true, "SI-123" : true, "SI-124" : true, "SI-125" : true, "SI-126" : true, + "SI-127" : true, "SI-128" : true, "SI-129" : true, "SI-130" : true, "SI-131" : true, + "SI-132" : true, "SI-133" : true, "SI-134" : true, "SI-135" : true, "SI-136" : true, + "SI-137" : true, "SI-138" : true, "SI-139" : true, "SI-140" : true, "SI-141" : true, + "SI-142" : true, "SI-143" : true, "SI-144" : true, "SI-146" : true, "SI-147" : true, + "SI-148" : true, "SI-149" : true, "SI-150" : true, "SI-151" : true, "SI-152" : true, + "SI-153" : true, "SI-154" : true, "SI-155" : true, "SI-156" : true, "SI-157" : true, + "SI-158" : true, "SI-159" : true, "SI-160" : true, "SI-161" : true, "SI-162" : true, + "SI-163" : true, "SI-164" : true, "SI-165" : true, "SI-166" : true, "SI-167" : true, + "SI-168" : true, "SI-169" : true, "SI-170" : true, "SI-171" : true, "SI-172" : true, + "SI-173" : true, "SI-174" : true, "SI-175" : true, "SI-176" : true, "SI-177" : true, + "SI-178" : true, "SI-179" : true, "SI-180" : true, "SI-181" : true, "SI-182" : true, + "SI-183" : true, "SI-184" : true, "SI-185" : true, "SI-186" : true, "SI-187" : true, + "SI-188" : true, "SI-189" : true, "SI-190" : true, "SI-191" : true, "SI-192" : true, + "SI-193" : true, "SI-194" : true, "SI-195" : true, "SI-196" : true, "SI-197" : true, + "SI-198" : true, "SI-199" : true, "SI-200" : true, "SI-201" : true, "SI-202" : true, + "SI-203" : true, "SI-204" : true, "SI-205" : true, "SI-206" : true, "SI-207" : true, + "SI-208" : true, "SI-209" : true, "SI-210" : true, "SI-211" : true, "SK-BC" : true, + "SK-BL" : true, "SK-KI" : true, "SK-NI" : true, "SK-PV" : true, "SK-TA" : true, + "SK-TC" : true, "SK-ZI" : true, "SL-E" : true, "SL-N" : true, "SL-S" : true, + "SL-W" : true, "SM-01" : true, "SM-02" : true, "SM-03" : true, "SM-04" : true, + "SM-05" : true, "SM-06" : true, "SM-07" : true, "SM-08" : true, "SM-09" : true, + "SN-DB" : true, "SN-DK" : true, "SN-FK" : true, "SN-KA" : true, "SN-KD" : true, + "SN-KE" : true, "SN-KL" : true, "SN-LG" : true, "SN-MT" : true, "SN-SE" : true, + "SN-SL" : true, "SN-TC" : true, "SN-TH" : true, "SN-ZG" : true, "SO-AW" : true, + "SO-BK" : true, "SO-BN" : true, "SO-BR" : true, "SO-BY" : true, "SO-GA" : true, + "SO-GE" : true, "SO-HI" : true, "SO-JD" : true, "SO-JH" : true, "SO-MU" : true, + "SO-NU" : true, "SO-SA" : true, "SO-SD" : true, "SO-SH" : true, "SO-SO" : true, + "SO-TO" : true, "SO-WO" : true, "SR-BR" : true, "SR-CM" : true, "SR-CR" : true, + "SR-MA" : true, "SR-NI" : true, "SR-PM" : true, "SR-PR" : true, "SR-SA" : true, + "SR-SI" : true, "SR-WA" : true, "SS-BN" : true, "SS-BW" : true, "SS-EC" : true, + "SS-EE8" : true, "SS-EW" : true, "SS-JG" : true, "SS-LK" : true, "SS-NU" : true, + "SS-UY" : true, "SS-WR" : true, "ST-P" : true, "ST-S" : true, "SV-AH" : true, + "SV-CA" : true, "SV-CH" : true, "SV-CU" : true, "SV-LI" : true, "SV-MO" : true, + "SV-PA" : true, "SV-SA" : true, "SV-SM" : true, "SV-SO" : true, "SV-SS" : true, + "SV-SV" : true, "SV-UN" : true, "SV-US" : true, "SY-DI" : true, "SY-DR" : true, + "SY-DY" : true, "SY-HA" : true, "SY-HI" : true, "SY-HL" : true, "SY-HM" : true, + "SY-ID" : true, "SY-LA" : true, "SY-QU" : true, "SY-RA" : true, "SY-RD" : true, + "SY-SU" : true, "SY-TA" : true, "SZ-HH" : true, "SZ-LU" : true, "SZ-MA" : true, + "SZ-SH" : true, "TD-BA" : true, "TD-BG" : true, "TD-BO" : true, "TD-CB" : true, + "TD-EN" : true, "TD-GR" : true, "TD-HL" : true, "TD-KA" : true, "TD-LC" : true, + "TD-LO" : true, "TD-LR" : true, "TD-MA" : true, "TD-MC" : true, "TD-ME" : true, + "TD-MO" : true, "TD-ND" : true, "TD-OD" : true, "TD-SA" : true, "TD-SI" : true, + "TD-TA" : true, "TD-TI" : true, "TD-WF" : true, "TG-C" : true, "TG-K" : true, + "TG-M" : true, "TG-P" : true, "TG-S" : true, "TH-10" : true, "TH-11" : true, + "TH-12" : true, "TH-13" : true, "TH-14" : true, "TH-15" : true, "TH-16" : true, + "TH-17" : true, "TH-18" : true, "TH-19" : true, "TH-20" : true, "TH-21" : true, + "TH-22" : true, "TH-23" : true, "TH-24" : true, "TH-25" : true, "TH-26" : true, + "TH-27" : true, "TH-30" : true, "TH-31" : true, "TH-32" : true, "TH-33" : true, + "TH-34" : true, "TH-35" : true, "TH-36" : true, "TH-37" : true, "TH-39" : true, + "TH-40" : true, "TH-41" : true, "TH-42" : true, "TH-43" : true, "TH-44" : true, + "TH-45" : true, "TH-46" : true, "TH-47" : true, "TH-48" : true, "TH-49" : true, + "TH-50" : true, "TH-51" : true, "TH-52" : true, "TH-53" : true, "TH-54" : true, + "TH-55" : true, "TH-56" : true, "TH-57" : true, "TH-58" : true, "TH-60" : true, + "TH-61" : true, "TH-62" : true, "TH-63" : true, "TH-64" : true, "TH-65" : true, + "TH-66" : true, "TH-67" : true, "TH-70" : true, "TH-71" : true, "TH-72" : true, + "TH-73" : true, "TH-74" : true, "TH-75" : true, "TH-76" : true, "TH-77" : true, + "TH-80" : true, "TH-81" : true, "TH-82" : true, "TH-83" : true, "TH-84" : true, + "TH-85" : true, "TH-86" : true, "TH-90" : true, "TH-91" : true, "TH-92" : true, + "TH-93" : true, "TH-94" : true, "TH-95" : true, "TH-96" : true, "TH-S" : true, + "TJ-GB" : true, "TJ-KT" : true, "TJ-SU" : true, "TL-AL" : true, "TL-AN" : true, + "TL-BA" : true, "TL-BO" : true, "TL-CO" : true, "TL-DI" : true, "TL-ER" : true, + "TL-LA" : true, "TL-LI" : true, "TL-MF" : true, "TL-MT" : true, "TL-OE" : true, + "TL-VI" : true, "TM-A" : true, "TM-B" : true, "TM-D" : true, "TM-L" : true, + "TM-M" : true, "TM-S" : true, "TN-11" : true, "TN-12" : true, "TN-13" : true, + "TN-14" : true, "TN-21" : true, "TN-22" : true, "TN-23" : true, "TN-31" : true, + "TN-32" : true, "TN-33" : true, "TN-34" : true, "TN-41" : true, "TN-42" : true, + "TN-43" : true, "TN-51" : true, "TN-52" : true, "TN-53" : true, "TN-61" : true, + "TN-71" : true, "TN-72" : true, "TN-73" : true, "TN-81" : true, "TN-82" : true, + "TN-83" : true, "TO-01" : true, "TO-02" : true, "TO-03" : true, "TO-04" : true, + "TO-05" : true, "TR-01" : true, "TR-02" : true, "TR-03" : true, "TR-04" : true, + "TR-05" : true, "TR-06" : true, "TR-07" : true, "TR-08" : true, "TR-09" : true, + "TR-10" : true, "TR-11" : true, "TR-12" : true, "TR-13" : true, "TR-14" : true, + "TR-15" : true, "TR-16" : true, "TR-17" : true, "TR-18" : true, "TR-19" : true, + "TR-20" : true, "TR-21" : true, "TR-22" : true, "TR-23" : true, "TR-24" : true, + "TR-25" : true, "TR-26" : true, "TR-27" : true, "TR-28" : true, "TR-29" : true, + "TR-30" : true, "TR-31" : true, "TR-32" : true, "TR-33" : true, "TR-34" : true, + "TR-35" : true, "TR-36" : true, "TR-37" : true, "TR-38" : true, "TR-39" : true, + "TR-40" : true, "TR-41" : true, "TR-42" : true, "TR-43" : true, "TR-44" : true, + "TR-45" : true, "TR-46" : true, "TR-47" : true, "TR-48" : true, "TR-49" : true, + "TR-50" : true, "TR-51" : true, "TR-52" : true, "TR-53" : true, "TR-54" : true, + "TR-55" : true, "TR-56" : true, "TR-57" : true, "TR-58" : true, "TR-59" : true, + "TR-60" : true, "TR-61" : true, "TR-62" : true, "TR-63" : true, "TR-64" : true, + "TR-65" : true, "TR-66" : true, "TR-67" : true, "TR-68" : true, "TR-69" : true, + "TR-70" : true, "TR-71" : true, "TR-72" : true, "TR-73" : true, "TR-74" : true, + "TR-75" : true, "TR-76" : true, "TR-77" : true, "TR-78" : true, "TR-79" : true, + "TR-80" : true, "TR-81" : true, "TT-ARI" : true, "TT-CHA" : true, "TT-CTT" : true, + "TT-DMN" : true, "TT-ETO" : true, "TT-PED" : true, "TT-POS" : true, "TT-PRT" : true, + "TT-PTF" : true, "TT-RCM" : true, "TT-SFO" : true, "TT-SGE" : true, "TT-SIP" : true, + "TT-SJL" : true, "TT-TUP" : true, "TT-WTO" : true, "TV-FUN" : true, "TV-NIT" : true, + "TV-NKF" : true, "TV-NKL" : true, "TV-NMA" : true, "TV-NMG" : true, "TV-NUI" : true, + "TV-VAI" : true, "TW-CHA" : true, "TW-CYI" : true, "TW-CYQ" : true, "TW-HSQ" : true, + "TW-HSZ" : true, "TW-HUA" : true, "TW-ILA" : true, "TW-KEE" : true, "TW-KHH" : true, + "TW-KHQ" : true, "TW-MIA" : true, "TW-NAN" : true, "TW-PEN" : true, "TW-PIF" : true, + "TW-TAO" : true, "TW-TNN" : true, "TW-TNQ" : true, "TW-TPE" : true, "TW-TPQ" : true, + "TW-TTT" : true, "TW-TXG" : true, "TW-TXQ" : true, "TW-YUN" : true, "TZ-01" : true, + "TZ-02" : true, "TZ-03" : true, "TZ-04" : true, "TZ-05" : true, "TZ-06" : true, + "TZ-07" : true, "TZ-08" : true, "TZ-09" : true, "TZ-10" : true, "TZ-11" : true, + "TZ-12" : true, "TZ-13" : true, "TZ-14" : true, "TZ-15" : true, "TZ-16" : true, + "TZ-17" : true, "TZ-18" : true, "TZ-19" : true, "TZ-20" : true, "TZ-21" : true, + "TZ-22" : true, "TZ-23" : true, "TZ-24" : true, "TZ-25" : true, "TZ-26" : true, + "UA-05" : true, "UA-07" : true, "UA-09" : true, "UA-12" : true, "UA-14" : true, + "UA-18" : true, "UA-21" : true, "UA-23" : true, "UA-26" : true, "UA-30" : true, + "UA-32" : true, "UA-35" : true, "UA-40" : true, "UA-43" : true, "UA-46" : true, + "UA-48" : true, "UA-51" : true, "UA-53" : true, "UA-56" : true, "UA-59" : true, + "UA-61" : true, "UA-63" : true, "UA-65" : true, "UA-68" : true, "UA-71" : true, + "UA-74" : true, "UA-77" : true, "UG-101" : true, "UG-102" : true, "UG-103" : true, + "UG-104" : true, "UG-105" : true, "UG-106" : true, "UG-107" : true, "UG-108" : true, + "UG-109" : true, "UG-110" : true, "UG-111" : true, "UG-112" : true, "UG-113" : true, + "UG-114" : true, "UG-115" : true, "UG-116" : true, "UG-201" : true, "UG-202" : true, + "UG-203" : true, "UG-204" : true, "UG-205" : true, "UG-206" : true, "UG-207" : true, + "UG-208" : true, "UG-209" : true, "UG-210" : true, "UG-211" : true, "UG-212" : true, + "UG-213" : true, "UG-214" : true, "UG-215" : true, "UG-216" : true, "UG-217" : true, + "UG-218" : true, "UG-219" : true, "UG-220" : true, "UG-221" : true, "UG-222" : true, + "UG-223" : true, "UG-224" : true, "UG-301" : true, "UG-302" : true, "UG-303" : true, + "UG-304" : true, "UG-305" : true, "UG-306" : true, "UG-307" : true, "UG-308" : true, + "UG-309" : true, "UG-310" : true, "UG-311" : true, "UG-312" : true, "UG-313" : true, + "UG-314" : true, "UG-315" : true, "UG-316" : true, "UG-317" : true, "UG-318" : true, + "UG-319" : true, "UG-320" : true, "UG-321" : true, "UG-401" : true, "UG-402" : true, + "UG-403" : true, "UG-404" : true, "UG-405" : true, "UG-406" : true, "UG-407" : true, + "UG-408" : true, "UG-409" : true, "UG-410" : true, "UG-411" : true, "UG-412" : true, + "UG-413" : true, "UG-414" : true, "UG-415" : true, "UG-416" : true, "UG-417" : true, + "UG-418" : true, "UG-419" : true, "UG-C" : true, "UG-E" : true, "UG-N" : true, + "UG-W" : true, "UM-67" : true, "UM-71" : true, "UM-76" : true, "UM-79" : true, + "UM-81" : true, "UM-84" : true, "UM-86" : true, "UM-89" : true, "UM-95" : true, + "US-AK" : true, "US-AL" : true, "US-AR" : true, "US-AS" : true, "US-AZ" : true, + "US-CA" : true, "US-CO" : true, "US-CT" : true, "US-DC" : true, "US-DE" : true, + "US-FL" : true, "US-GA" : true, "US-GU" : true, "US-HI" : true, "US-IA" : true, + "US-ID" : true, "US-IL" : true, "US-IN" : true, "US-KS" : true, "US-KY" : true, + "US-LA" : true, "US-MA" : true, "US-MD" : true, "US-ME" : true, "US-MI" : true, + "US-MN" : true, "US-MO" : true, "US-MP" : true, "US-MS" : true, "US-MT" : true, + "US-NC" : true, "US-ND" : true, "US-NE" : true, "US-NH" : true, "US-NJ" : true, + "US-NM" : true, "US-NV" : true, "US-NY" : true, "US-OH" : true, "US-OK" : true, + "US-OR" : true, "US-PA" : true, "US-PR" : true, "US-RI" : true, "US-SC" : true, + "US-SD" : true, "US-TN" : true, "US-TX" : true, "US-UM" : true, "US-UT" : true, + "US-VA" : true, "US-VI" : true, "US-VT" : true, "US-WA" : true, "US-WI" : true, + "US-WV" : true, "US-WY" : true, "UY-AR" : true, "UY-CA" : true, "UY-CL" : true, + "UY-CO" : true, "UY-DU" : true, "UY-FD" : true, "UY-FS" : true, "UY-LA" : true, + "UY-MA" : true, "UY-MO" : true, "UY-PA" : true, "UY-RN" : true, "UY-RO" : true, + "UY-RV" : true, "UY-SA" : true, "UY-SJ" : true, "UY-SO" : true, "UY-TA" : true, + "UY-TT" : true, "UZ-AN" : true, "UZ-BU" : true, "UZ-FA" : true, "UZ-JI" : true, + "UZ-NG" : true, "UZ-NW" : true, "UZ-QA" : true, "UZ-QR" : true, "UZ-SA" : true, + "UZ-SI" : true, "UZ-SU" : true, "UZ-TK" : true, "UZ-TO" : true, "UZ-XO" : true, + "VC-01" : true, "VC-02" : true, "VC-03" : true, "VC-04" : true, "VC-05" : true, + "VC-06" : true, "VE-A" : true, "VE-B" : true, "VE-C" : true, "VE-D" : true, + "VE-E" : true, "VE-F" : true, "VE-G" : true, "VE-H" : true, "VE-I" : true, + "VE-J" : true, "VE-K" : true, "VE-L" : true, "VE-M" : true, "VE-N" : true, + "VE-O" : true, "VE-P" : true, "VE-R" : true, "VE-S" : true, "VE-T" : true, + "VE-U" : true, "VE-V" : true, "VE-W" : true, "VE-X" : true, "VE-Y" : true, + "VE-Z" : true, "VN-01" : true, "VN-02" : true, "VN-03" : true, "VN-04" : true, + "VN-05" : true, "VN-06" : true, "VN-07" : true, "VN-09" : true, "VN-13" : true, + "VN-14" : true, "VN-15" : true, "VN-18" : true, "VN-20" : true, "VN-21" : true, + "VN-22" : true, "VN-23" : true, "VN-24" : true, "VN-25" : true, "VN-26" : true, + "VN-27" : true, "VN-28" : true, "VN-29" : true, "VN-30" : true, "VN-31" : true, + "VN-32" : true, "VN-33" : true, "VN-34" : true, "VN-35" : true, "VN-36" : true, + "VN-37" : true, "VN-39" : true, "VN-40" : true, "VN-41" : true, "VN-43" : true, + "VN-44" : true, "VN-45" : true, "VN-46" : true, "VN-47" : true, "VN-49" : true, + "VN-50" : true, "VN-51" : true, "VN-52" : true, "VN-53" : true, "VN-54" : true, + "VN-55" : true, "VN-56" : true, "VN-57" : true, "VN-58" : true, "VN-59" : true, + "VN-61" : true, "VN-63" : true, "VN-66" : true, "VN-67" : true, "VN-68" : true, + "VN-69" : true, "VN-70" : true, "VN-71" : true, "VN-72" : true, "VN-73" : true, + "VN-CT" : true, "VN-DN" : true, "VN-HN" : true, "VN-HP" : true, "VN-SG" : true, + "VU-MAP" : true, "VU-PAM" : true, "VU-SAM" : true, "VU-SEE" : true, "VU-TAE" : true, + "VU-TOB" : true, "WS-AA" : true, "WS-AL" : true, "WS-AT" : true, "WS-FA" : true, + "WS-GE" : true, "WS-GI" : true, "WS-PA" : true, "WS-SA" : true, "WS-TU" : true, + "WS-VF" : true, "WS-VS" : true, "YE-AB" : true, "YE-AD" : true, "YE-AM" : true, + "YE-BA" : true, "YE-DA" : true, "YE-DH" : true, "YE-HD" : true, "YE-HJ" : true, + "YE-IB" : true, "YE-JA" : true, "YE-LA" : true, "YE-MA" : true, "YE-MR" : true, + "YE-MU" : true, "YE-MW" : true, "YE-RA" : true, "YE-SD" : true, "YE-SH" : true, + "YE-SN" : true, "YE-TA" : true, "ZA-EC" : true, "ZA-FS" : true, "ZA-GP" : true, + "ZA-LP" : true, "ZA-MP" : true, "ZA-NC" : true, "ZA-NW" : true, "ZA-WC" : true, + "ZA-ZN" : true, "ZM-01" : true, "ZM-02" : true, "ZM-03" : true, "ZM-04" : true, + "ZM-05" : true, "ZM-06" : true, "ZM-07" : true, "ZM-08" : true, "ZM-09" : true, + "ZW-BU" : true, "ZW-HA" : true, "ZW-MA" : true, "ZW-MC" : true, "ZW-ME" : true, + "ZW-MI" : true, "ZW-MN" : true, "ZW-MS" : true, "ZW-MV" : true, "ZW-MW" : true, +} diff --git a/vendor/github.com/go-playground/validator/v10/currency_codes.go b/vendor/github.com/go-playground/validator/v10/currency_codes.go new file mode 100644 index 0000000000..a5cd9b18a0 --- /dev/null +++ b/vendor/github.com/go-playground/validator/v10/currency_codes.go @@ -0,0 +1,79 @@ +package validator + +var iso4217 = map[string]bool{ + "AFN": true, "EUR": true, "ALL": true, "DZD": true, "USD": true, + "AOA": true, "XCD": true, "ARS": true, "AMD": true, "AWG": true, + "AUD": true, "AZN": true, "BSD": true, "BHD": true, "BDT": true, + "BBD": true, "BYN": true, "BZD": true, "XOF": true, "BMD": true, + "INR": true, "BTN": true, "BOB": true, "BOV": true, "BAM": true, + "BWP": true, "NOK": true, "BRL": true, "BND": true, "BGN": true, + "BIF": true, "CVE": true, "KHR": true, "XAF": true, "CAD": true, + "KYD": true, "CLP": true, "CLF": true, "CNY": true, "COP": true, + "COU": true, "KMF": true, "CDF": true, "NZD": true, "CRC": true, + "HRK": true, "CUP": true, "CUC": true, "ANG": true, "CZK": true, + "DKK": true, "DJF": true, "DOP": true, "EGP": true, "SVC": true, + "ERN": true, "SZL": true, "ETB": true, "FKP": true, "FJD": true, + "XPF": true, "GMD": true, "GEL": true, "GHS": true, "GIP": true, + "GTQ": true, "GBP": true, "GNF": true, "GYD": true, "HTG": true, + "HNL": true, "HKD": true, "HUF": true, "ISK": true, "IDR": true, + "XDR": true, "IRR": true, "IQD": true, "ILS": true, "JMD": true, + "JPY": true, "JOD": true, "KZT": true, "KES": true, "KPW": true, + "KRW": true, "KWD": true, "KGS": true, "LAK": true, "LBP": true, + "LSL": true, "ZAR": true, "LRD": true, "LYD": true, "CHF": true, + "MOP": true, "MKD": true, "MGA": true, "MWK": true, "MYR": true, + "MVR": true, "MRU": true, "MUR": true, "XUA": true, "MXN": true, + "MXV": true, "MDL": true, "MNT": true, "MAD": true, "MZN": true, + "MMK": true, "NAD": true, "NPR": true, "NIO": true, "NGN": true, + "OMR": true, "PKR": true, "PAB": true, "PGK": true, "PYG": true, + "PEN": true, "PHP": true, "PLN": true, "QAR": true, "RON": true, + "RUB": true, "RWF": true, "SHP": true, "WST": true, "STN": true, + "SAR": true, "RSD": true, "SCR": true, "SLL": true, "SGD": true, + "XSU": true, "SBD": true, "SOS": true, "SSP": true, "LKR": true, + "SDG": true, "SRD": true, "SEK": true, "CHE": true, "CHW": true, + "SYP": true, "TWD": true, "TJS": true, "TZS": true, "THB": true, + "TOP": true, "TTD": true, "TND": true, "TRY": true, "TMT": true, + "UGX": true, "UAH": true, "AED": true, "USN": true, "UYU": true, + "UYI": true, "UYW": true, "UZS": true, "VUV": true, "VES": true, + "VND": true, "YER": true, "ZMW": true, "ZWL": true, "XBA": true, + "XBB": true, "XBC": true, "XBD": true, "XTS": true, "XXX": true, + "XAU": true, "XPD": true, "XPT": true, "XAG": true, +} + +var iso4217_numeric = map[int]bool{ + 8: true, 12: true, 32: true, 36: true, 44: true, + 48: true, 50: true, 51: true, 52: true, 60: true, + 64: true, 68: true, 72: true, 84: true, 90: true, + 96: true, 104: true, 108: true, 116: true, 124: true, + 132: true, 136: true, 144: true, 152: true, 156: true, + 170: true, 174: true, 188: true, 191: true, 192: true, + 203: true, 208: true, 214: true, 222: true, 230: true, + 232: true, 238: true, 242: true, 262: true, 270: true, + 292: true, 320: true, 324: true, 328: true, 332: true, + 340: true, 344: true, 348: true, 352: true, 356: true, + 360: true, 364: true, 368: true, 376: true, 388: true, + 392: true, 398: true, 400: true, 404: true, 408: true, + 410: true, 414: true, 417: true, 418: true, 422: true, + 426: true, 430: true, 434: true, 446: true, 454: true, + 458: true, 462: true, 480: true, 484: true, 496: true, + 498: true, 504: true, 512: true, 516: true, 524: true, + 532: true, 533: true, 548: true, 554: true, 558: true, + 566: true, 578: true, 586: true, 590: true, 598: true, + 600: true, 604: true, 608: true, 634: true, 643: true, + 646: true, 654: true, 682: true, 690: true, 694: true, + 702: true, 704: true, 706: true, 710: true, 728: true, + 748: true, 752: true, 756: true, 760: true, 764: true, + 776: true, 780: true, 784: true, 788: true, 800: true, + 807: true, 818: true, 826: true, 834: true, 840: true, + 858: true, 860: true, 882: true, 886: true, 901: true, + 927: true, 928: true, 929: true, 930: true, 931: true, + 932: true, 933: true, 934: true, 936: true, 938: true, + 940: true, 941: true, 943: true, 944: true, 946: true, + 947: true, 948: true, 949: true, 950: true, 951: true, + 952: true, 953: true, 955: true, 956: true, 957: true, + 958: true, 959: true, 960: true, 961: true, 962: true, + 963: true, 964: true, 965: true, 967: true, 968: true, + 969: true, 970: true, 971: true, 972: true, 973: true, + 975: true, 976: true, 977: true, 978: true, 979: true, + 980: true, 981: true, 984: true, 985: true, 986: true, + 990: true, 994: true, 997: true, 999: true, +} diff --git a/vendor/github.com/go-playground/validator/v10/doc.go b/vendor/github.com/go-playground/validator/v10/doc.go new file mode 100644 index 0000000000..7341c67d74 --- /dev/null +++ b/vendor/github.com/go-playground/validator/v10/doc.go @@ -0,0 +1,1401 @@ +/* +Package validator implements value validations for structs and individual fields +based on tags. + +It can also handle Cross-Field and Cross-Struct validation for nested structs +and has the ability to dive into arrays and maps of any type. + +see more examples https://github.com/go-playground/validator/tree/master/_examples + +Singleton + +Validator is designed to be thread-safe and used as a singleton instance. +It caches information about your struct and validations, +in essence only parsing your validation tags once per struct type. +Using multiple instances neglects the benefit of caching. +The not thread-safe functions are explicitly marked as such in the documentation. + +Validation Functions Return Type error + +Doing things this way is actually the way the standard library does, see the +file.Open method here: + + https://golang.org/pkg/os/#Open. + +The authors return type "error" to avoid the issue discussed in the following, +where err is always != nil: + + http://stackoverflow.com/a/29138676/3158232 + https://github.com/go-playground/validator/issues/134 + +Validator only InvalidValidationError for bad validation input, nil or +ValidationErrors as type error; so, in your code all you need to do is check +if the error returned is not nil, and if it's not check if error is +InvalidValidationError ( if necessary, most of the time it isn't ) type cast +it to type ValidationErrors like so err.(validator.ValidationErrors). + +Custom Validation Functions + +Custom Validation functions can be added. Example: + + // Structure + func customFunc(fl validator.FieldLevel) bool { + + if fl.Field().String() == "invalid" { + return false + } + + return true + } + + validate.RegisterValidation("custom tag name", customFunc) + // NOTES: using the same tag name as an existing function + // will overwrite the existing one + +Cross-Field Validation + +Cross-Field Validation can be done via the following tags: + - eqfield + - nefield + - gtfield + - gtefield + - ltfield + - ltefield + - eqcsfield + - necsfield + - gtcsfield + - gtecsfield + - ltcsfield + - ltecsfield + +If, however, some custom cross-field validation is required, it can be done +using a custom validation. + +Why not just have cross-fields validation tags (i.e. only eqcsfield and not +eqfield)? + +The reason is efficiency. If you want to check a field within the same struct +"eqfield" only has to find the field on the same struct (1 level). But, if we +used "eqcsfield" it could be multiple levels down. Example: + + type Inner struct { + StartDate time.Time + } + + type Outer struct { + InnerStructField *Inner + CreatedAt time.Time `validate:"ltecsfield=InnerStructField.StartDate"` + } + + now := time.Now() + + inner := &Inner{ + StartDate: now, + } + + outer := &Outer{ + InnerStructField: inner, + CreatedAt: now, + } + + errs := validate.Struct(outer) + + // NOTE: when calling validate.Struct(val) topStruct will be the top level struct passed + // into the function + // when calling validate.VarWithValue(val, field, tag) val will be + // whatever you pass, struct, field... + // when calling validate.Field(field, tag) val will be nil + +Multiple Validators + +Multiple validators on a field will process in the order defined. Example: + + type Test struct { + Field `validate:"max=10,min=1"` + } + + // max will be checked then min + +Bad Validator definitions are not handled by the library. Example: + + type Test struct { + Field `validate:"min=10,max=0"` + } + + // this definition of min max will never succeed + +Using Validator Tags + +Baked In Cross-Field validation only compares fields on the same struct. +If Cross-Field + Cross-Struct validation is needed you should implement your +own custom validator. + +Comma (",") is the default separator of validation tags. If you wish to +have a comma included within the parameter (i.e. excludesall=,) you will need to +use the UTF-8 hex representation 0x2C, which is replaced in the code as a comma, +so the above will become excludesall=0x2C. + + type Test struct { + Field `validate:"excludesall=,"` // BAD! Do not include a comma. + Field `validate:"excludesall=0x2C"` // GOOD! Use the UTF-8 hex representation. + } + +Pipe ("|") is the 'or' validation tags deparator. If you wish to +have a pipe included within the parameter i.e. excludesall=| you will need to +use the UTF-8 hex representation 0x7C, which is replaced in the code as a pipe, +so the above will become excludesall=0x7C + + type Test struct { + Field `validate:"excludesall=|"` // BAD! Do not include a a pipe! + Field `validate:"excludesall=0x7C"` // GOOD! Use the UTF-8 hex representation. + } + + +Baked In Validators and Tags + +Here is a list of the current built in validators: + + +Skip Field + +Tells the validation to skip this struct field; this is particularly +handy in ignoring embedded structs from being validated. (Usage: -) + Usage: - + + +Or Operator + +This is the 'or' operator allowing multiple validators to be used and +accepted. (Usage: rgb|rgba) <-- this would allow either rgb or rgba +colors to be accepted. This can also be combined with 'and' for example +( Usage: omitempty,rgb|rgba) + + Usage: | + +StructOnly + +When a field that is a nested struct is encountered, and contains this flag +any validation on the nested struct will be run, but none of the nested +struct fields will be validated. This is useful if inside of your program +you know the struct will be valid, but need to verify it has been assigned. +NOTE: only "required" and "omitempty" can be used on a struct itself. + + Usage: structonly + +NoStructLevel + +Same as structonly tag except that any struct level validations will not run. + + Usage: nostructlevel + +Omit Empty + +Allows conditional validation, for example if a field is not set with +a value (Determined by the "required" validator) then other validation +such as min or max won't run, but if a value is set validation will run. + + Usage: omitempty + +Dive + +This tells the validator to dive into a slice, array or map and validate that +level of the slice, array or map with the validation tags that follow. +Multidimensional nesting is also supported, each level you wish to dive will +require another dive tag. dive has some sub-tags, 'keys' & 'endkeys', please see +the Keys & EndKeys section just below. + + Usage: dive + +Example #1 + + [][]string with validation tag "gt=0,dive,len=1,dive,required" + // gt=0 will be applied to [] + // len=1 will be applied to []string + // required will be applied to string + +Example #2 + + [][]string with validation tag "gt=0,dive,dive,required" + // gt=0 will be applied to [] + // []string will be spared validation + // required will be applied to string + +Keys & EndKeys + +These are to be used together directly after the dive tag and tells the validator +that anything between 'keys' and 'endkeys' applies to the keys of a map and not the +values; think of it like the 'dive' tag, but for map keys instead of values. +Multidimensional nesting is also supported, each level you wish to validate will +require another 'keys' and 'endkeys' tag. These tags are only valid for maps. + + Usage: dive,keys,othertagvalidation(s),endkeys,valuevalidationtags + +Example #1 + + map[string]string with validation tag "gt=0,dive,keys,eg=1|eq=2,endkeys,required" + // gt=0 will be applied to the map itself + // eg=1|eq=2 will be applied to the map keys + // required will be applied to map values + +Example #2 + + map[[2]string]string with validation tag "gt=0,dive,keys,dive,eq=1|eq=2,endkeys,required" + // gt=0 will be applied to the map itself + // eg=1|eq=2 will be applied to each array element in the the map keys + // required will be applied to map values + +Required + +This validates that the value is not the data types default zero value. +For numbers ensures value is not zero. For strings ensures value is +not "". For slices, maps, pointers, interfaces, channels and functions +ensures the value is not nil. + + Usage: required + +Required If + +The field under validation must be present and not empty only if all +the other specified fields are equal to the value following the specified +field. For strings ensures value is not "". For slices, maps, pointers, +interfaces, channels and functions ensures the value is not nil. + + Usage: required_if + +Examples: + + // require the field if the Field1 is equal to the parameter given: + Usage: required_if=Field1 foobar + + // require the field if the Field1 and Field2 is equal to the value respectively: + Usage: required_if=Field1 foo Field2 bar + +Required Unless + +The field under validation must be present and not empty unless all +the other specified fields are equal to the value following the specified +field. For strings ensures value is not "". For slices, maps, pointers, +interfaces, channels and functions ensures the value is not nil. + + Usage: required_unless + +Examples: + + // require the field unless the Field1 is equal to the parameter given: + Usage: required_unless=Field1 foobar + + // require the field unless the Field1 and Field2 is equal to the value respectively: + Usage: required_unless=Field1 foo Field2 bar + +Required With + +The field under validation must be present and not empty only if any +of the other specified fields are present. For strings ensures value is +not "". For slices, maps, pointers, interfaces, channels and functions +ensures the value is not nil. + + Usage: required_with + +Examples: + + // require the field if the Field1 is present: + Usage: required_with=Field1 + + // require the field if the Field1 or Field2 is present: + Usage: required_with=Field1 Field2 + +Required With All + +The field under validation must be present and not empty only if all +of the other specified fields are present. For strings ensures value is +not "". For slices, maps, pointers, interfaces, channels and functions +ensures the value is not nil. + + Usage: required_with_all + +Example: + + // require the field if the Field1 and Field2 is present: + Usage: required_with_all=Field1 Field2 + +Required Without + +The field under validation must be present and not empty only when any +of the other specified fields are not present. For strings ensures value is +not "". For slices, maps, pointers, interfaces, channels and functions +ensures the value is not nil. + + Usage: required_without + +Examples: + + // require the field if the Field1 is not present: + Usage: required_without=Field1 + + // require the field if the Field1 or Field2 is not present: + Usage: required_without=Field1 Field2 + +Required Without All + +The field under validation must be present and not empty only when all +of the other specified fields are not present. For strings ensures value is +not "". For slices, maps, pointers, interfaces, channels and functions +ensures the value is not nil. + + Usage: required_without_all + +Example: + + // require the field if the Field1 and Field2 is not present: + Usage: required_without_all=Field1 Field2 + +Excluded If + +The field under validation must not be present or not empty only if all +the other specified fields are equal to the value following the specified +field. For strings ensures value is not "". For slices, maps, pointers, +interfaces, channels and functions ensures the value is not nil. + + Usage: excluded_if + +Examples: + + // exclude the field if the Field1 is equal to the parameter given: + Usage: excluded_if=Field1 foobar + + // exclude the field if the Field1 and Field2 is equal to the value respectively: + Usage: excluded_if=Field1 foo Field2 bar + +Excluded Unless + +The field under validation must not be present or empty unless all +the other specified fields are equal to the value following the specified +field. For strings ensures value is not "". For slices, maps, pointers, +interfaces, channels and functions ensures the value is not nil. + + Usage: excluded_unless + +Examples: + + // exclude the field unless the Field1 is equal to the parameter given: + Usage: excluded_unless=Field1 foobar + + // exclude the field unless the Field1 and Field2 is equal to the value respectively: + Usage: excluded_unless=Field1 foo Field2 bar + +Is Default + +This validates that the value is the default value and is almost the +opposite of required. + + Usage: isdefault + +Length + +For numbers, length will ensure that the value is +equal to the parameter given. For strings, it checks that +the string length is exactly that number of characters. For slices, +arrays, and maps, validates the number of items. + +Example #1 + + Usage: len=10 + +Example #2 (time.Duration) + +For time.Duration, len will ensure that the value is equal to the duration given +in the parameter. + + Usage: len=1h30m + +Maximum + +For numbers, max will ensure that the value is +less than or equal to the parameter given. For strings, it checks +that the string length is at most that number of characters. For +slices, arrays, and maps, validates the number of items. + +Example #1 + + Usage: max=10 + +Example #2 (time.Duration) + +For time.Duration, max will ensure that the value is less than or equal to the +duration given in the parameter. + + Usage: max=1h30m + +Minimum + +For numbers, min will ensure that the value is +greater or equal to the parameter given. For strings, it checks that +the string length is at least that number of characters. For slices, +arrays, and maps, validates the number of items. + +Example #1 + + Usage: min=10 + +Example #2 (time.Duration) + +For time.Duration, min will ensure that the value is greater than or equal to +the duration given in the parameter. + + Usage: min=1h30m + +Equals + +For strings & numbers, eq will ensure that the value is +equal to the parameter given. For slices, arrays, and maps, +validates the number of items. + +Example #1 + + Usage: eq=10 + +Example #2 (time.Duration) + +For time.Duration, eq will ensure that the value is equal to the duration given +in the parameter. + + Usage: eq=1h30m + +Not Equal + +For strings & numbers, ne will ensure that the value is not +equal to the parameter given. For slices, arrays, and maps, +validates the number of items. + +Example #1 + + Usage: ne=10 + +Example #2 (time.Duration) + +For time.Duration, ne will ensure that the value is not equal to the duration +given in the parameter. + + Usage: ne=1h30m + +One Of + +For strings, ints, and uints, oneof will ensure that the value +is one of the values in the parameter. The parameter should be +a list of values separated by whitespace. Values may be +strings or numbers. To match strings with spaces in them, include +the target string between single quotes. + + Usage: oneof=red green + oneof='red green' 'blue yellow' + oneof=5 7 9 + +Greater Than + +For numbers, this will ensure that the value is greater than the +parameter given. For strings, it checks that the string length +is greater than that number of characters. For slices, arrays +and maps it validates the number of items. + +Example #1 + + Usage: gt=10 + +Example #2 (time.Time) + +For time.Time ensures the time value is greater than time.Now.UTC(). + + Usage: gt + +Example #3 (time.Duration) + +For time.Duration, gt will ensure that the value is greater than the duration +given in the parameter. + + Usage: gt=1h30m + +Greater Than or Equal + +Same as 'min' above. Kept both to make terminology with 'len' easier. + +Example #1 + + Usage: gte=10 + +Example #2 (time.Time) + +For time.Time ensures the time value is greater than or equal to time.Now.UTC(). + + Usage: gte + +Example #3 (time.Duration) + +For time.Duration, gte will ensure that the value is greater than or equal to +the duration given in the parameter. + + Usage: gte=1h30m + +Less Than + +For numbers, this will ensure that the value is less than the parameter given. +For strings, it checks that the string length is less than that number of +characters. For slices, arrays, and maps it validates the number of items. + +Example #1 + + Usage: lt=10 + +Example #2 (time.Time) + +For time.Time ensures the time value is less than time.Now.UTC(). + + Usage: lt + +Example #3 (time.Duration) + +For time.Duration, lt will ensure that the value is less than the duration given +in the parameter. + + Usage: lt=1h30m + +Less Than or Equal + +Same as 'max' above. Kept both to make terminology with 'len' easier. + +Example #1 + + Usage: lte=10 + +Example #2 (time.Time) + +For time.Time ensures the time value is less than or equal to time.Now.UTC(). + + Usage: lte + +Example #3 (time.Duration) + +For time.Duration, lte will ensure that the value is less than or equal to the +duration given in the parameter. + + Usage: lte=1h30m + +Field Equals Another Field + +This will validate the field value against another fields value either within +a struct or passed in field. + +Example #1: + + // Validation on Password field using: + Usage: eqfield=ConfirmPassword + +Example #2: + + // Validating by field: + validate.VarWithValue(password, confirmpassword, "eqfield") + +Field Equals Another Field (relative) + +This does the same as eqfield except that it validates the field provided relative +to the top level struct. + + Usage: eqcsfield=InnerStructField.Field) + +Field Does Not Equal Another Field + +This will validate the field value against another fields value either within +a struct or passed in field. + +Examples: + + // Confirm two colors are not the same: + // + // Validation on Color field: + Usage: nefield=Color2 + + // Validating by field: + validate.VarWithValue(color1, color2, "nefield") + +Field Does Not Equal Another Field (relative) + +This does the same as nefield except that it validates the field provided +relative to the top level struct. + + Usage: necsfield=InnerStructField.Field + +Field Greater Than Another Field + +Only valid for Numbers, time.Duration and time.Time types, this will validate +the field value against another fields value either within a struct or passed in +field. usage examples are for validation of a Start and End date: + +Example #1: + + // Validation on End field using: + validate.Struct Usage(gtfield=Start) + +Example #2: + + // Validating by field: + validate.VarWithValue(start, end, "gtfield") + +Field Greater Than Another Relative Field + +This does the same as gtfield except that it validates the field provided +relative to the top level struct. + + Usage: gtcsfield=InnerStructField.Field + +Field Greater Than or Equal To Another Field + +Only valid for Numbers, time.Duration and time.Time types, this will validate +the field value against another fields value either within a struct or passed in +field. usage examples are for validation of a Start and End date: + +Example #1: + + // Validation on End field using: + validate.Struct Usage(gtefield=Start) + +Example #2: + + // Validating by field: + validate.VarWithValue(start, end, "gtefield") + +Field Greater Than or Equal To Another Relative Field + +This does the same as gtefield except that it validates the field provided relative +to the top level struct. + + Usage: gtecsfield=InnerStructField.Field + +Less Than Another Field + +Only valid for Numbers, time.Duration and time.Time types, this will validate +the field value against another fields value either within a struct or passed in +field. usage examples are for validation of a Start and End date: + +Example #1: + + // Validation on End field using: + validate.Struct Usage(ltfield=Start) + +Example #2: + + // Validating by field: + validate.VarWithValue(start, end, "ltfield") + +Less Than Another Relative Field + +This does the same as ltfield except that it validates the field provided relative +to the top level struct. + + Usage: ltcsfield=InnerStructField.Field + +Less Than or Equal To Another Field + +Only valid for Numbers, time.Duration and time.Time types, this will validate +the field value against another fields value either within a struct or passed in +field. usage examples are for validation of a Start and End date: + +Example #1: + + // Validation on End field using: + validate.Struct Usage(ltefield=Start) + +Example #2: + + // Validating by field: + validate.VarWithValue(start, end, "ltefield") + +Less Than or Equal To Another Relative Field + +This does the same as ltefield except that it validates the field provided relative +to the top level struct. + + Usage: ltecsfield=InnerStructField.Field + +Field Contains Another Field + +This does the same as contains except for struct fields. It should only be used +with string types. See the behavior of reflect.Value.String() for behavior on +other types. + + Usage: containsfield=InnerStructField.Field + +Field Excludes Another Field + +This does the same as excludes except for struct fields. It should only be used +with string types. See the behavior of reflect.Value.String() for behavior on +other types. + + Usage: excludesfield=InnerStructField.Field + +Unique + +For arrays & slices, unique will ensure that there are no duplicates. +For maps, unique will ensure that there are no duplicate values. +For slices of struct, unique will ensure that there are no duplicate values +in a field of the struct specified via a parameter. + + // For arrays, slices, and maps: + Usage: unique + + // For slices of struct: + Usage: unique=field + +Alpha Only + +This validates that a string value contains ASCII alpha characters only + + Usage: alpha + +Alphanumeric + +This validates that a string value contains ASCII alphanumeric characters only + + Usage: alphanum + +Alpha Unicode + +This validates that a string value contains unicode alpha characters only + + Usage: alphaunicode + +Alphanumeric Unicode + +This validates that a string value contains unicode alphanumeric characters only + + Usage: alphanumunicode + +Boolean + +This validates that a string value can successfully be parsed into a boolean with strconv.ParseBool + + Usage: boolean + +Number + +This validates that a string value contains number values only. +For integers or float it returns true. + + Usage: number + +Numeric + +This validates that a string value contains a basic numeric value. +basic excludes exponents etc... +for integers or float it returns true. + + Usage: numeric + +Hexadecimal String + +This validates that a string value contains a valid hexadecimal. + + Usage: hexadecimal + +Hexcolor String + +This validates that a string value contains a valid hex color including +hashtag (#) + + Usage: hexcolor + +Lowercase String + +This validates that a string value contains only lowercase characters. An empty string is not a valid lowercase string. + + Usage: lowercase + +Uppercase String + +This validates that a string value contains only uppercase characters. An empty string is not a valid uppercase string. + + Usage: uppercase + +RGB String + +This validates that a string value contains a valid rgb color + + Usage: rgb + +RGBA String + +This validates that a string value contains a valid rgba color + + Usage: rgba + +HSL String + +This validates that a string value contains a valid hsl color + + Usage: hsl + +HSLA String + +This validates that a string value contains a valid hsla color + + Usage: hsla + +E.164 Phone Number String + +This validates that a string value contains a valid E.164 Phone number +https://en.wikipedia.org/wiki/E.164 (ex. +1123456789) + + Usage: e164 + +E-mail String + +This validates that a string value contains a valid email +This may not conform to all possibilities of any rfc standard, but neither +does any email provider accept all possibilities. + + Usage: email + +JSON String + +This validates that a string value is valid JSON + + Usage: json + +JWT String + +This validates that a string value is a valid JWT + + Usage: jwt + +File path + +This validates that a string value contains a valid file path and that +the file exists on the machine. +This is done using os.Stat, which is a platform independent function. + + Usage: file + +URL String + +This validates that a string value contains a valid url +This will accept any url the golang request uri accepts but must contain +a schema for example http:// or rtmp:// + + Usage: url + +URI String + +This validates that a string value contains a valid uri +This will accept any uri the golang request uri accepts + + Usage: uri + +Urn RFC 2141 String + +This validataes that a string value contains a valid URN +according to the RFC 2141 spec. + + Usage: urn_rfc2141 + +Base64 String + +This validates that a string value contains a valid base64 value. +Although an empty string is valid base64 this will report an empty string +as an error, if you wish to accept an empty string as valid you can use +this with the omitempty tag. + + Usage: base64 + +Base64URL String + +This validates that a string value contains a valid base64 URL safe value +according the the RFC4648 spec. +Although an empty string is a valid base64 URL safe value, this will report +an empty string as an error, if you wish to accept an empty string as valid +you can use this with the omitempty tag. + + Usage: base64url + +Bitcoin Address + +This validates that a string value contains a valid bitcoin address. +The format of the string is checked to ensure it matches one of the three formats +P2PKH, P2SH and performs checksum validation. + + Usage: btc_addr + +Bitcoin Bech32 Address (segwit) + +This validates that a string value contains a valid bitcoin Bech32 address as defined +by bip-0173 (https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki) +Special thanks to Pieter Wuille for providng reference implementations. + + Usage: btc_addr_bech32 + +Ethereum Address + +This validates that a string value contains a valid ethereum address. +The format of the string is checked to ensure it matches the standard Ethereum address format. + + Usage: eth_addr + +Contains + +This validates that a string value contains the substring value. + + Usage: contains=@ + +Contains Any + +This validates that a string value contains any Unicode code points +in the substring value. + + Usage: containsany=!@#? + +Contains Rune + +This validates that a string value contains the supplied rune value. + + Usage: containsrune=@ + +Excludes + +This validates that a string value does not contain the substring value. + + Usage: excludes=@ + +Excludes All + +This validates that a string value does not contain any Unicode code +points in the substring value. + + Usage: excludesall=!@#? + +Excludes Rune + +This validates that a string value does not contain the supplied rune value. + + Usage: excludesrune=@ + +Starts With + +This validates that a string value starts with the supplied string value + + Usage: startswith=hello + +Ends With + +This validates that a string value ends with the supplied string value + + Usage: endswith=goodbye + +Does Not Start With + +This validates that a string value does not start with the supplied string value + + Usage: startsnotwith=hello + +Does Not End With + +This validates that a string value does not end with the supplied string value + + Usage: endsnotwith=goodbye + +International Standard Book Number + +This validates that a string value contains a valid isbn10 or isbn13 value. + + Usage: isbn + +International Standard Book Number 10 + +This validates that a string value contains a valid isbn10 value. + + Usage: isbn10 + +International Standard Book Number 13 + +This validates that a string value contains a valid isbn13 value. + + Usage: isbn13 + +Universally Unique Identifier UUID + +This validates that a string value contains a valid UUID. Uppercase UUID values will not pass - use `uuid_rfc4122` instead. + + Usage: uuid + +Universally Unique Identifier UUID v3 + +This validates that a string value contains a valid version 3 UUID. Uppercase UUID values will not pass - use `uuid3_rfc4122` instead. + + Usage: uuid3 + +Universally Unique Identifier UUID v4 + +This validates that a string value contains a valid version 4 UUID. Uppercase UUID values will not pass - use `uuid4_rfc4122` instead. + + Usage: uuid4 + +Universally Unique Identifier UUID v5 + +This validates that a string value contains a valid version 5 UUID. Uppercase UUID values will not pass - use `uuid5_rfc4122` instead. + + Usage: uuid5 + +Universally Unique Lexicographically Sortable Identifier ULID + +This validates that a string value contains a valid ULID value. + + Usage: ulid + +ASCII + +This validates that a string value contains only ASCII characters. +NOTE: if the string is blank, this validates as true. + + Usage: ascii + +Printable ASCII + +This validates that a string value contains only printable ASCII characters. +NOTE: if the string is blank, this validates as true. + + Usage: printascii + +Multi-Byte Characters + +This validates that a string value contains one or more multibyte characters. +NOTE: if the string is blank, this validates as true. + + Usage: multibyte + +Data URL + +This validates that a string value contains a valid DataURI. +NOTE: this will also validate that the data portion is valid base64 + + Usage: datauri + +Latitude + +This validates that a string value contains a valid latitude. + + Usage: latitude + +Longitude + +This validates that a string value contains a valid longitude. + + Usage: longitude + +Social Security Number SSN + +This validates that a string value contains a valid U.S. Social Security Number. + + Usage: ssn + +Internet Protocol Address IP + +This validates that a string value contains a valid IP Address. + + Usage: ip + +Internet Protocol Address IPv4 + +This validates that a string value contains a valid v4 IP Address. + + Usage: ipv4 + +Internet Protocol Address IPv6 + +This validates that a string value contains a valid v6 IP Address. + + Usage: ipv6 + +Classless Inter-Domain Routing CIDR + +This validates that a string value contains a valid CIDR Address. + + Usage: cidr + +Classless Inter-Domain Routing CIDRv4 + +This validates that a string value contains a valid v4 CIDR Address. + + Usage: cidrv4 + +Classless Inter-Domain Routing CIDRv6 + +This validates that a string value contains a valid v6 CIDR Address. + + Usage: cidrv6 + +Transmission Control Protocol Address TCP + +This validates that a string value contains a valid resolvable TCP Address. + + Usage: tcp_addr + +Transmission Control Protocol Address TCPv4 + +This validates that a string value contains a valid resolvable v4 TCP Address. + + Usage: tcp4_addr + +Transmission Control Protocol Address TCPv6 + +This validates that a string value contains a valid resolvable v6 TCP Address. + + Usage: tcp6_addr + +User Datagram Protocol Address UDP + +This validates that a string value contains a valid resolvable UDP Address. + + Usage: udp_addr + +User Datagram Protocol Address UDPv4 + +This validates that a string value contains a valid resolvable v4 UDP Address. + + Usage: udp4_addr + +User Datagram Protocol Address UDPv6 + +This validates that a string value contains a valid resolvable v6 UDP Address. + + Usage: udp6_addr + +Internet Protocol Address IP + +This validates that a string value contains a valid resolvable IP Address. + + Usage: ip_addr + +Internet Protocol Address IPv4 + +This validates that a string value contains a valid resolvable v4 IP Address. + + Usage: ip4_addr + +Internet Protocol Address IPv6 + +This validates that a string value contains a valid resolvable v6 IP Address. + + Usage: ip6_addr + +Unix domain socket end point Address + +This validates that a string value contains a valid Unix Address. + + Usage: unix_addr + +Media Access Control Address MAC + +This validates that a string value contains a valid MAC Address. + + Usage: mac + +Note: See Go's ParseMAC for accepted formats and types: + + http://golang.org/src/net/mac.go?s=866:918#L29 + +Hostname RFC 952 + +This validates that a string value is a valid Hostname according to RFC 952 https://tools.ietf.org/html/rfc952 + + Usage: hostname + +Hostname RFC 1123 + +This validates that a string value is a valid Hostname according to RFC 1123 https://tools.ietf.org/html/rfc1123 + + Usage: hostname_rfc1123 or if you want to continue to use 'hostname' in your tags, create an alias. + +Full Qualified Domain Name (FQDN) + +This validates that a string value contains a valid FQDN. + + Usage: fqdn + +HTML Tags + +This validates that a string value appears to be an HTML element tag +including those described at https://developer.mozilla.org/en-US/docs/Web/HTML/Element + + Usage: html + +HTML Encoded + +This validates that a string value is a proper character reference in decimal +or hexadecimal format + + Usage: html_encoded + +URL Encoded + +This validates that a string value is percent-encoded (URL encoded) according +to https://tools.ietf.org/html/rfc3986#section-2.1 + + Usage: url_encoded + +Directory + +This validates that a string value contains a valid directory and that +it exists on the machine. +This is done using os.Stat, which is a platform independent function. + + Usage: dir + +HostPort + +This validates that a string value contains a valid DNS hostname and port that +can be used to valiate fields typically passed to sockets and connections. + + Usage: hostname_port + +Datetime + +This validates that a string value is a valid datetime based on the supplied datetime format. +Supplied format must match the official Go time format layout as documented in https://golang.org/pkg/time/ + + Usage: datetime=2006-01-02 + +Iso3166-1 alpha-2 + +This validates that a string value is a valid country code based on iso3166-1 alpha-2 standard. +see: https://www.iso.org/iso-3166-country-codes.html + + Usage: iso3166_1_alpha2 + +Iso3166-1 alpha-3 + +This validates that a string value is a valid country code based on iso3166-1 alpha-3 standard. +see: https://www.iso.org/iso-3166-country-codes.html + + Usage: iso3166_1_alpha3 + +Iso3166-1 alpha-numeric + +This validates that a string value is a valid country code based on iso3166-1 alpha-numeric standard. +see: https://www.iso.org/iso-3166-country-codes.html + + Usage: iso3166_1_alpha3 + +BCP 47 Language Tag + +This validates that a string value is a valid BCP 47 language tag, as parsed by language.Parse. +More information on https://pkg.go.dev/golang.org/x/text/language + + Usage: bcp47_language_tag + +BIC (SWIFT code) + +This validates that a string value is a valid Business Identifier Code (SWIFT code), defined in ISO 9362. +More information on https://www.iso.org/standard/60390.html + + Usage: bic + +RFC 1035 label + +This validates that a string value is a valid dns RFC 1035 label, defined in RFC 1035. +More information on https://datatracker.ietf.org/doc/html/rfc1035 + + Usage: dns_rfc1035_label + +TimeZone + +This validates that a string value is a valid time zone based on the time zone database present on the system. +Although empty value and Local value are allowed by time.LoadLocation golang function, they are not allowed by this validator. +More information on https://golang.org/pkg/time/#LoadLocation + + Usage: timezone + +Semantic Version + +This validates that a string value is a valid semver version, defined in Semantic Versioning 2.0.0. +More information on https://semver.org/ + + Usage: semver + +Credit Card + +This validates that a string value contains a valid credit card number using Luhn algoritm. + + Usage: credit_card + +Alias Validators and Tags + +NOTE: When returning an error, the tag returned in "FieldError" will be +the alias tag unless the dive tag is part of the alias. Everything after the +dive tag is not reported as the alias tag. Also, the "ActualTag" in the before +case will be the actual tag within the alias that failed. + +Here is a list of the current built in alias tags: + + "iscolor" + alias is "hexcolor|rgb|rgba|hsl|hsla" (Usage: iscolor) + "country_code" + alias is "iso3166_1_alpha2|iso3166_1_alpha3|iso3166_1_alpha_numeric" (Usage: country_code) + +Validator notes: + + regex + a regex validator won't be added because commas and = signs can be part + of a regex which conflict with the validation definitions. Although + workarounds can be made, they take away from using pure regex's. + Furthermore it's quick and dirty but the regex's become harder to + maintain and are not reusable, so it's as much a programming philosophy + as anything. + + In place of this new validator functions should be created; a regex can + be used within the validator function and even be precompiled for better + efficiency within regexes.go. + + And the best reason, you can submit a pull request and we can keep on + adding to the validation library of this package! + +Non standard validators + +A collection of validation rules that are frequently needed but are more +complex than the ones found in the baked in validators. +A non standard validator must be registered manually like you would +with your own custom validation functions. + +Example of registration and use: + + type Test struct { + TestField string `validate:"yourtag"` + } + + t := &Test{ + TestField: "Test" + } + + validate := validator.New() + validate.RegisterValidation("yourtag", validators.NotBlank) + +Here is a list of the current non standard validators: + + NotBlank + This validates that the value is not blank or with length zero. + For strings ensures they do not contain only spaces. For channels, maps, slices and arrays + ensures they don't have zero length. For others, a non empty value is required. + + Usage: notblank + +Panics + +This package panics when bad input is provided, this is by design, bad code like +that should not make it to production. + + type Test struct { + TestField string `validate:"nonexistantfunction=1"` + } + + t := &Test{ + TestField: "Test" + } + + validate.Struct(t) // this will panic +*/ +package validator diff --git a/vendor/github.com/go-playground/validator/v10/errors.go b/vendor/github.com/go-playground/validator/v10/errors.go new file mode 100644 index 0000000000..9a1b1abe93 --- /dev/null +++ b/vendor/github.com/go-playground/validator/v10/errors.go @@ -0,0 +1,275 @@ +package validator + +import ( + "bytes" + "fmt" + "reflect" + "strings" + + ut "github.com/go-playground/universal-translator" +) + +const ( + fieldErrMsg = "Key: '%s' Error:Field validation for '%s' failed on the '%s' tag" +) + +// ValidationErrorsTranslations is the translation return type +type ValidationErrorsTranslations map[string]string + +// InvalidValidationError describes an invalid argument passed to +// `Struct`, `StructExcept`, StructPartial` or `Field` +type InvalidValidationError struct { + Type reflect.Type +} + +// Error returns InvalidValidationError message +func (e *InvalidValidationError) Error() string { + + if e.Type == nil { + return "validator: (nil)" + } + + return "validator: (nil " + e.Type.String() + ")" +} + +// ValidationErrors is an array of FieldError's +// for use in custom error messages post validation. +type ValidationErrors []FieldError + +// Error is intended for use in development + debugging and not intended to be a production error message. +// It allows ValidationErrors to subscribe to the Error interface. +// All information to create an error message specific to your application is contained within +// the FieldError found within the ValidationErrors array +func (ve ValidationErrors) Error() string { + + buff := bytes.NewBufferString("") + + var fe *fieldError + + for i := 0; i < len(ve); i++ { + + fe = ve[i].(*fieldError) + buff.WriteString(fe.Error()) + buff.WriteString("\n") + } + + return strings.TrimSpace(buff.String()) +} + +// Translate translates all of the ValidationErrors +func (ve ValidationErrors) Translate(ut ut.Translator) ValidationErrorsTranslations { + + trans := make(ValidationErrorsTranslations) + + var fe *fieldError + + for i := 0; i < len(ve); i++ { + fe = ve[i].(*fieldError) + + // // in case an Anonymous struct was used, ensure that the key + // // would be 'Username' instead of ".Username" + // if len(fe.ns) > 0 && fe.ns[:1] == "." { + // trans[fe.ns[1:]] = fe.Translate(ut) + // continue + // } + + trans[fe.ns] = fe.Translate(ut) + } + + return trans +} + +// FieldError contains all functions to get error details +type FieldError interface { + + // Tag returns the validation tag that failed. if the + // validation was an alias, this will return the + // alias name and not the underlying tag that failed. + // + // eg. alias "iscolor": "hexcolor|rgb|rgba|hsl|hsla" + // will return "iscolor" + Tag() string + + // ActualTag returns the validation tag that failed, even if an + // alias the actual tag within the alias will be returned. + // If an 'or' validation fails the entire or will be returned. + // + // eg. alias "iscolor": "hexcolor|rgb|rgba|hsl|hsla" + // will return "hexcolor|rgb|rgba|hsl|hsla" + ActualTag() string + + // Namespace returns the namespace for the field error, with the tag + // name taking precedence over the field's actual name. + // + // eg. JSON name "User.fname" + // + // See StructNamespace() for a version that returns actual names. + // + // NOTE: this field can be blank when validating a single primitive field + // using validate.Field(...) as there is no way to extract it's name + Namespace() string + + // StructNamespace returns the namespace for the field error, with the field's + // actual name. + // + // eq. "User.FirstName" see Namespace for comparison + // + // NOTE: this field can be blank when validating a single primitive field + // using validate.Field(...) as there is no way to extract its name + StructNamespace() string + + // Field returns the fields name with the tag name taking precedence over the + // field's actual name. + // + // eq. JSON name "fname" + // see StructField for comparison + Field() string + + // StructField returns the field's actual name from the struct, when able to determine. + // + // eq. "FirstName" + // see Field for comparison + StructField() string + + // Value returns the actual field's value in case needed for creating the error + // message + Value() interface{} + + // Param returns the param value, in string form for comparison; this will also + // help with generating an error message + Param() string + + // Kind returns the Field's reflect Kind + // + // eg. time.Time's kind is a struct + Kind() reflect.Kind + + // Type returns the Field's reflect Type + // + // eg. time.Time's type is time.Time + Type() reflect.Type + + // Translate returns the FieldError's translated error + // from the provided 'ut.Translator' and registered 'TranslationFunc' + // + // NOTE: if no registered translator can be found it returns the same as + // calling fe.Error() + Translate(ut ut.Translator) string + + // Error returns the FieldError's message + Error() string +} + +// compile time interface checks +var _ FieldError = new(fieldError) +var _ error = new(fieldError) + +// fieldError contains a single field's validation error along +// with other properties that may be needed for error message creation +// it complies with the FieldError interface +type fieldError struct { + v *Validate + tag string + actualTag string + ns string + structNs string + fieldLen uint8 + structfieldLen uint8 + value interface{} + param string + kind reflect.Kind + typ reflect.Type +} + +// Tag returns the validation tag that failed. +func (fe *fieldError) Tag() string { + return fe.tag +} + +// ActualTag returns the validation tag that failed, even if an +// alias the actual tag within the alias will be returned. +func (fe *fieldError) ActualTag() string { + return fe.actualTag +} + +// Namespace returns the namespace for the field error, with the tag +// name taking precedence over the field's actual name. +func (fe *fieldError) Namespace() string { + return fe.ns +} + +// StructNamespace returns the namespace for the field error, with the field's +// actual name. +func (fe *fieldError) StructNamespace() string { + return fe.structNs +} + +// Field returns the field's name with the tag name taking precedence over the +// field's actual name. +func (fe *fieldError) Field() string { + + return fe.ns[len(fe.ns)-int(fe.fieldLen):] + // // return fe.field + // fld := fe.ns[len(fe.ns)-int(fe.fieldLen):] + + // log.Println("FLD:", fld) + + // if len(fld) > 0 && fld[:1] == "." { + // return fld[1:] + // } + + // return fld +} + +// StructField returns the field's actual name from the struct, when able to determine. +func (fe *fieldError) StructField() string { + // return fe.structField + return fe.structNs[len(fe.structNs)-int(fe.structfieldLen):] +} + +// Value returns the actual field's value in case needed for creating the error +// message +func (fe *fieldError) Value() interface{} { + return fe.value +} + +// Param returns the param value, in string form for comparison; this will +// also help with generating an error message +func (fe *fieldError) Param() string { + return fe.param +} + +// Kind returns the Field's reflect Kind +func (fe *fieldError) Kind() reflect.Kind { + return fe.kind +} + +// Type returns the Field's reflect Type +func (fe *fieldError) Type() reflect.Type { + return fe.typ +} + +// Error returns the fieldError's error message +func (fe *fieldError) Error() string { + return fmt.Sprintf(fieldErrMsg, fe.ns, fe.Field(), fe.tag) +} + +// Translate returns the FieldError's translated error +// from the provided 'ut.Translator' and registered 'TranslationFunc' +// +// NOTE: if no registered translation can be found, it returns the original +// untranslated error message. +func (fe *fieldError) Translate(ut ut.Translator) string { + + m, ok := fe.v.transTagFunc[ut] + if !ok { + return fe.Error() + } + + fn, ok := m[fe.tag] + if !ok { + return fe.Error() + } + + return fn(ut, fe) +} diff --git a/vendor/github.com/go-playground/validator/v10/field_level.go b/vendor/github.com/go-playground/validator/v10/field_level.go new file mode 100644 index 0000000000..ef35826ee6 --- /dev/null +++ b/vendor/github.com/go-playground/validator/v10/field_level.go @@ -0,0 +1,120 @@ +package validator + +import "reflect" + +// FieldLevel contains all the information and helper functions +// to validate a field +type FieldLevel interface { + + // Top returns the top level struct, if any + Top() reflect.Value + + // Parent returns the current fields parent struct, if any or + // the comparison value if called 'VarWithValue' + Parent() reflect.Value + + // Field returns current field for validation + Field() reflect.Value + + // FieldName returns the field's name with the tag + // name taking precedence over the fields actual name. + FieldName() string + + // StructFieldName returns the struct field's name + StructFieldName() string + + // Param returns param for validation against current field + Param() string + + // GetTag returns the current validations tag name + GetTag() string + + // ExtractType gets the actual underlying type of field value. + // It will dive into pointers, customTypes and return you the + // underlying value and it's kind. + ExtractType(field reflect.Value) (value reflect.Value, kind reflect.Kind, nullable bool) + + // GetStructFieldOK traverses the parent struct to retrieve a specific field denoted by the provided namespace + // in the param and returns the field, field kind and whether is was successful in retrieving + // the field at all. + // + // NOTE: when not successful ok will be false, this can happen when a nested struct is nil and so the field + // could not be retrieved because it didn't exist. + // + // Deprecated: Use GetStructFieldOK2() instead which also return if the value is nullable. + GetStructFieldOK() (reflect.Value, reflect.Kind, bool) + + // GetStructFieldOKAdvanced is the same as GetStructFieldOK except that it accepts the parent struct to start looking for + // the field and namespace allowing more extensibility for validators. + // + // Deprecated: Use GetStructFieldOKAdvanced2() instead which also return if the value is nullable. + GetStructFieldOKAdvanced(val reflect.Value, namespace string) (reflect.Value, reflect.Kind, bool) + + // GetStructFieldOK2 traverses the parent struct to retrieve a specific field denoted by the provided namespace + // in the param and returns the field, field kind, if it's a nullable type and whether is was successful in retrieving + // the field at all. + // + // NOTE: when not successful ok will be false, this can happen when a nested struct is nil and so the field + // could not be retrieved because it didn't exist. + GetStructFieldOK2() (reflect.Value, reflect.Kind, bool, bool) + + // GetStructFieldOKAdvanced2 is the same as GetStructFieldOK except that it accepts the parent struct to start looking for + // the field and namespace allowing more extensibility for validators. + GetStructFieldOKAdvanced2(val reflect.Value, namespace string) (reflect.Value, reflect.Kind, bool, bool) +} + +var _ FieldLevel = new(validate) + +// Field returns current field for validation +func (v *validate) Field() reflect.Value { + return v.flField +} + +// FieldName returns the field's name with the tag +// name taking precedence over the fields actual name. +func (v *validate) FieldName() string { + return v.cf.altName +} + +// GetTag returns the current validations tag name +func (v *validate) GetTag() string { + return v.ct.tag +} + +// StructFieldName returns the struct field's name +func (v *validate) StructFieldName() string { + return v.cf.name +} + +// Param returns param for validation against current field +func (v *validate) Param() string { + return v.ct.param +} + +// GetStructFieldOK returns Param returns param for validation against current field +// +// Deprecated: Use GetStructFieldOK2() instead which also return if the value is nullable. +func (v *validate) GetStructFieldOK() (reflect.Value, reflect.Kind, bool) { + current, kind, _, found := v.getStructFieldOKInternal(v.slflParent, v.ct.param) + return current, kind, found +} + +// GetStructFieldOKAdvanced is the same as GetStructFieldOK except that it accepts the parent struct to start looking for +// the field and namespace allowing more extensibility for validators. +// +// Deprecated: Use GetStructFieldOKAdvanced2() instead which also return if the value is nullable. +func (v *validate) GetStructFieldOKAdvanced(val reflect.Value, namespace string) (reflect.Value, reflect.Kind, bool) { + current, kind, _, found := v.GetStructFieldOKAdvanced2(val, namespace) + return current, kind, found +} + +// GetStructFieldOK2 returns Param returns param for validation against current field +func (v *validate) GetStructFieldOK2() (reflect.Value, reflect.Kind, bool, bool) { + return v.getStructFieldOKInternal(v.slflParent, v.ct.param) +} + +// GetStructFieldOKAdvanced2 is the same as GetStructFieldOK except that it accepts the parent struct to start looking for +// the field and namespace allowing more extensibility for validators. +func (v *validate) GetStructFieldOKAdvanced2(val reflect.Value, namespace string) (reflect.Value, reflect.Kind, bool, bool) { + return v.getStructFieldOKInternal(val, namespace) +} diff --git a/vendor/github.com/go-playground/validator/v10/logo.png b/vendor/github.com/go-playground/validator/v10/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..355000f5247d50e979cf5db5de38188ef4649a34 GIT binary patch literal 13443 zcmbVz^LHiB^LK39wrv|5-`KWoTN~T9%?&s9Mte8f*xWeZ`~Lg^&kxU>)6-|>Om|IH zcUM=vsybFxSr!?A009gP3|U@IN*z>Z{#W2&KzAW<*L_e0I`lYd#@osT8GH952<>}$=#%H%txCM^!YLYIPG*~?*PoX}XfpXD#$r$vg% zUJ@M8Sa6}E0bs?J()q&Aj2!Xx^!*X7wf45!j09TZ!t8tmiZrhYa~rM!hkOgG3jNOL z$t%hsiEZp{`uZS=pUq3db%5@e>LpqUR%RzF4Fp&XYtszH3NMj(x&yBfN!B@dDe(i*$ zFaI9z`VK(*+SzZ3Km$V|gFS(NfPUS&ND}#zKM&MsZR;zy@SJwDwy5moK{eH84yz0`{Dhd+jynpps_Wzr*Rl)ctU%7jk!=>D(g}(sK zP}YV(B1|d_4NeR~4qlx?36qk5ng9u-wt+@fOTlvqhk>WQ%HxtjxBspSS(-6OpP;_x z73LX72W9oA=yUj&B*sjt0z}2U44ACNztdo!tbwR&pl8vCLjf!@HDwcP;p{h$JYsrk zE3Pp7L^A>!xwNPSX+2zrQgJ8|CCr11n`u|=C}{? zlHLN%{DxBD;+;&!6Se$BciUB@EQ~Y8_ZT-Q&4p}|A3l`R=AVR9Kt+V~a3a3V{l=)gHBK2op+X}BW7o(X1K2eRTZ^; ziO?#OmuWkXeCj2*{H(1C#qnQ>tz|Kq>*#cF7g)+?3G3(pVB@N37)9YHmYxa}CVb-% z@SHf5CnrEMiI6-&fkkOb9ema$%-Ld}qN54xNf|CDt?#e@Aec&IEcEEpu3Ak5Y z>0@s)b7yHEr~UCsek0JVuF%66MBgBxj-d!wQu4Evlx;p|pZG{&=4VV)*pIE{{f=SO z;V$)QC5ae=-6(Nc68{(S;2ymNVxIiwAs9}A@vA2?55kfV(qK>S6caF|bywd&p8ydL zB}xJ~6Di7u^Xl{s1E&b!{FXH0#>1$=MTNA7+vd;Pm*#B`iYRecX>5H7^iqDqQ{GQH zKNNh0?p}h?nEjh_Ft*^M`+(a;L*rKgPp=E!!}stvVxG|YKY=Yh25?+RloCoyT3T~2 zr1!?YL58}YTlyj1sTl_H(oBl48zJPwJFr9|r(>T7Npe$Hyl7Pm(dZ}|x;n!X(4wtZ zeNCCz4LTygy(gl;pV;dp+-Lpq=weiOW2Z_Lt@RNd_s43tZ>$@23^%6`T}rfexq!%# z)e|oR;kRY~2fW@V(in6QZzE*6TubN0<>|v2xiX)v6->d$no+&np8 z=DZPj>yPVL2Y2U^MJuW`R8R{2@Rg&}`S+$yEgsGihuW$3 z2y*A5Rm-TCh*xaY#R1q)HfzQS_%fPHCL7200}u=S#u`m zvW%z6F_UcmBq~g~s|d}v6$Q?noL`Z(X;@Q$i>kw^bF}I3A8QQyAE_nz-`H~a9o2}- ztPUs0q(DTZ^Yx3oA6C5I?{nHCX0qfW&C2r}h~~slhe!$_Hh1WB`w?_|D{JsF#zpgf z;F^yDTZs-$?`myzyDj@=x}@L4b~_KtUWzV+uiL${48Qh^ZdoywlRNR<*WLFY>v0fq zeWQS`g6{8q<#x){FrCbZlcTAh?+fw^gB-2LpRnlF^}`$D;(KxTOLn;dXs3Yl(uW$g6hyw3{wZdTVg|kdSet`n+SACG=!&%#r zl+Ha_MzD$G>iQb%tW~Uus7-zOMPI__Qo92dK3VKkGgR#;-!`uw++~l5J?MT+BUCv3 zcItfZO)uKXlipj1XD?F|>3frjQWA;$JV>TcHHrcrR=Ql;-B}Bb4;f|uVo(S7xL(QP zE%c8{bnchCJ%aG)3x8gx0`Hqq`eapfWqK`~Ec6Mea`v0{J?4~x(S2D#-7sMBR1X;{ zO-QlMUsyD!#jI^8v6y2J8TinHz_zsU@;3|?TfT0F2b2A7aX&aEQGc;IZ>UV*cToht z27rX9TA$h1ZMxk`KX|$6o$)=$PxIM3k^FhGmiJMaA3fBM6(M#efLJ9ucfbo2TkroP zxE4Dv?B_Nkef;0LYVj3nk|C9-MLv{y^-tY`SD(5phR2KMn}9@?I@SQ^#m* zu>9T8l>)311+yf)qc`Zp%3Cp9FS4PN18t5zZGy-!{f^5eJQA&Fb>Llf4kF^OZ}Tu z=jyadHyzlQLaf@_eAf{CFb}_v=Gj*BLc$VrMAe%hAL@6JaXkt^p&>`#SXjBAX!3#; zZ(sPdwtkoS08=HP@lruhHm*fIlu{y~LTu@+@;u*LBUU~nbQ7S{eH09xc5^_Xtu!q@ z6^P#P!A-(qwW30Th;TBWNp{b1+lP1D!2Y2In`HJ8=DTs8;1)Y~TE2Tco&agHaJGJRtE&{R2y^@Gnpny|$qxXc2=Ps$@$~9mxET{1Q$%i!i#frlzo0UOe_Y zMxNvLk98G99Jhl+-rMB_{OyQsE?70nTDUTZf%>P_;7WAz0a+FG*4EALUD*p3UWt_( z3yZrIM%L#2dleC=K}bD*)-@4195ctqtgM0iQACxJ?F&0O<{t?%^dK1pMJo*-dHj;E z%Vt=-^pa?Z(eb%_rx~$m@yuyvX^t!IvZZ&&LJtY`#;x+PXT-Gb~(3>gv;tf~4N37#aCX z-tW%A@AM^Cf&WBJl*|wp9s0RGq_rCL)=Klfe3e8BUY|7FGZM)#ZdT04zyZ#{*|<&8 z+dsxt9B+krqDfJbykPO==|6C|yAi)*jkV&C{Du7Y#drV0`{jGeFSFOANIz#B-ncz= zB?v}IR2j5eCJ`2>yNMN9<}h!(e$i><|KSPd(Ff^lC-7pg&G~QJ8T0JD-37gq1-K+V z;1?GW_CVrGX3V0m%yvW#+uGLl^01=9zyGrgZ5fJ6GeeULS25^4)YCL=-Z!w`r$tH= zj-ikdG|nI;y1wvvk2)h7^hL0Xvnxw)Y1u}&9Vv%k1};Z0IqW?AQ8)B@QOUa?ayt31 zX^`u?pa(0F6YpbrT;e2^auw#%0BX_ub?}_ieYF;4rGRd*1_vX-+Xv9I&yR@ zZF(3;`kXg0vHdTn$5Ie;gpS4@djPPJ60-Z_1?!DwQz9NO2jKDbkZ^oJbQVc?6v#&0 zAW|kWVx3>tw#eTFT> z$S^|&ZWo)7Lyes7r)@VL=2A|$JW1nr)ed9~F&(_uHC1f;YO_5oj&Afj!0(9M)7c*f z$rra8Ji?1Bc%e|v^CcS{(B7RRCc7Wrrs=I7)f#8IE{rDM)o~`?Y8!;pSaL!lLHCZ% z2RHV1+l?QSk}_AkH)`_s#(xKJ?jwKC`csy*aOGtV&`hmHIG<5hXtzm+=iQkb{pyZ< z%;RxAP~z<%lTo;vNWd4mn;*jW+1tVM*tJ0j)}5|LR4#M7r{PkXJaW;yHBr@9pIuiG z8V1M4Ci1&Z6T1I>(C@#6rJT=}4_MR%kp=0LFD)iInpDCFQ;rm ziA+yF-c%|NyQ8);!vM6)#xu8qylq9(nieBl!@e}S5}R@)8LEU)Q|o0z)Z3vP);l2n zvCG7gtlR2XtjF1}fhC?!r{BZ4#sNRJi-Kgt?Rd(rePR;wmE}rqM-z^#fA_=ptrRR~ zqS-A)prf=s19gdfPBn?#&j;!a+e1!wX7|RMt|@0KQ_^z7My)2imN}+? z&Ro$-#EC#FN(11}WJ|$X)eQ0hf7Xye3AhvowX$0|1+x+uY~g?ccTKswq+io;vFNd6 zr7#C9z4;>@b-tg$UzV@9U5hK{mDW{6%YjDa>FJu9Z8hZyN}pshPN=W>uI!^Q$kMqm z+}IiQA9sdYvoB1IiBfX#m0axM;6c8}N>K$tD8kW56>r1h5t8J!3X0YAj1|Aw&~l@A zxf2^V`F;A0W?i!7*yQ+#;?4!!1ZQrBEI$9+-N z6P_sTrV&}s7MX}77Nq}~KmQy&5T&0ZWX--y(<$MEOLGIm!7k)jQOWggN0!Rg^`Bj3z7;;PquhhFnoqJeAbUfHR~d2;C{_De_Ogp81i65*qU(X5fweyv+B#w>RW0 zm&_w7Zm z`YWfGxm^7MK^A>0nDITy;gz^Lzudv@BC>+^JOVExD%|?aa0W#9qe``&CHjF6vqV zB8&tSqdhz{r4(|w3!g-DZKg>^k=!a74kk`D{P(2>&R~8kXP)^Ns3jTlnM7|b=I@?W z*3YW^eW^H83@t)lUE4LAm#(ICbAZTgW?ohHU;Ok91QJvMGp6fHL|&TQb|ICaXi{OO zrD__`B5>e)a6orX^!P5CsJZqQhI9-E6v4*!cC1vUi2?G|44quG+rfLS+7ZX;meFoT zMa+fb0pH+x{|o<7L^;cM5J4}K*7m~l#N2_qa(YL%G9rt7(fo;z(CaJOODkCKPA9`Bop?dIYFl3wBU&l zdqN~tz4k#i1&+HT_N>0Qm%uxG;}xqfaciIXXK|67VNTu0yzMz6pt6)m~ z7y^EZ+(wMlK9yMiwkhp&>cmXQoRzGf`o{MmkrGaxJY*%s0Dza_WczOvC8IXtY4zGE zoAfaSy~MQoF^;l5RWb}DJq*S_&wp|_lkCAaR~iQkooeXo>yX+1hRw(?%#&k0 zm|IG1?>%mpBmLr(*DC>|Vr>bN;nKsdZLlS4*_h%G1n`;;6|sE0rg^T9KG)Swoz!z& zJra776~H1@daS@C;jzI*0~;x5(E1Fpo!nLAV=SmM;Q>*#bxdaC<;wO{!IV4ONwN}f z8NK=|T>UjQ5%%_C3KAVb1}wC~Feno-GH|l>&?HI*RX~t*0XtJ~S0R6Kst$kD*7mw& z{mR31-KopNO5bKJqku0*PjnBKFE_1y_|tmDtiN7SF!NZpwNb5#sV6w^bu9#1B5K7# z0N}))422cqc#^(uW?wJU*^KLe?VU&(*c6j;U6^LZcQoK4POU1{yKSH^?k2$VGLEWB zog!7!3_Kl%apr)=%d3Rpw_4BDLZf!1tIdN&D;Yg?X2&jp0vSBqbz)XX`Wu2%`IWJS1s3lhZ7H--?PJxQLg$XONw$8qE z@4G(S5}8yFwM`{Rdz9E__ZH{{Gusj%$t#w4+ac&G3wkM0n&qZPP}J9r*av-Zq- z%NdhH1sgs~Oq9{PLkkxDiK6MQo36OTZrr&F7k6+F*a}5hV<;1u+B`QQSF#ti5`pI3 z@gvRFovLjNAri8~54co-plD$yQSX*b95r9t@B%~eI2r9NqXw{mGRKtdG5*|wk~yO zW)?msL*Rlpy{X4OLKx;RTX5`t1RY4!(bJ`a7rJ?=xM7fwcCL;k7j%-*cj9NLfbojM= zsFk;>hWcz(m*MFBO66YXrs>D4!BqdqWy_oZ>c&}P@|L*1a zVk(-?<3wy?;t9XLM*dyTj^XbicaVIM%BJouomO8jaqzV51LbTf>Ywq=#cXFtO*-oC z$O(ezf}G*);p^d{5Cc9apUxWE7RHp-F$ne9h?~C!5ok6%glp3JFOLJd2A-Fm@I}Id-s z30mMGUBh}2LTd&+z4*b8fB8hNy+ke`kmJbFXYm9=Ud96znCvs;Xa*GB`{*jEPp($~+DX+RP*)$prD03Z~ zot>}r&YE}7>5Wkie5E(*NC^ihU`EdF6Ezw%Y_=C72{{2}2gipm z*Kp)Aa`c2J&xYYZ876z^z{Zt5pR2|?72(fT&g8MYt4OgJ8>+ZDr_oB=>9xhEw%27Y zdZWI$a9GrD@5Los+iFbyl507c-TMRH3x)MMT{uczOKy3!ra7;z>2})#CRqJW`Jr@s z)uA36KCgr8c)q);G>N2B3p4kyV4NWuoxzls;Xqq+eg~fI$A3otuea;KAQGd#L@`_H zA12vy0BVLhln8XMstlX5M43pjjcZzAO3GUc$zV-2^wq;7JE(EwPLoa!*2(XgxwSlx z2_J0xvN3`hnHWW^kuO7z`%AW8B~t4yhgSPHzS%y%$=}V7s+fZJ0#{k0^O+*L0|Zg4 zfX#xMrgl!s6Xo=iNk_&jq83fy!YAvDSuT8GO6%m58Pi*2YUR|;TQb;TdN=rqTpKIZ z-p&;$N{lIA6N##--%mV~CtEEa4=)@J`4YoT@$9}xH&qcX>lvW>wj*s%n1(JbS$r*d zK9ca~LMdTQ7v!Y34Q6Zh;50&tLX-E@$j3m@9%{iLEyrjeeM_lyMFuI6_pPMcUemdp z%6;iM!PP84B5GQ70B|+R^|BqipYC7_%BZRXP;eo#KZ6EBvBzlpn}@P3p}|8#I(4 zul0x<>TxI(s0g?8v|a89+n1)Jx##kH*g@FY*niUw?{Sqmm)Xi-;WBKlUieBT&& zR3bfdZ|yI{!e~+H2q@uF@=N3k*$H|RZpj@5hvmw~_Py+wV14-k8ynOVi-{@1gB;!g zop(C8F2W!)$gD|@VYtF3M2`gl44ny?45baF7yCBl4PB@{E_nNFz6{2b zr3nxXdd~S*FLLzzO#wytqw(3PI0_%D56fEkMQPca=JX$gqH9aJ{ZpKvk8&kz zVxpVpl56nj^P5R4Lm_KK_6WeFW0cD?IY zZu%H?$YfA5eBYF>2g^}+ig>LD^PgW_C#jRJ$|LNXlubK_b)pT9uqy)nlg?;4DG*(P@1w56aN4^TZM6bWUyCM1*1Czy}HIA#1w25=*y73 z^<0dmnQg(qFmL~t3lPYXx1H8~Zxg@d(x{4t40F=4{->PSRp{RzUszJHDlXejc7G)lY;8~fKsU-hk(590&9v& zFxr}ZKJqco?V2qb5bnkeLoQVbyu32=?$Kwh?;N0OiGN|7=6`RkdoJ(JT@djZ8dUCb za?z#~&v8Fm?V}L${Zr&aQ8JC0EF>X56u4pkjt-w^+1bG$r9f1OrJ$<6qE&iV7_}kN zQweT&?sbJOanV*#E0|bLjkCC(vOm|{V<5MsimhiSt-uxzjxz9SMUvMQK{`~RZ+v_m ztb%l8kCZHm@?oa?Mb$L;Bv2$(K*V=w5SD>$*ITQ!W*n%SOXJlQO>pLoRxLI#%aHpA zmYUE<8T)d$P6F=j$+`7W&dSV^FR;c5cvU=igm6$Q0Bz?EE|?msF@JEX89DoMOUuTr z`R{3)%|h-VtA7`wTgs8)s;PQ6$6IvQTsUzrO=Y6G!D)=Xx9w0$Gba6n1y?{dK@SoK ze54vzFH|9D2~QbpUTb_H)IYDfa|J}Lq9?%CFHbsIB8(vc1WUKbA`4uL=6b&iurle2 zi(4jg{2hA5K*7uKNnBA0KV4x*3NO0jb^QuEWV&39?%#Ve9aEQ)AWUUwycBSf_o%|` zTcm^fRU(B}U8I(N*#z&8fsGAkKpBAt5@UnRa>N{07@%qaw@bs$K2R5VP#c$2^Q%RQ zVuW0slT(*~U8kk?duR;_jOTpmwrrbx->n}JX^_|@zO|a)Ik@>X7HOQ(!z(#CF@`^7JGf2aEfn1S0v}oHKo%uVUMDjl3<>f#kD$hfw(^nW(aRB6AaG-TDAh%oHjEJ=J$;2s zNEtTUsuZa{ji(_8)1j8gUOb~B9fXBSc)M%Hfsu<`&aJGt{{#rePUQ zno1K;1#~H`?Rd#V$}MtvkS~UOgsP~@^u^u{ua{D3V=Fa{2IKwI7>|!cOUteP#X!Z_ z0=9Z(Y!#lhZpJ0TKxMl6%R?6~lt!EvNztb>dbADO5-ZkYS1f(TlqF6|c^Euh&Dojz z>7lTs0ClkTp5>|*~0 z_E{QdSna;}KOcu@*xbF3xyhffB&XIT`p{6hS*F))v#>=YEtJB9Cr*b2YtK$qd9@hS zP$+_%N43)URxgAF_fx!4#yRV$Y6W06mtQ<`6RwW>A*AaHVyEylR` z2)a@71;tKHeL9Ik*CB!~)Qw;=Fl6gGLG;?;LTeerep>@XsgVh4FN73z`?Z=yj9;v% zBxr{}l;h6)J_enD_Xs$w_!zAMpK(;B2{L7;9924=)DeQQG^=eR>S_sq&5Q6tF?!ZR z5Qknd!5HirCsnTIK}aSQLQ_)EQtb#JSG@QUVD}mpOr(idOXutsza|QP5K1WjdsWrs zkY855Sph`j8nzw^f)v# zwC?)Bwo9-}lWq~G9ow>)3->q?FnXQ<$)Y*Vq?hu8MmH8aL1yGrPXCBBQZxc2c}gM_ zazx&=nWtc(!DSU&y7M>VVWHK|f42Z4$ zgM>V`3TB$s+ZXAeFq65x>B{Mdc~^YySq_px;%mpmr2Huz$C}=8-KJN$50%RxgBJ`5 zP&~~O#I1B_1NXRe11=!ZG+8?m1fW)N1v3M~LuJCB_sLZ){E+CtNyJ{zEW!m2t6~4F z%H681*4phFkdH+Wb0LC&2rz`YF05QDpj#b^CS9c1iNN6yizQhsjIRb7ouDlN!>cKa zg7n0;K8z}XHxXi2Ecua32b&VylFo$*L~5$eud(~1>99o0y8R!-= zN_$<&9xytjEu>6segSMd2}6=@3VVB@GhvK>e5(3kr&=sV&}-F69b-m9?Ip^S&_1rK z)REQFT(LR2P6B9EqR$$Fjhw z@@PRbM9s{1I>jgtQ$A{Too_2xnL(GQD!IAjpSUUis4yB{sY$2}MT}d+!IfS_pu32*B z(%fM}`E)&K1vl5$L@*MaDwYf>96D4c;kb|PKTS;+YgrY9Ko@0Q)3$VlDZzF2D5qzp z3ooIC#iZNaZ8P4)aA|hlnC{a}TPrb~vTu2a+lFss)C;W1zZ926mndG{GXR|B)WfV} z(w*ugyn0Rs7_}^z1)X+M+)NXwrEUSMFwNFX_HD7RuV z!p-X54t?QhInx8)RxXg9Gk>_MaF-=XqAoa3dpy^>ZnMr+Cdt={MR4L zlI?2b=gsG3&Ijqpwy~pkv)Y=9n_|E|4ghMbhOV!U-CR;Kg+YdeFwVdfiyc*SZ33P= z$^Lo3LKgdGzEro#sbQm;1h}cbE=gD;VPV$RSAC(NX#P3$r*wNcQV1ac_8s?7<*v7Pd5{UE zcj<@b8s(}ugB+l6X(Y2RciZYZr@$lnh&EYVD&Q;@IV#m~)&N`>i%eC8QGg&uMXI=s zQLp~@6So9V;*{|ZngyWwRLWwzOCrXEh&`MazZ2wm)kNAKFDMMTX_jGA!oO_hJ-YRa z$^tLI^PHPVUu(o9eNPBKBkY8oY*JvIpawcN$Hq>rF`BD0kq%ngOwjI!^ei&^{U1>= z!^&Yoa|y-vSLjPKIP(7C?$zHcE6TomiB6zAM~x|S=v76w%>=hQ$rVordZSPGH_r!u za~NE4L)9W;Zi;ur8=N=;g2x`9ew-T?zd44CWDowkmcCKC2ZEkwyy{Cgf?DBwA)VTz zfJ;~J*q-_{>l2=#Z#w%BHa5yiZUb#89mRN|$!s*X41Sj}m@%Y%D8!j#oex}HpuLkT zi_70a875WHbj(&5q=Cb3*-Fn-b_=@DxVxh?M%~C#aO%I9A zfDhFlS)5h5m^sgc`qgo&LB;4CbJ+4Do$EQJL-i45cQ|%b4D${*iHS6$Z!lFja4{Z& zm_cQ;+$jmX_Ipjb?|qoQbz3TEQd@UgHO-t8i&2#uH*%Y+@t8HptKD;^>9mRb|w53r?9PIIfP$v|io_ z*cIdNpF96_?%r4O-CUdtgPsVgQ7~>`(Iv=~Vz&=N0I0@6UyQtkp156a;eRI#QPSg> zAcDjr+gD33>K!@@N;gSJr1%xowp?n{?=lK{fWo0V0xrMs(WD=)!hLrQ-FS z@!mYs_Wz~@&+paJijML41V^ce^;23KtbY_xNJKz@7&zTeFEoHm7;$(UI=YQFs#$@ptk!EQ42Y4FfxEf@TOsVt37 z}4AVbnC9Ri){mLjd@o@_vA;wzpV8G_ypN3Y=M08M6ZfM2Xtkpu^=A9}u!A?A z)0NYU%Y#TSSE#tnm?KTmo4 zd|UY(Tqjl;m?`7^R${$QG*ZIW=)p?(%lWYXyf8k9{rdP=)z$ty1cAPSJfgXTOPXN1 z^D-Pknjk$jWsP@0+o&sn#8=lA=)a-i-j|YE5DwZ9s#vk3w-c?}%C?C;Q@<(1;-i>L zl}SN#MAX*71GGR14&RiPaHe@3srrMMPYHjml+|aGSDU_fRi{h1_NlT;MHYR@D(IR3 zt6;N#m)Tdz?)V=$7s!&Z;ZdmJFd0m>InR~Umqz^)eM=coLx(q4tw%~Z0U73ho^=Mj zF)fREGIOlh6`*ARYk?K%ir!a_Yvw9snW){J#zyP<3!#qD8Q_2~d|so+(Xc54smil}_4kGqEK^l7mVKQmM+ zBR70H=a2QXGB!3jg`P(Kg~lE^KQr-y_EVJi%}cMMzb+f?)6-|yp{QzpZdk)-9EhXzQpEZ(ZuvkddnL`d4Y{JQ>J+Eg}}BSGkUqgbqYuem+;8++@MM(|;Eh?pTI_O&4Gy6PBOnIB)^cWfo! V^Rh-@K?jDw` + jWTRegexString = "^[A-Za-z0-9-_]+\\.[A-Za-z0-9-_]+\\.[A-Za-z0-9-_]*$" + splitParamsRegexString = `'[^']*'|\S+` + bicRegexString = `^[A-Za-z]{6}[A-Za-z0-9]{2}([A-Za-z0-9]{3})?$` + semverRegexString = `^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$` // numbered capture groups https://semver.org/ + dnsRegexStringRFC1035Label = "^[a-z]([-a-z0-9]*[a-z0-9]){0,62}$" +) + +var ( + alphaRegex = regexp.MustCompile(alphaRegexString) + alphaNumericRegex = regexp.MustCompile(alphaNumericRegexString) + alphaUnicodeRegex = regexp.MustCompile(alphaUnicodeRegexString) + alphaUnicodeNumericRegex = regexp.MustCompile(alphaUnicodeNumericRegexString) + numericRegex = regexp.MustCompile(numericRegexString) + numberRegex = regexp.MustCompile(numberRegexString) + hexadecimalRegex = regexp.MustCompile(hexadecimalRegexString) + hexColorRegex = regexp.MustCompile(hexColorRegexString) + rgbRegex = regexp.MustCompile(rgbRegexString) + rgbaRegex = regexp.MustCompile(rgbaRegexString) + hslRegex = regexp.MustCompile(hslRegexString) + hslaRegex = regexp.MustCompile(hslaRegexString) + e164Regex = regexp.MustCompile(e164RegexString) + emailRegex = regexp.MustCompile(emailRegexString) + base64Regex = regexp.MustCompile(base64RegexString) + base64URLRegex = regexp.MustCompile(base64URLRegexString) + iSBN10Regex = regexp.MustCompile(iSBN10RegexString) + iSBN13Regex = regexp.MustCompile(iSBN13RegexString) + uUID3Regex = regexp.MustCompile(uUID3RegexString) + uUID4Regex = regexp.MustCompile(uUID4RegexString) + uUID5Regex = regexp.MustCompile(uUID5RegexString) + uUIDRegex = regexp.MustCompile(uUIDRegexString) + uUID3RFC4122Regex = regexp.MustCompile(uUID3RFC4122RegexString) + uUID4RFC4122Regex = regexp.MustCompile(uUID4RFC4122RegexString) + uUID5RFC4122Regex = regexp.MustCompile(uUID5RFC4122RegexString) + uUIDRFC4122Regex = regexp.MustCompile(uUIDRFC4122RegexString) + uLIDRegex = regexp.MustCompile(uLIDRegexString) + md4Regex = regexp.MustCompile(md4RegexString) + md5Regex = regexp.MustCompile(md5RegexString) + sha256Regex = regexp.MustCompile(sha256RegexString) + sha384Regex = regexp.MustCompile(sha384RegexString) + sha512Regex = regexp.MustCompile(sha512RegexString) + ripemd128Regex = regexp.MustCompile(ripemd128RegexString) + ripemd160Regex = regexp.MustCompile(ripemd160RegexString) + tiger128Regex = regexp.MustCompile(tiger128RegexString) + tiger160Regex = regexp.MustCompile(tiger160RegexString) + tiger192Regex = regexp.MustCompile(tiger192RegexString) + aSCIIRegex = regexp.MustCompile(aSCIIRegexString) + printableASCIIRegex = regexp.MustCompile(printableASCIIRegexString) + multibyteRegex = regexp.MustCompile(multibyteRegexString) + dataURIRegex = regexp.MustCompile(dataURIRegexString) + latitudeRegex = regexp.MustCompile(latitudeRegexString) + longitudeRegex = regexp.MustCompile(longitudeRegexString) + sSNRegex = regexp.MustCompile(sSNRegexString) + hostnameRegexRFC952 = regexp.MustCompile(hostnameRegexStringRFC952) + hostnameRegexRFC1123 = regexp.MustCompile(hostnameRegexStringRFC1123) + fqdnRegexRFC1123 = regexp.MustCompile(fqdnRegexStringRFC1123) + btcAddressRegex = regexp.MustCompile(btcAddressRegexString) + btcUpperAddressRegexBech32 = regexp.MustCompile(btcAddressUpperRegexStringBech32) + btcLowerAddressRegexBech32 = regexp.MustCompile(btcAddressLowerRegexStringBech32) + ethAddressRegex = regexp.MustCompile(ethAddressRegexString) + ethAddressRegexUpper = regexp.MustCompile(ethAddressUpperRegexString) + ethAddressRegexLower = regexp.MustCompile(ethAddressLowerRegexString) + uRLEncodedRegex = regexp.MustCompile(uRLEncodedRegexString) + hTMLEncodedRegex = regexp.MustCompile(hTMLEncodedRegexString) + hTMLRegex = regexp.MustCompile(hTMLRegexString) + jWTRegex = regexp.MustCompile(jWTRegexString) + splitParamsRegex = regexp.MustCompile(splitParamsRegexString) + bicRegex = regexp.MustCompile(bicRegexString) + semverRegex = regexp.MustCompile(semverRegexString) + dnsRegexRFC1035Label = regexp.MustCompile(dnsRegexStringRFC1035Label) +) diff --git a/vendor/github.com/go-playground/validator/v10/struct_level.go b/vendor/github.com/go-playground/validator/v10/struct_level.go new file mode 100644 index 0000000000..c0d89cfbed --- /dev/null +++ b/vendor/github.com/go-playground/validator/v10/struct_level.go @@ -0,0 +1,175 @@ +package validator + +import ( + "context" + "reflect" +) + +// StructLevelFunc accepts all values needed for struct level validation +type StructLevelFunc func(sl StructLevel) + +// StructLevelFuncCtx accepts all values needed for struct level validation +// but also allows passing of contextual validation information via context.Context. +type StructLevelFuncCtx func(ctx context.Context, sl StructLevel) + +// wrapStructLevelFunc wraps normal StructLevelFunc makes it compatible with StructLevelFuncCtx +func wrapStructLevelFunc(fn StructLevelFunc) StructLevelFuncCtx { + return func(ctx context.Context, sl StructLevel) { + fn(sl) + } +} + +// StructLevel contains all the information and helper functions +// to validate a struct +type StructLevel interface { + + // Validator returns the main validation object, in case one wants to call validations internally. + // this is so you don't have to use anonymous functions to get access to the validate + // instance. + Validator() *Validate + + // Top returns the top level struct, if any + Top() reflect.Value + + // Parent returns the current fields parent struct, if any + Parent() reflect.Value + + // Current returns the current struct. + Current() reflect.Value + + // ExtractType gets the actual underlying type of field value. + // It will dive into pointers, customTypes and return you the + // underlying value and its kind. + ExtractType(field reflect.Value) (value reflect.Value, kind reflect.Kind, nullable bool) + + // ReportError reports an error just by passing the field and tag information + // + // NOTES: + // + // fieldName and altName get appended to the existing namespace that + // validator is on. e.g. pass 'FirstName' or 'Names[0]' depending + // on the nesting + // + // tag can be an existing validation tag or just something you make up + // and process on the flip side it's up to you. + ReportError(field interface{}, fieldName, structFieldName string, tag, param string) + + // ReportValidationErrors reports an error just by passing ValidationErrors + // + // NOTES: + // + // relativeNamespace and relativeActualNamespace get appended to the + // existing namespace that validator is on. + // e.g. pass 'User.FirstName' or 'Users[0].FirstName' depending + // on the nesting. most of the time they will be blank, unless you validate + // at a level lower the the current field depth + ReportValidationErrors(relativeNamespace, relativeActualNamespace string, errs ValidationErrors) +} + +var _ StructLevel = new(validate) + +// Top returns the top level struct +// +// NOTE: this can be the same as the current struct being validated +// if not is a nested struct. +// +// this is only called when within Struct and Field Level validation and +// should not be relied upon for an acurate value otherwise. +func (v *validate) Top() reflect.Value { + return v.top +} + +// Parent returns the current structs parent +// +// NOTE: this can be the same as the current struct being validated +// if not is a nested struct. +// +// this is only called when within Struct and Field Level validation and +// should not be relied upon for an acurate value otherwise. +func (v *validate) Parent() reflect.Value { + return v.slflParent +} + +// Current returns the current struct. +func (v *validate) Current() reflect.Value { + return v.slCurrent +} + +// Validator returns the main validation object, in case one want to call validations internally. +func (v *validate) Validator() *Validate { + return v.v +} + +// ExtractType gets the actual underlying type of field value. +func (v *validate) ExtractType(field reflect.Value) (reflect.Value, reflect.Kind, bool) { + return v.extractTypeInternal(field, false) +} + +// ReportError reports an error just by passing the field and tag information +func (v *validate) ReportError(field interface{}, fieldName, structFieldName, tag, param string) { + + fv, kind, _ := v.extractTypeInternal(reflect.ValueOf(field), false) + + if len(structFieldName) == 0 { + structFieldName = fieldName + } + + v.str1 = string(append(v.ns, fieldName...)) + + if v.v.hasTagNameFunc || fieldName != structFieldName { + v.str2 = string(append(v.actualNs, structFieldName...)) + } else { + v.str2 = v.str1 + } + + if kind == reflect.Invalid { + + v.errs = append(v.errs, + &fieldError{ + v: v.v, + tag: tag, + actualTag: tag, + ns: v.str1, + structNs: v.str2, + fieldLen: uint8(len(fieldName)), + structfieldLen: uint8(len(structFieldName)), + param: param, + kind: kind, + }, + ) + return + } + + v.errs = append(v.errs, + &fieldError{ + v: v.v, + tag: tag, + actualTag: tag, + ns: v.str1, + structNs: v.str2, + fieldLen: uint8(len(fieldName)), + structfieldLen: uint8(len(structFieldName)), + value: fv.Interface(), + param: param, + kind: kind, + typ: fv.Type(), + }, + ) +} + +// ReportValidationErrors reports ValidationErrors obtained from running validations within the Struct Level validation. +// +// NOTE: this function prepends the current namespace to the relative ones. +func (v *validate) ReportValidationErrors(relativeNamespace, relativeStructNamespace string, errs ValidationErrors) { + + var err *fieldError + + for i := 0; i < len(errs); i++ { + + err = errs[i].(*fieldError) + err.ns = string(append(append(v.ns, relativeNamespace...), err.ns...)) + err.structNs = string(append(append(v.actualNs, relativeStructNamespace...), err.structNs...)) + + v.errs = append(v.errs, err) + } +} diff --git a/vendor/github.com/go-playground/validator/v10/translations.go b/vendor/github.com/go-playground/validator/v10/translations.go new file mode 100644 index 0000000000..4d9d75c13a --- /dev/null +++ b/vendor/github.com/go-playground/validator/v10/translations.go @@ -0,0 +1,11 @@ +package validator + +import ut "github.com/go-playground/universal-translator" + +// TranslationFunc is the function type used to register or override +// custom translations +type TranslationFunc func(ut ut.Translator, fe FieldError) string + +// RegisterTranslationsFunc allows for registering of translations +// for a 'ut.Translator' for use within the 'TranslationFunc' +type RegisterTranslationsFunc func(ut ut.Translator) error diff --git a/vendor/github.com/go-playground/validator/v10/util.go b/vendor/github.com/go-playground/validator/v10/util.go new file mode 100644 index 0000000000..36da85514e --- /dev/null +++ b/vendor/github.com/go-playground/validator/v10/util.go @@ -0,0 +1,288 @@ +package validator + +import ( + "reflect" + "strconv" + "strings" + "time" +) + +// extractTypeInternal gets the actual underlying type of field value. +// It will dive into pointers, customTypes and return you the +// underlying value and it's kind. +func (v *validate) extractTypeInternal(current reflect.Value, nullable bool) (reflect.Value, reflect.Kind, bool) { + +BEGIN: + switch current.Kind() { + case reflect.Ptr: + + nullable = true + + if current.IsNil() { + return current, reflect.Ptr, nullable + } + + current = current.Elem() + goto BEGIN + + case reflect.Interface: + + nullable = true + + if current.IsNil() { + return current, reflect.Interface, nullable + } + + current = current.Elem() + goto BEGIN + + case reflect.Invalid: + return current, reflect.Invalid, nullable + + default: + + if v.v.hasCustomFuncs { + + if fn, ok := v.v.customFuncs[current.Type()]; ok { + current = reflect.ValueOf(fn(current)) + goto BEGIN + } + } + + return current, current.Kind(), nullable + } +} + +// getStructFieldOKInternal traverses a struct to retrieve a specific field denoted by the provided namespace and +// returns the field, field kind and whether is was successful in retrieving the field at all. +// +// NOTE: when not successful ok will be false, this can happen when a nested struct is nil and so the field +// could not be retrieved because it didn't exist. +func (v *validate) getStructFieldOKInternal(val reflect.Value, namespace string) (current reflect.Value, kind reflect.Kind, nullable bool, found bool) { + +BEGIN: + current, kind, nullable = v.ExtractType(val) + if kind == reflect.Invalid { + return + } + + if namespace == "" { + found = true + return + } + + switch kind { + + case reflect.Ptr, reflect.Interface: + return + + case reflect.Struct: + + typ := current.Type() + fld := namespace + var ns string + + if !typ.ConvertibleTo(timeType) { + + idx := strings.Index(namespace, namespaceSeparator) + + if idx != -1 { + fld = namespace[:idx] + ns = namespace[idx+1:] + } else { + ns = "" + } + + bracketIdx := strings.Index(fld, leftBracket) + if bracketIdx != -1 { + fld = fld[:bracketIdx] + + ns = namespace[bracketIdx:] + } + + val = current.FieldByName(fld) + namespace = ns + goto BEGIN + } + + case reflect.Array, reflect.Slice: + idx := strings.Index(namespace, leftBracket) + idx2 := strings.Index(namespace, rightBracket) + + arrIdx, _ := strconv.Atoi(namespace[idx+1 : idx2]) + + if arrIdx >= current.Len() { + return + } + + startIdx := idx2 + 1 + + if startIdx < len(namespace) { + if namespace[startIdx:startIdx+1] == namespaceSeparator { + startIdx++ + } + } + + val = current.Index(arrIdx) + namespace = namespace[startIdx:] + goto BEGIN + + case reflect.Map: + idx := strings.Index(namespace, leftBracket) + 1 + idx2 := strings.Index(namespace, rightBracket) + + endIdx := idx2 + + if endIdx+1 < len(namespace) { + if namespace[endIdx+1:endIdx+2] == namespaceSeparator { + endIdx++ + } + } + + key := namespace[idx:idx2] + + switch current.Type().Key().Kind() { + case reflect.Int: + i, _ := strconv.Atoi(key) + val = current.MapIndex(reflect.ValueOf(i)) + namespace = namespace[endIdx+1:] + + case reflect.Int8: + i, _ := strconv.ParseInt(key, 10, 8) + val = current.MapIndex(reflect.ValueOf(int8(i))) + namespace = namespace[endIdx+1:] + + case reflect.Int16: + i, _ := strconv.ParseInt(key, 10, 16) + val = current.MapIndex(reflect.ValueOf(int16(i))) + namespace = namespace[endIdx+1:] + + case reflect.Int32: + i, _ := strconv.ParseInt(key, 10, 32) + val = current.MapIndex(reflect.ValueOf(int32(i))) + namespace = namespace[endIdx+1:] + + case reflect.Int64: + i, _ := strconv.ParseInt(key, 10, 64) + val = current.MapIndex(reflect.ValueOf(i)) + namespace = namespace[endIdx+1:] + + case reflect.Uint: + i, _ := strconv.ParseUint(key, 10, 0) + val = current.MapIndex(reflect.ValueOf(uint(i))) + namespace = namespace[endIdx+1:] + + case reflect.Uint8: + i, _ := strconv.ParseUint(key, 10, 8) + val = current.MapIndex(reflect.ValueOf(uint8(i))) + namespace = namespace[endIdx+1:] + + case reflect.Uint16: + i, _ := strconv.ParseUint(key, 10, 16) + val = current.MapIndex(reflect.ValueOf(uint16(i))) + namespace = namespace[endIdx+1:] + + case reflect.Uint32: + i, _ := strconv.ParseUint(key, 10, 32) + val = current.MapIndex(reflect.ValueOf(uint32(i))) + namespace = namespace[endIdx+1:] + + case reflect.Uint64: + i, _ := strconv.ParseUint(key, 10, 64) + val = current.MapIndex(reflect.ValueOf(i)) + namespace = namespace[endIdx+1:] + + case reflect.Float32: + f, _ := strconv.ParseFloat(key, 32) + val = current.MapIndex(reflect.ValueOf(float32(f))) + namespace = namespace[endIdx+1:] + + case reflect.Float64: + f, _ := strconv.ParseFloat(key, 64) + val = current.MapIndex(reflect.ValueOf(f)) + namespace = namespace[endIdx+1:] + + case reflect.Bool: + b, _ := strconv.ParseBool(key) + val = current.MapIndex(reflect.ValueOf(b)) + namespace = namespace[endIdx+1:] + + // reflect.Type = string + default: + val = current.MapIndex(reflect.ValueOf(key)) + namespace = namespace[endIdx+1:] + } + + goto BEGIN + } + + // if got here there was more namespace, cannot go any deeper + panic("Invalid field namespace") +} + +// asInt returns the parameter as a int64 +// or panics if it can't convert +func asInt(param string) int64 { + i, err := strconv.ParseInt(param, 0, 64) + panicIf(err) + + return i +} + +// asIntFromTimeDuration parses param as time.Duration and returns it as int64 +// or panics on error. +func asIntFromTimeDuration(param string) int64 { + d, err := time.ParseDuration(param) + if err != nil { + // attempt parsing as an an integer assuming nanosecond precision + return asInt(param) + } + return int64(d) +} + +// asIntFromType calls the proper function to parse param as int64, +// given a field's Type t. +func asIntFromType(t reflect.Type, param string) int64 { + switch t { + case timeDurationType: + return asIntFromTimeDuration(param) + default: + return asInt(param) + } +} + +// asUint returns the parameter as a uint64 +// or panics if it can't convert +func asUint(param string) uint64 { + + i, err := strconv.ParseUint(param, 0, 64) + panicIf(err) + + return i +} + +// asFloat returns the parameter as a float64 +// or panics if it can't convert +func asFloat(param string) float64 { + + i, err := strconv.ParseFloat(param, 64) + panicIf(err) + + return i +} + +// asBool returns the parameter as a bool +// or panics if it can't convert +func asBool(param string) bool { + + i, err := strconv.ParseBool(param) + panicIf(err) + + return i +} + +func panicIf(err error) { + if err != nil { + panic(err.Error()) + } +} diff --git a/vendor/github.com/go-playground/validator/v10/validator.go b/vendor/github.com/go-playground/validator/v10/validator.go new file mode 100644 index 0000000000..80da095a63 --- /dev/null +++ b/vendor/github.com/go-playground/validator/v10/validator.go @@ -0,0 +1,486 @@ +package validator + +import ( + "context" + "fmt" + "reflect" + "strconv" +) + +// per validate construct +type validate struct { + v *Validate + top reflect.Value + ns []byte + actualNs []byte + errs ValidationErrors + includeExclude map[string]struct{} // reset only if StructPartial or StructExcept are called, no need otherwise + ffn FilterFunc + slflParent reflect.Value // StructLevel & FieldLevel + slCurrent reflect.Value // StructLevel & FieldLevel + flField reflect.Value // StructLevel & FieldLevel + cf *cField // StructLevel & FieldLevel + ct *cTag // StructLevel & FieldLevel + misc []byte // misc reusable + str1 string // misc reusable + str2 string // misc reusable + fldIsPointer bool // StructLevel & FieldLevel + isPartial bool + hasExcludes bool +} + +// parent and current will be the same the first run of validateStruct +func (v *validate) validateStruct(ctx context.Context, parent reflect.Value, current reflect.Value, typ reflect.Type, ns []byte, structNs []byte, ct *cTag) { + + cs, ok := v.v.structCache.Get(typ) + if !ok { + cs = v.v.extractStructCache(current, typ.Name()) + } + + if len(ns) == 0 && len(cs.name) != 0 { + + ns = append(ns, cs.name...) + ns = append(ns, '.') + + structNs = append(structNs, cs.name...) + structNs = append(structNs, '.') + } + + // ct is nil on top level struct, and structs as fields that have no tag info + // so if nil or if not nil and the structonly tag isn't present + if ct == nil || ct.typeof != typeStructOnly { + + var f *cField + + for i := 0; i < len(cs.fields); i++ { + + f = cs.fields[i] + + if v.isPartial { + + if v.ffn != nil { + // used with StructFiltered + if v.ffn(append(structNs, f.name...)) { + continue + } + + } else { + // used with StructPartial & StructExcept + _, ok = v.includeExclude[string(append(structNs, f.name...))] + + if (ok && v.hasExcludes) || (!ok && !v.hasExcludes) { + continue + } + } + } + + v.traverseField(ctx, current, current.Field(f.idx), ns, structNs, f, f.cTags) + } + } + + // check if any struct level validations, after all field validations already checked. + // first iteration will have no info about nostructlevel tag, and is checked prior to + // calling the next iteration of validateStruct called from traverseField. + if cs.fn != nil { + + v.slflParent = parent + v.slCurrent = current + v.ns = ns + v.actualNs = structNs + + cs.fn(ctx, v) + } +} + +// traverseField validates any field, be it a struct or single field, ensures it's validity and passes it along to be validated via it's tag options +func (v *validate) traverseField(ctx context.Context, parent reflect.Value, current reflect.Value, ns []byte, structNs []byte, cf *cField, ct *cTag) { + var typ reflect.Type + var kind reflect.Kind + + current, kind, v.fldIsPointer = v.extractTypeInternal(current, false) + + switch kind { + case reflect.Ptr, reflect.Interface, reflect.Invalid: + + if ct == nil { + return + } + + if ct.typeof == typeOmitEmpty || ct.typeof == typeIsDefault { + return + } + + if ct.hasTag { + if kind == reflect.Invalid { + v.str1 = string(append(ns, cf.altName...)) + if v.v.hasTagNameFunc { + v.str2 = string(append(structNs, cf.name...)) + } else { + v.str2 = v.str1 + } + v.errs = append(v.errs, + &fieldError{ + v: v.v, + tag: ct.aliasTag, + actualTag: ct.tag, + ns: v.str1, + structNs: v.str2, + fieldLen: uint8(len(cf.altName)), + structfieldLen: uint8(len(cf.name)), + param: ct.param, + kind: kind, + }, + ) + return + } + + v.str1 = string(append(ns, cf.altName...)) + if v.v.hasTagNameFunc { + v.str2 = string(append(structNs, cf.name...)) + } else { + v.str2 = v.str1 + } + if !ct.runValidationWhenNil { + v.errs = append(v.errs, + &fieldError{ + v: v.v, + tag: ct.aliasTag, + actualTag: ct.tag, + ns: v.str1, + structNs: v.str2, + fieldLen: uint8(len(cf.altName)), + structfieldLen: uint8(len(cf.name)), + value: current.Interface(), + param: ct.param, + kind: kind, + typ: current.Type(), + }, + ) + return + } + } + + case reflect.Struct: + + typ = current.Type() + + if !typ.ConvertibleTo(timeType) { + + if ct != nil { + + if ct.typeof == typeStructOnly { + goto CONTINUE + } else if ct.typeof == typeIsDefault { + // set Field Level fields + v.slflParent = parent + v.flField = current + v.cf = cf + v.ct = ct + + if !ct.fn(ctx, v) { + v.str1 = string(append(ns, cf.altName...)) + + if v.v.hasTagNameFunc { + v.str2 = string(append(structNs, cf.name...)) + } else { + v.str2 = v.str1 + } + + v.errs = append(v.errs, + &fieldError{ + v: v.v, + tag: ct.aliasTag, + actualTag: ct.tag, + ns: v.str1, + structNs: v.str2, + fieldLen: uint8(len(cf.altName)), + structfieldLen: uint8(len(cf.name)), + value: current.Interface(), + param: ct.param, + kind: kind, + typ: typ, + }, + ) + return + } + } + + ct = ct.next + } + + if ct != nil && ct.typeof == typeNoStructLevel { + return + } + + CONTINUE: + // if len == 0 then validating using 'Var' or 'VarWithValue' + // Var - doesn't make much sense to do it that way, should call 'Struct', but no harm... + // VarWithField - this allows for validating against each field within the struct against a specific value + // pretty handy in certain situations + if len(cf.name) > 0 { + ns = append(append(ns, cf.altName...), '.') + structNs = append(append(structNs, cf.name...), '.') + } + + v.validateStruct(ctx, parent, current, typ, ns, structNs, ct) + return + } + } + + if ct == nil || !ct.hasTag { + return + } + + typ = current.Type() + +OUTER: + for { + if ct == nil { + return + } + + switch ct.typeof { + + case typeOmitEmpty: + + // set Field Level fields + v.slflParent = parent + v.flField = current + v.cf = cf + v.ct = ct + + if !hasValue(v) { + return + } + + ct = ct.next + continue + + case typeEndKeys: + return + + case typeDive: + + ct = ct.next + + // traverse slice or map here + // or panic ;) + switch kind { + case reflect.Slice, reflect.Array: + + var i64 int64 + reusableCF := &cField{} + + for i := 0; i < current.Len(); i++ { + + i64 = int64(i) + + v.misc = append(v.misc[0:0], cf.name...) + v.misc = append(v.misc, '[') + v.misc = strconv.AppendInt(v.misc, i64, 10) + v.misc = append(v.misc, ']') + + reusableCF.name = string(v.misc) + + if cf.namesEqual { + reusableCF.altName = reusableCF.name + } else { + + v.misc = append(v.misc[0:0], cf.altName...) + v.misc = append(v.misc, '[') + v.misc = strconv.AppendInt(v.misc, i64, 10) + v.misc = append(v.misc, ']') + + reusableCF.altName = string(v.misc) + } + v.traverseField(ctx, parent, current.Index(i), ns, structNs, reusableCF, ct) + } + + case reflect.Map: + + var pv string + reusableCF := &cField{} + + for _, key := range current.MapKeys() { + + pv = fmt.Sprintf("%v", key.Interface()) + + v.misc = append(v.misc[0:0], cf.name...) + v.misc = append(v.misc, '[') + v.misc = append(v.misc, pv...) + v.misc = append(v.misc, ']') + + reusableCF.name = string(v.misc) + + if cf.namesEqual { + reusableCF.altName = reusableCF.name + } else { + v.misc = append(v.misc[0:0], cf.altName...) + v.misc = append(v.misc, '[') + v.misc = append(v.misc, pv...) + v.misc = append(v.misc, ']') + + reusableCF.altName = string(v.misc) + } + + if ct != nil && ct.typeof == typeKeys && ct.keys != nil { + v.traverseField(ctx, parent, key, ns, structNs, reusableCF, ct.keys) + // can be nil when just keys being validated + if ct.next != nil { + v.traverseField(ctx, parent, current.MapIndex(key), ns, structNs, reusableCF, ct.next) + } + } else { + v.traverseField(ctx, parent, current.MapIndex(key), ns, structNs, reusableCF, ct) + } + } + + default: + // throw error, if not a slice or map then should not have gotten here + // bad dive tag + panic("dive error! can't dive on a non slice or map") + } + + return + + case typeOr: + + v.misc = v.misc[0:0] + + for { + + // set Field Level fields + v.slflParent = parent + v.flField = current + v.cf = cf + v.ct = ct + + if ct.fn(ctx, v) { + if ct.isBlockEnd { + ct = ct.next + continue OUTER + } + + // drain rest of the 'or' values, then continue or leave + for { + + ct = ct.next + + if ct == nil { + return + } + + if ct.typeof != typeOr { + continue OUTER + } + + if ct.isBlockEnd { + ct = ct.next + continue OUTER + } + } + } + + v.misc = append(v.misc, '|') + v.misc = append(v.misc, ct.tag...) + + if ct.hasParam { + v.misc = append(v.misc, '=') + v.misc = append(v.misc, ct.param...) + } + + if ct.isBlockEnd || ct.next == nil { + // if we get here, no valid 'or' value and no more tags + v.str1 = string(append(ns, cf.altName...)) + + if v.v.hasTagNameFunc { + v.str2 = string(append(structNs, cf.name...)) + } else { + v.str2 = v.str1 + } + + if ct.hasAlias { + + v.errs = append(v.errs, + &fieldError{ + v: v.v, + tag: ct.aliasTag, + actualTag: ct.actualAliasTag, + ns: v.str1, + structNs: v.str2, + fieldLen: uint8(len(cf.altName)), + structfieldLen: uint8(len(cf.name)), + value: current.Interface(), + param: ct.param, + kind: kind, + typ: typ, + }, + ) + + } else { + + tVal := string(v.misc)[1:] + + v.errs = append(v.errs, + &fieldError{ + v: v.v, + tag: tVal, + actualTag: tVal, + ns: v.str1, + structNs: v.str2, + fieldLen: uint8(len(cf.altName)), + structfieldLen: uint8(len(cf.name)), + value: current.Interface(), + param: ct.param, + kind: kind, + typ: typ, + }, + ) + } + + return + } + + ct = ct.next + } + + default: + + // set Field Level fields + v.slflParent = parent + v.flField = current + v.cf = cf + v.ct = ct + + if !ct.fn(ctx, v) { + + v.str1 = string(append(ns, cf.altName...)) + + if v.v.hasTagNameFunc { + v.str2 = string(append(structNs, cf.name...)) + } else { + v.str2 = v.str1 + } + + v.errs = append(v.errs, + &fieldError{ + v: v.v, + tag: ct.aliasTag, + actualTag: ct.tag, + ns: v.str1, + structNs: v.str2, + fieldLen: uint8(len(cf.altName)), + structfieldLen: uint8(len(cf.name)), + value: current.Interface(), + param: ct.param, + kind: kind, + typ: typ, + }, + ) + + return + } + ct = ct.next + } + } + +} diff --git a/vendor/github.com/go-playground/validator/v10/validator_instance.go b/vendor/github.com/go-playground/validator/v10/validator_instance.go new file mode 100644 index 0000000000..9493da491a --- /dev/null +++ b/vendor/github.com/go-playground/validator/v10/validator_instance.go @@ -0,0 +1,699 @@ +package validator + +import ( + "context" + "errors" + "fmt" + "reflect" + "strings" + "sync" + "time" + + ut "github.com/go-playground/universal-translator" +) + +const ( + defaultTagName = "validate" + utf8HexComma = "0x2C" + utf8Pipe = "0x7C" + tagSeparator = "," + orSeparator = "|" + tagKeySeparator = "=" + structOnlyTag = "structonly" + noStructLevelTag = "nostructlevel" + omitempty = "omitempty" + isdefault = "isdefault" + requiredWithoutAllTag = "required_without_all" + requiredWithoutTag = "required_without" + requiredWithTag = "required_with" + requiredWithAllTag = "required_with_all" + requiredIfTag = "required_if" + requiredUnlessTag = "required_unless" + excludedWithoutAllTag = "excluded_without_all" + excludedWithoutTag = "excluded_without" + excludedWithTag = "excluded_with" + excludedWithAllTag = "excluded_with_all" + excludedIfTag = "excluded_if" + excludedUnlessTag = "excluded_unless" + skipValidationTag = "-" + diveTag = "dive" + keysTag = "keys" + endKeysTag = "endkeys" + requiredTag = "required" + namespaceSeparator = "." + leftBracket = "[" + rightBracket = "]" + restrictedTagChars = ".[],|=+()`~!@#$%^&*\\\"/?<>{}" + restrictedAliasErr = "Alias '%s' either contains restricted characters or is the same as a restricted tag needed for normal operation" + restrictedTagErr = "Tag '%s' either contains restricted characters or is the same as a restricted tag needed for normal operation" +) + +var ( + timeDurationType = reflect.TypeOf(time.Duration(0)) + timeType = reflect.TypeOf(time.Time{}) + + defaultCField = &cField{namesEqual: true} +) + +// FilterFunc is the type used to filter fields using +// StructFiltered(...) function. +// returning true results in the field being filtered/skiped from +// validation +type FilterFunc func(ns []byte) bool + +// CustomTypeFunc allows for overriding or adding custom field type handler functions +// field = field value of the type to return a value to be validated +// example Valuer from sql drive see https://golang.org/src/database/sql/driver/types.go?s=1210:1293#L29 +type CustomTypeFunc func(field reflect.Value) interface{} + +// TagNameFunc allows for adding of a custom tag name parser +type TagNameFunc func(field reflect.StructField) string + +type internalValidationFuncWrapper struct { + fn FuncCtx + runValidatinOnNil bool +} + +// Validate contains the validator settings and cache +type Validate struct { + tagName string + pool *sync.Pool + hasCustomFuncs bool + hasTagNameFunc bool + tagNameFunc TagNameFunc + structLevelFuncs map[reflect.Type]StructLevelFuncCtx + customFuncs map[reflect.Type]CustomTypeFunc + aliases map[string]string + validations map[string]internalValidationFuncWrapper + transTagFunc map[ut.Translator]map[string]TranslationFunc // map[]map[]TranslationFunc + rules map[reflect.Type]map[string]string + tagCache *tagCache + structCache *structCache +} + +// New returns a new instance of 'validate' with sane defaults. +// Validate is designed to be thread-safe and used as a singleton instance. +// It caches information about your struct and validations, +// in essence only parsing your validation tags once per struct type. +// Using multiple instances neglects the benefit of caching. +func New() *Validate { + + tc := new(tagCache) + tc.m.Store(make(map[string]*cTag)) + + sc := new(structCache) + sc.m.Store(make(map[reflect.Type]*cStruct)) + + v := &Validate{ + tagName: defaultTagName, + aliases: make(map[string]string, len(bakedInAliases)), + validations: make(map[string]internalValidationFuncWrapper, len(bakedInValidators)), + tagCache: tc, + structCache: sc, + } + + // must copy alias validators for separate validations to be used in each validator instance + for k, val := range bakedInAliases { + v.RegisterAlias(k, val) + } + + // must copy validators for separate validations to be used in each instance + for k, val := range bakedInValidators { + + switch k { + // these require that even if the value is nil that the validation should run, omitempty still overrides this behaviour + case requiredIfTag, requiredUnlessTag, requiredWithTag, requiredWithAllTag, requiredWithoutTag, requiredWithoutAllTag, + excludedIfTag, excludedUnlessTag, excludedWithTag, excludedWithAllTag, excludedWithoutTag, excludedWithoutAllTag: + _ = v.registerValidation(k, wrapFunc(val), true, true) + default: + // no need to error check here, baked in will always be valid + _ = v.registerValidation(k, wrapFunc(val), true, false) + } + } + + v.pool = &sync.Pool{ + New: func() interface{} { + return &validate{ + v: v, + ns: make([]byte, 0, 64), + actualNs: make([]byte, 0, 64), + misc: make([]byte, 32), + } + }, + } + + return v +} + +// SetTagName allows for changing of the default tag name of 'validate' +func (v *Validate) SetTagName(name string) { + v.tagName = name +} + +// ValidateMapCtx validates a map using a map of validation rules and allows passing of contextual +// validation validation information via context.Context. +func (v Validate) ValidateMapCtx(ctx context.Context, data map[string]interface{}, rules map[string]interface{}) map[string]interface{} { + errs := make(map[string]interface{}) + for field, rule := range rules { + if ruleObj, ok := rule.(map[string]interface{}); ok { + if dataObj, ok := data[field].(map[string]interface{}); ok { + err := v.ValidateMapCtx(ctx, dataObj, ruleObj) + if len(err) > 0 { + errs[field] = err + } + } else if dataObjs, ok := data[field].([]map[string]interface{}); ok { + for _, obj := range dataObjs { + err := v.ValidateMapCtx(ctx, obj, ruleObj) + if len(err) > 0 { + errs[field] = err + } + } + } else { + errs[field] = errors.New("The field: '" + field + "' is not a map to dive") + } + } else if ruleStr, ok := rule.(string); ok { + err := v.VarCtx(ctx, data[field], ruleStr) + if err != nil { + errs[field] = err + } + } + } + return errs +} + +// ValidateMap validates map data from a map of tags +func (v *Validate) ValidateMap(data map[string]interface{}, rules map[string]interface{}) map[string]interface{} { + return v.ValidateMapCtx(context.Background(), data, rules) +} + +// RegisterTagNameFunc registers a function to get alternate names for StructFields. +// +// eg. to use the names which have been specified for JSON representations of structs, rather than normal Go field names: +// +// validate.RegisterTagNameFunc(func(fld reflect.StructField) string { +// name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0] +// // skip if tag key says it should be ignored +// if name == "-" { +// return "" +// } +// return name +// }) +func (v *Validate) RegisterTagNameFunc(fn TagNameFunc) { + v.tagNameFunc = fn + v.hasTagNameFunc = true +} + +// RegisterValidation adds a validation with the given tag +// +// NOTES: +// - if the key already exists, the previous validation function will be replaced. +// - this method is not thread-safe it is intended that these all be registered prior to any validation +func (v *Validate) RegisterValidation(tag string, fn Func, callValidationEvenIfNull ...bool) error { + return v.RegisterValidationCtx(tag, wrapFunc(fn), callValidationEvenIfNull...) +} + +// RegisterValidationCtx does the same as RegisterValidation on accepts a FuncCtx validation +// allowing context.Context validation support. +func (v *Validate) RegisterValidationCtx(tag string, fn FuncCtx, callValidationEvenIfNull ...bool) error { + var nilCheckable bool + if len(callValidationEvenIfNull) > 0 { + nilCheckable = callValidationEvenIfNull[0] + } + return v.registerValidation(tag, fn, false, nilCheckable) +} + +func (v *Validate) registerValidation(tag string, fn FuncCtx, bakedIn bool, nilCheckable bool) error { + if len(tag) == 0 { + return errors.New("function Key cannot be empty") + } + + if fn == nil { + return errors.New("function cannot be empty") + } + + _, ok := restrictedTags[tag] + if !bakedIn && (ok || strings.ContainsAny(tag, restrictedTagChars)) { + panic(fmt.Sprintf(restrictedTagErr, tag)) + } + v.validations[tag] = internalValidationFuncWrapper{fn: fn, runValidatinOnNil: nilCheckable} + return nil +} + +// RegisterAlias registers a mapping of a single validation tag that +// defines a common or complex set of validation(s) to simplify adding validation +// to structs. +// +// NOTE: this function is not thread-safe it is intended that these all be registered prior to any validation +func (v *Validate) RegisterAlias(alias, tags string) { + + _, ok := restrictedTags[alias] + + if ok || strings.ContainsAny(alias, restrictedTagChars) { + panic(fmt.Sprintf(restrictedAliasErr, alias)) + } + + v.aliases[alias] = tags +} + +// RegisterStructValidation registers a StructLevelFunc against a number of types. +// +// NOTE: +// - this method is not thread-safe it is intended that these all be registered prior to any validation +func (v *Validate) RegisterStructValidation(fn StructLevelFunc, types ...interface{}) { + v.RegisterStructValidationCtx(wrapStructLevelFunc(fn), types...) +} + +// RegisterStructValidationCtx registers a StructLevelFuncCtx against a number of types and allows passing +// of contextual validation information via context.Context. +// +// NOTE: +// - this method is not thread-safe it is intended that these all be registered prior to any validation +func (v *Validate) RegisterStructValidationCtx(fn StructLevelFuncCtx, types ...interface{}) { + + if v.structLevelFuncs == nil { + v.structLevelFuncs = make(map[reflect.Type]StructLevelFuncCtx) + } + + for _, t := range types { + tv := reflect.ValueOf(t) + if tv.Kind() == reflect.Ptr { + t = reflect.Indirect(tv).Interface() + } + + v.structLevelFuncs[reflect.TypeOf(t)] = fn + } +} + +// RegisterStructValidationMapRules registers validate map rules. +// Be aware that map validation rules supersede those defined on a/the struct if present. +// +// NOTE: this method is not thread-safe it is intended that these all be registered prior to any validation +func (v *Validate) RegisterStructValidationMapRules(rules map[string]string, types ...interface{}) { + if v.rules == nil { + v.rules = make(map[reflect.Type]map[string]string) + } + + deepCopyRules := make(map[string]string) + for i, rule := range rules { + deepCopyRules[i] = rule + } + + for _, t := range types { + typ := reflect.TypeOf(t) + + if typ.Kind() == reflect.Ptr { + typ = typ.Elem() + } + + if typ.Kind() != reflect.Struct { + continue + } + v.rules[typ] = deepCopyRules + } +} + +// RegisterCustomTypeFunc registers a CustomTypeFunc against a number of types +// +// NOTE: this method is not thread-safe it is intended that these all be registered prior to any validation +func (v *Validate) RegisterCustomTypeFunc(fn CustomTypeFunc, types ...interface{}) { + + if v.customFuncs == nil { + v.customFuncs = make(map[reflect.Type]CustomTypeFunc) + } + + for _, t := range types { + v.customFuncs[reflect.TypeOf(t)] = fn + } + + v.hasCustomFuncs = true +} + +// RegisterTranslation registers translations against the provided tag. +func (v *Validate) RegisterTranslation(tag string, trans ut.Translator, registerFn RegisterTranslationsFunc, translationFn TranslationFunc) (err error) { + + if v.transTagFunc == nil { + v.transTagFunc = make(map[ut.Translator]map[string]TranslationFunc) + } + + if err = registerFn(trans); err != nil { + return + } + + m, ok := v.transTagFunc[trans] + if !ok { + m = make(map[string]TranslationFunc) + v.transTagFunc[trans] = m + } + + m[tag] = translationFn + + return +} + +// Struct validates a structs exposed fields, and automatically validates nested structs, unless otherwise specified. +// +// It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise. +// You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors. +func (v *Validate) Struct(s interface{}) error { + return v.StructCtx(context.Background(), s) +} + +// StructCtx validates a structs exposed fields, and automatically validates nested structs, unless otherwise specified +// and also allows passing of context.Context for contextual validation information. +// +// It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise. +// You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors. +func (v *Validate) StructCtx(ctx context.Context, s interface{}) (err error) { + + val := reflect.ValueOf(s) + top := val + + if val.Kind() == reflect.Ptr && !val.IsNil() { + val = val.Elem() + } + + if val.Kind() != reflect.Struct || val.Type().ConvertibleTo(timeType) { + return &InvalidValidationError{Type: reflect.TypeOf(s)} + } + + // good to validate + vd := v.pool.Get().(*validate) + vd.top = top + vd.isPartial = false + // vd.hasExcludes = false // only need to reset in StructPartial and StructExcept + + vd.validateStruct(ctx, top, val, val.Type(), vd.ns[0:0], vd.actualNs[0:0], nil) + + if len(vd.errs) > 0 { + err = vd.errs + vd.errs = nil + } + + v.pool.Put(vd) + + return +} + +// StructFiltered validates a structs exposed fields, that pass the FilterFunc check and automatically validates +// nested structs, unless otherwise specified. +// +// It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise. +// You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors. +func (v *Validate) StructFiltered(s interface{}, fn FilterFunc) error { + return v.StructFilteredCtx(context.Background(), s, fn) +} + +// StructFilteredCtx validates a structs exposed fields, that pass the FilterFunc check and automatically validates +// nested structs, unless otherwise specified and also allows passing of contextual validation information via +// context.Context +// +// It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise. +// You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors. +func (v *Validate) StructFilteredCtx(ctx context.Context, s interface{}, fn FilterFunc) (err error) { + val := reflect.ValueOf(s) + top := val + + if val.Kind() == reflect.Ptr && !val.IsNil() { + val = val.Elem() + } + + if val.Kind() != reflect.Struct || val.Type().ConvertibleTo(timeType) { + return &InvalidValidationError{Type: reflect.TypeOf(s)} + } + + // good to validate + vd := v.pool.Get().(*validate) + vd.top = top + vd.isPartial = true + vd.ffn = fn + // vd.hasExcludes = false // only need to reset in StructPartial and StructExcept + + vd.validateStruct(ctx, top, val, val.Type(), vd.ns[0:0], vd.actualNs[0:0], nil) + + if len(vd.errs) > 0 { + err = vd.errs + vd.errs = nil + } + + v.pool.Put(vd) + + return +} + +// StructPartial validates the fields passed in only, ignoring all others. +// Fields may be provided in a namespaced fashion relative to the struct provided +// eg. NestedStruct.Field or NestedArrayField[0].Struct.Name +// +// It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise. +// You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors. +func (v *Validate) StructPartial(s interface{}, fields ...string) error { + return v.StructPartialCtx(context.Background(), s, fields...) +} + +// StructPartialCtx validates the fields passed in only, ignoring all others and allows passing of contextual +// validation validation information via context.Context +// Fields may be provided in a namespaced fashion relative to the struct provided +// eg. NestedStruct.Field or NestedArrayField[0].Struct.Name +// +// It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise. +// You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors. +func (v *Validate) StructPartialCtx(ctx context.Context, s interface{}, fields ...string) (err error) { + val := reflect.ValueOf(s) + top := val + + if val.Kind() == reflect.Ptr && !val.IsNil() { + val = val.Elem() + } + + if val.Kind() != reflect.Struct || val.Type().ConvertibleTo(timeType) { + return &InvalidValidationError{Type: reflect.TypeOf(s)} + } + + // good to validate + vd := v.pool.Get().(*validate) + vd.top = top + vd.isPartial = true + vd.ffn = nil + vd.hasExcludes = false + vd.includeExclude = make(map[string]struct{}) + + typ := val.Type() + name := typ.Name() + + for _, k := range fields { + + flds := strings.Split(k, namespaceSeparator) + if len(flds) > 0 { + + vd.misc = append(vd.misc[0:0], name...) + // Don't append empty name for unnamed structs + if len(vd.misc) != 0 { + vd.misc = append(vd.misc, '.') + } + + for _, s := range flds { + + idx := strings.Index(s, leftBracket) + + if idx != -1 { + for idx != -1 { + vd.misc = append(vd.misc, s[:idx]...) + vd.includeExclude[string(vd.misc)] = struct{}{} + + idx2 := strings.Index(s, rightBracket) + idx2++ + vd.misc = append(vd.misc, s[idx:idx2]...) + vd.includeExclude[string(vd.misc)] = struct{}{} + s = s[idx2:] + idx = strings.Index(s, leftBracket) + } + } else { + + vd.misc = append(vd.misc, s...) + vd.includeExclude[string(vd.misc)] = struct{}{} + } + + vd.misc = append(vd.misc, '.') + } + } + } + + vd.validateStruct(ctx, top, val, typ, vd.ns[0:0], vd.actualNs[0:0], nil) + + if len(vd.errs) > 0 { + err = vd.errs + vd.errs = nil + } + + v.pool.Put(vd) + + return +} + +// StructExcept validates all fields except the ones passed in. +// Fields may be provided in a namespaced fashion relative to the struct provided +// i.e. NestedStruct.Field or NestedArrayField[0].Struct.Name +// +// It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise. +// You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors. +func (v *Validate) StructExcept(s interface{}, fields ...string) error { + return v.StructExceptCtx(context.Background(), s, fields...) +} + +// StructExceptCtx validates all fields except the ones passed in and allows passing of contextual +// validation validation information via context.Context +// Fields may be provided in a namespaced fashion relative to the struct provided +// i.e. NestedStruct.Field or NestedArrayField[0].Struct.Name +// +// It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise. +// You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors. +func (v *Validate) StructExceptCtx(ctx context.Context, s interface{}, fields ...string) (err error) { + val := reflect.ValueOf(s) + top := val + + if val.Kind() == reflect.Ptr && !val.IsNil() { + val = val.Elem() + } + + if val.Kind() != reflect.Struct || val.Type().ConvertibleTo(timeType) { + return &InvalidValidationError{Type: reflect.TypeOf(s)} + } + + // good to validate + vd := v.pool.Get().(*validate) + vd.top = top + vd.isPartial = true + vd.ffn = nil + vd.hasExcludes = true + vd.includeExclude = make(map[string]struct{}) + + typ := val.Type() + name := typ.Name() + + for _, key := range fields { + + vd.misc = vd.misc[0:0] + + if len(name) > 0 { + vd.misc = append(vd.misc, name...) + vd.misc = append(vd.misc, '.') + } + + vd.misc = append(vd.misc, key...) + vd.includeExclude[string(vd.misc)] = struct{}{} + } + + vd.validateStruct(ctx, top, val, typ, vd.ns[0:0], vd.actualNs[0:0], nil) + + if len(vd.errs) > 0 { + err = vd.errs + vd.errs = nil + } + + v.pool.Put(vd) + + return +} + +// Var validates a single variable using tag style validation. +// eg. +// var i int +// validate.Var(i, "gt=1,lt=10") +// +// WARNING: a struct can be passed for validation eg. time.Time is a struct or +// if you have a custom type and have registered a custom type handler, so must +// allow it; however unforeseen validations will occur if trying to validate a +// struct that is meant to be passed to 'validate.Struct' +// +// It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise. +// You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors. +// validate Array, Slice and maps fields which may contain more than one error +func (v *Validate) Var(field interface{}, tag string) error { + return v.VarCtx(context.Background(), field, tag) +} + +// VarCtx validates a single variable using tag style validation and allows passing of contextual +// validation validation information via context.Context. +// eg. +// var i int +// validate.Var(i, "gt=1,lt=10") +// +// WARNING: a struct can be passed for validation eg. time.Time is a struct or +// if you have a custom type and have registered a custom type handler, so must +// allow it; however unforeseen validations will occur if trying to validate a +// struct that is meant to be passed to 'validate.Struct' +// +// It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise. +// You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors. +// validate Array, Slice and maps fields which may contain more than one error +func (v *Validate) VarCtx(ctx context.Context, field interface{}, tag string) (err error) { + if len(tag) == 0 || tag == skipValidationTag { + return nil + } + + ctag := v.fetchCacheTag(tag) + val := reflect.ValueOf(field) + vd := v.pool.Get().(*validate) + vd.top = val + vd.isPartial = false + vd.traverseField(ctx, val, val, vd.ns[0:0], vd.actualNs[0:0], defaultCField, ctag) + + if len(vd.errs) > 0 { + err = vd.errs + vd.errs = nil + } + v.pool.Put(vd) + return +} + +// VarWithValue validates a single variable, against another variable/field's value using tag style validation +// eg. +// s1 := "abcd" +// s2 := "abcd" +// validate.VarWithValue(s1, s2, "eqcsfield") // returns true +// +// WARNING: a struct can be passed for validation eg. time.Time is a struct or +// if you have a custom type and have registered a custom type handler, so must +// allow it; however unforeseen validations will occur if trying to validate a +// struct that is meant to be passed to 'validate.Struct' +// +// It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise. +// You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors. +// validate Array, Slice and maps fields which may contain more than one error +func (v *Validate) VarWithValue(field interface{}, other interface{}, tag string) error { + return v.VarWithValueCtx(context.Background(), field, other, tag) +} + +// VarWithValueCtx validates a single variable, against another variable/field's value using tag style validation and +// allows passing of contextual validation validation information via context.Context. +// eg. +// s1 := "abcd" +// s2 := "abcd" +// validate.VarWithValue(s1, s2, "eqcsfield") // returns true +// +// WARNING: a struct can be passed for validation eg. time.Time is a struct or +// if you have a custom type and have registered a custom type handler, so must +// allow it; however unforeseen validations will occur if trying to validate a +// struct that is meant to be passed to 'validate.Struct' +// +// It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise. +// You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors. +// validate Array, Slice and maps fields which may contain more than one error +func (v *Validate) VarWithValueCtx(ctx context.Context, field interface{}, other interface{}, tag string) (err error) { + if len(tag) == 0 || tag == skipValidationTag { + return nil + } + ctag := v.fetchCacheTag(tag) + otherVal := reflect.ValueOf(other) + vd := v.pool.Get().(*validate) + vd.top = otherVal + vd.isPartial = false + vd.traverseField(ctx, otherVal, reflect.ValueOf(field), vd.ns[0:0], vd.actualNs[0:0], defaultCField, ctag) + + if len(vd.errs) > 0 { + err = vd.errs + vd.errs = nil + } + v.pool.Put(vd) + return +} diff --git a/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/command/create.go b/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/command/create.go index d84b5bd9e8..400c1e1a7f 100644 --- a/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/command/create.go +++ b/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/command/create.go @@ -18,147 +18,79 @@ package command import ( "fmt" - "regexp" - "time" - "github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/common" "github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/metadata" "github.com/ory/viper" "github.com/spf13/cobra" + "os" ) type CreateCmdConfig struct { - // Quarkus project options - ProjectName string // Project name - Extesions string // List of extensions separated by "," to be add on the Quarkus project - - // Dependencies versions - DependenciesVersion metadata.DependenciesVersion + ProjectName string } func NewCreateCommand() *cobra.Command { var cmd = &cobra.Command{ Use: "create", - Short: "Create a Kogito Serverless Workflow project", + Short: "Creates a new SonataFlow project", Long: ` - Creates a Kogito Serverless Workflow project in the current directory. - It sets up a Quarkus project with minimal extensions to build a workflow - project. - The generated project has a "hello world" workflow.sw.json located on the - .//src/main/resources directory. - `, + Creates a Workflow file in the specified directory (new-project is the default). + + This SonataFlow project targets use cases requiring a single Serverless + Workflow file definition. + + Additionally, you can define the configurable parameters of your application in the + "application.properties" file (inside the root directory). + You can also store your spec files (i.e., Open API files) inside the "specs" folder. + `, Example: ` # Create a project in the local directory # By default the project is named "new-project" {{.Name}} create - # Create a project with an specfic name + # Create a project with an specific name {{.Name}} create --name myproject - - # Create a project with additional extensions - # You can add multiple extensions by separating them with a comma - {{.Name}} create --extensions kogito-addons-quarkus-persistence-postgresql,quarkus-core `, SuggestFor: []string{"vreate", "creaet", "craete", "new"}, - PreRunE: common.BindEnv("name", "extension", "quarkus-platform-group-id", "quarkus-version"), + PreRunE: common.BindEnv("name"), } cmd.RunE = func(cmd *cobra.Command, args []string) error { - return runCreate(cmd, args) + cfg, err := runCreateCmdConfig() + if err != nil { + return fmt.Errorf("initializing create config: %w", err) + } + return runCreate(cfg) } - quarkusDepedencies := metadata.ResolveQuarkusDependencies() - cmd.Flags().StringP("name", "n", "new-project", "Project name created in the current directory.") - cmd.Flags().StringP("extension", "e", "", "Project custom Maven extensions, separated with a comma.") - cmd.Flags().StringP("quarkus-platform-group-id", "G", quarkusDepedencies.QuarkusPlatformGroupId, "Quarkus group id to be set in the project.") - cmd.Flags().StringP("quarkus-version", "V", quarkusDepedencies.QuarkusVersion, "Quarkus version to be set in the project.") cmd.SetHelpFunc(common.DefaultTemplatedHelp) return cmd } -func runCreate(cmd *cobra.Command, args []string) error { - start := time.Now() - - cfg, err := runCreateCmdConfig(cmd) - if err != nil { - return fmt.Errorf("initializing create config: %w", err) - } +func runCreate(cfg CreateCmdConfig) error { + fmt.Println("🛠️ Creating SonataFlow project") - if err := common.CheckJavaDependencies(); err != nil { - return err + if err := os.Mkdir(cfg.ProjectName, os.ModePerm); err != nil { + return fmt.Errorf("❌ ERROR: Error creating project directory: %w", err) } - if err = runCreateProject(cfg); err != nil { - return err + workflowPath := fmt.Sprintf("./%s/%s", cfg.ProjectName, metadata.WorkflowSwJson) + if err := common.CreateWorkflow(workflowPath); err != nil { + return fmt.Errorf("❌ ERROR: Error creating workflow file: %w", err) } - workflowFilePath := fmt.Sprintf("./%s/src/main/resources/%s", cfg.ProjectName, metadata.WORKFLOW_SW_JSON) - CreateWorkflow(workflowFilePath) + fmt.Println("🎉 SonataFlow project successfully created") - finish := time.Since(start) - fmt.Printf("🚀 Project creation took: %s \n", finish) return nil -} - -func runCreateProject(cfg CreateCmdConfig) (err error) { - if err = checkProjectName(cfg.ProjectName); err != nil { - return err - } - exists, err := common.CheckIfDirExists(cfg.ProjectName) - if err != nil || exists { - return fmt.Errorf("directory with name \"%s\" already exists: %w", cfg.ProjectName, err) - } - create := common.ExecCommand( - "mvn", - fmt.Sprintf("%s:%s:%s:create", cfg.DependenciesVersion.QuarkusPlatformGroupId, metadata.QUARKUS_MAVEN_PLUGIN, cfg.DependenciesVersion.QuarkusVersion), - "-DprojectGroupId=org.acme", - "-DnoCode", - fmt.Sprintf("-DplatformVersion=%s", cfg.DependenciesVersion.QuarkusVersion), - fmt.Sprintf("-DprojectArtifactId=%s", cfg.ProjectName), - fmt.Sprintf("-Dextensions=%s", cfg.Extesions)) - - fmt.Println("Creating a Kogito Serverless Workflow project...") - - if err := common.RunCommand( - create, - "create", - ); err != nil { - return err - } - return -} - -func checkProjectName(name string) (err error) { - matched, err := regexp.MatchString(`^([_\-\.a-zA-Z0-9]+)$`, name) - if !matched { - fmt.Printf("The project name (\"%s\") contains invalid characters. Valid characters are alphanumeric (A-Za-z), underscore, dash and dot.", name) - err = fmt.Errorf("invalid project name") - } - return } -// runCreateCmdConfig returns the configs from the current execution context -func runCreateCmdConfig(cmd *cobra.Command) (cfg CreateCmdConfig, err error) { - quarkusPlatformGroupId := viper.GetString("quarkus-platform-group-id") - quarkusVersion := viper.GetString("quarkus-version") +func runCreateCmdConfig() (cfg CreateCmdConfig, err error) { cfg = CreateCmdConfig{ ProjectName: viper.GetString("name"), - Extesions: fmt.Sprintf("%s,%s,%s,%s,%s", - metadata.KOGITO_QUARKUS_SERVERLESS_WORKFLOW_EXTENSION, - metadata.KOGITO_ADDONS_QUARKUS_KNATIVE_EVENTING_EXTENSION, - metadata.QUARKUS_KUBERNETES_EXTENSION, - metadata.QUARKUS_RESTEASY_JACKSON_EXTENSION, - viper.GetString("extension"), - ), - - DependenciesVersion: metadata.DependenciesVersion{ - QuarkusPlatformGroupId: quarkusPlatformGroupId, - QuarkusVersion: quarkusVersion, - }, } - return + return cfg, nil } diff --git a/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/command/deploy.go b/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/command/deploy.go index c31325cafa..577e14a792 100644 --- a/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/command/deploy.go +++ b/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/command/deploy.go @@ -18,114 +18,122 @@ package command import ( "fmt" - "time" "github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/common" "github.com/ory/viper" "github.com/spf13/cobra" + "os" + "path" ) -type DeployCmdConfig struct { - // Deploy options - Path string // service name -} - func NewDeployCommand() *cobra.Command { var cmd = &cobra.Command{ Use: "deploy", - Short: "Deploy a Kogito Serverless Workflow project", + Short: "Deploy a SonataFlow project on Kubernetes via SonataFlow Operator", Long: ` - Deploys a Kogito Serverless Workflow project in the current directory. - By default, this command uses the ./target/kubernetes folder to find - the deployment files generated in the build process. The build step - is required before using the deploy command. - - Before you use the deploy command, ensure that your cluster have - access to the build output image. - `, + Deploy a SonataFlow project in Kubernetes via the SonataFlow Operator. + `, Example: ` - # Deploy the workflow from the current directory's project. - # Deploy as Knative service. - {{.Name}} deploy - - # Specify the path of the directory containing the "knative.yml" - {{.Name}} deploy --path ./kubernetes + # Deploy the workflow project from the current directory's project. + # You must provide target namespace. + {{.Name}} deploy --namespace + # Persist the generated Kubernetes manifests on a given path and deploy the + # workflow from the current directory's project. + {{.Name}} deploy --manifestPath= + # Specify a custom support files folder. + {{.Name}} deploy --supportFiles= `, + + PreRunE: common.BindEnv("namespace", "manifestPath", "supportFilesFolder"), SuggestFor: []string{"delpoy", "deplyo"}, - PreRunE: common.BindEnv("path"), } cmd.RunE = func(cmd *cobra.Command, args []string) error { - return runDeploy(cmd, args) + return runDeployUndeploy(cmd, args) } - cmd.Flags().StringP("path", "p", "./target/kubernetes", fmt.Sprintf("%s path to knative deployment files", cmd.Name())) + cmd.Flags().StringP("namespace", "n", "", "Target namespace of your deployment.") + cmd.Flags().StringP("manifestPath", "c", "", "Target directory of your generated Kubernetes manifests.") + cmd.Flags().StringP("supportFilesFolder", "s", "", "Specify a custom support files folder") cmd.SetHelpFunc(common.DefaultTemplatedHelp) return cmd } -func runDeploy(cmd *cobra.Command, args []string) error { - start := time.Now() +func runDeployUndeploy(cmd *cobra.Command, args []string) error { cfg, err := runDeployCmdConfig(cmd) + //temp dir cleanup + defer func(cfg *DeployUndeployCmdConfig) { + if cfg.TempDir != "" { + if err := os.RemoveAll(cfg.TempDir); err != nil { + fmt.Errorf("❌ ERROR: failed to remove temp dir: %v", err) + } + } + }(&cfg) + if err != nil { - return fmt.Errorf("initializing deploy config: %w", err) + return fmt.Errorf("❌ ERROR: initializing deploy config: %w", err) } - if err = common.CheckKubectl(); err != nil { - return err + fmt.Println("🛠️️ Deploy a SonataFlow project on Kubernetes via the SonataFlow Operator...") + + if err := checkEnvironment(&cfg); err != nil { + return fmt.Errorf("❌ ERROR: checking deploy environment: %w", err) } - if _, err = deployKnativeServiceAndEventingBindings(cfg); err != nil { - return err + if err := generateManifests(&cfg); err != nil { + return fmt.Errorf("❌ ERROR: generating deploy environment: %w", err) } - finish := time.Since(start) - fmt.Printf("🚀 Deploy took: %s \n", finish) + if err = deploy(&cfg); err != nil { + return fmt.Errorf("❌ ERROR: applying deploy: %w", err) + } + + fmt.Printf("\n🎉 SonataFlow project successfully deployed.\n") + return nil } -func deployKnativeServiceAndEventingBindings(cfg DeployCmdConfig) (bool, error) { - isKnativeEventingBindingsCreated := false - createService := common.ExecCommand("kubectl", "apply", "-f", fmt.Sprintf("%s/knative.yml", cfg.Path)) - if err := common.RunCommand( - createService, - "deploy", - ); err != nil { - fmt.Println("❌ Deploy failed, Knative service was not created.") - return isKnativeEventingBindingsCreated, err +func deploy(cfg *DeployUndeployCmdConfig) error { + fmt.Printf("🛠 Deploying your SonataFlow project in namespace %s\n", cfg.NameSpace) + + manifestExtension := []string{".yaml"} + + files, err := common.FindFilesWithExtensions(cfg.ManifestPath, manifestExtension) + if err != nil { + return fmt.Errorf("❌ ERROR: failed to get manifest directory and files: %w", err) } - fmt.Println("✅ Knative service sucessufully created") - - // Check if kogito.yml file exists - if exists, err := checkIfKogitoFileExists(cfg); exists && err == nil { - deploy := common.ExecCommand("kubectl", "apply", "-f", fmt.Sprintf("%s/kogito.yml", cfg.Path)) - if err := common.RunCommand( - deploy, - "deploy", - ); err != nil { - fmt.Println("❌ Deploy failed, Knative Eventing binding was not created.") - return isKnativeEventingBindingsCreated, err + for _, file := range files { + if err = common.ExecuteKubectlApply(file, cfg.NameSpace); err != nil { + return fmt.Errorf("❌ ERROR: failed to deploy manifest %s, %w", file, err) } - isKnativeEventingBindingsCreated = true - fmt.Println("✅ Knative Eventing bindings successfully created") + fmt.Printf(" - ✅ Manifest %s successfully deployed in namespace %s\n", path.Base(file), cfg.NameSpace) + } - return isKnativeEventingBindingsCreated, nil + return nil } -func runDeployCmdConfig(cmd *cobra.Command) (cfg DeployCmdConfig, err error) { - cfg = DeployCmdConfig{ - Path: viper.GetString("path"), +func runDeployCmdConfig(cmd *cobra.Command) (cfg DeployUndeployCmdConfig, err error) { + + cfg = DeployUndeployCmdConfig{ + NameSpace: viper.GetString("namespace"), + SupportFileFolder: viper.GetString("supportFilesFolder"), + ManifestPath: viper.GetString("manifestPath"), } - return -} -func checkIfKogitoFileExists(cfg DeployCmdConfig) (bool, error) { - if _, err := common.FS.Stat(fmt.Sprintf("%s/kogito.yml", cfg.Path)); err == nil { - return true, nil - } else { - return false, err + if len(cfg.SupportFileFolder) == 0 { + dir, err := os.Getwd() + cfg.SupportFileFolder = dir + "/specs" + if err != nil { + return cfg, fmt.Errorf("❌ ERROR: failed to get current directory: %w", err) + } } + //setup manifest path + if err := setupConfigManifestPath(&cfg); err != nil { + return cfg, err + } + + return cfg, nil } diff --git a/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/command/deploy_undeploy_common.go b/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/command/deploy_undeploy_common.go new file mode 100644 index 0000000000..4a1fa6f641 --- /dev/null +++ b/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/command/deploy_undeploy_common.go @@ -0,0 +1,191 @@ +/* + * Copyright 2023 Red Hat, Inc. and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package command + +import ( + "fmt" + "github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/common" + "github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/metadata" + "github.com/kiegroup/kogito-serverless-operator/workflowproj" + "os" + "path/filepath" +) + +type DeployUndeployCmdConfig struct { + NameSpace string + KubectlContext string + SonataFlowFile string + ManifestPath string + TempDir string + ApplicationPropertiesPath string + SupportFileFolder string + SupportFilesPath []string +} + +func checkEnvironment(cfg *DeployUndeployCmdConfig) error { + fmt.Println("\n🔎 Checking your environment...") + + if err := common.CheckKubectl(); err != nil { + return err + } + + if ctx, err := common.CheckKubectlContext(); err != nil { + return err + } else { + cfg.KubectlContext = ctx + } + + //setup namespace + if len(cfg.NameSpace) == 0 { + if defaultNamespace, err := common.GetKubectlNamespace(); err == nil { + cfg.NameSpace = defaultNamespace + } else { + return err + } + } + + fmt.Println("🔎 Checking if the SonataFlow Operator is correctly installed...") + if err := common.CheckOperatorInstalled(); err != nil { + return err + } + + return nil +} + +func generateManifests(cfg *DeployUndeployCmdConfig) error { + fmt.Println("\n🛠️ Generating your manifests...") + fmt.Println("🔍 Looking for your SonataFlow files...") + if file, err := findSonataFlowFile(); err != nil { + return err + } else { + cfg.SonataFlowFile = file + } + fmt.Printf(" - ✅ SonataFlow file found: %s\n", cfg.SonataFlowFile) + + fmt.Println("🔍 Looking for your configuration support files...") + + dir, err := os.Getwd() + if err != nil { + return fmt.Errorf("❌ ERROR: failed to get current directory: %w", err) + } + + applicationPropertiesPath := findApplicationPropertiesPath(dir) + if applicationPropertiesPath != "" { + cfg.ApplicationPropertiesPath = applicationPropertiesPath + fmt.Printf(" - ✅ Properties file found: %s\n", cfg.ApplicationPropertiesPath) + } + + extensions := []string{".json", ".yaml", ".yml"} + + files, err := common.FindFilesWithExtensions(cfg.SupportFileFolder, extensions) + if err != nil { + return fmt.Errorf("❌ ERROR: failed to get current directory: %w", err) + } + cfg.SupportFilesPath = files + for _, file := range cfg.SupportFilesPath { + fmt.Printf(" - ✅ Support file found: %s\n", file) + } + + fmt.Println("🚚️ Generating your Kubernetes manifest files..") + + swfFile, err := common.MustGetFile(cfg.SonataFlowFile) + if err != nil { + return err + } + + handler := workflowproj.New(cfg.NameSpace).WithWorkflow(swfFile) + if cfg.ApplicationPropertiesPath != "" { + appIO, err := common.MustGetFile(cfg.ApplicationPropertiesPath) + if err != nil { + return err + } + handler.WithAppProperties(appIO) + } + + for _, supportfile := range cfg.SupportFilesPath { + specIO, err := common.MustGetFile(supportfile) + if err != nil { + return err + } + handler.AddResource(filepath.Base(supportfile), specIO) + } + + _, err = handler.AsObjects() + if err != nil { + return err + } + + err = handler.SaveAsKubernetesManifests(cfg.ManifestPath) + if err != nil { + return err + } + + return nil +} + +func findApplicationPropertiesPath(directoryPath string) string { + filePath := filepath.Join(directoryPath, metadata.ApplicationProperties) + + fileInfo, err := os.Stat(filePath) + if err != nil || fileInfo.IsDir() { + return "" + } + + return filePath +} + +func findSonataFlowFile() (string, error) { + extensions := []string{metadata.YAMLExtension, metadata.YAMLExtensionShort, metadata.JSONExtension} + + dir, err := os.Getwd() + if err != nil { + return "", fmt.Errorf("❌ ERROR: failed to get current directory: %w", err) + } + + var matchingFiles []string + for _, ext := range extensions { + files, _ := filepath.Glob(filepath.Join(dir, "*."+ext)) + matchingFiles = append(matchingFiles, files...) + } + + switch len(matchingFiles) { + case 0: + return "", fmt.Errorf("❌ ERROR: no matching files found") + case 1: + return matchingFiles[0], nil + default: + return "", fmt.Errorf("❌ ERROR: multiple SonataFlow definition files found") + } +} + +func setupConfigManifestPath(cfg *DeployUndeployCmdConfig) error { + + if len(cfg.ManifestPath) == 0 { + tempDir, err := os.MkdirTemp("", "manifests") + if err != nil { + return fmt.Errorf("❌ ERROR: failed to create temporary directory: %w", err) + } + cfg.ManifestPath = tempDir + cfg.TempDir = tempDir + } else { + _, err := os.Stat(cfg.ManifestPath) + if err != nil { + return fmt.Errorf("❌ ERROR: cannot find or open directory %s : %w", cfg.ManifestPath, err) + } + } + return nil +} diff --git a/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/command/build.go b/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/command/quarkus/build.go similarity index 93% rename from vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/command/build.go rename to vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/command/quarkus/build.go index bd8a187b0c..bd89ee8b68 100644 --- a/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/command/build.go +++ b/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/command/quarkus/build.go @@ -1,5 +1,5 @@ /* - * Copyright 2022 Red Hat, Inc. and/or its affiliates. + * Copyright 2023 Red Hat, Inc. and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,23 +14,20 @@ * limitations under the License. */ -package command +package quarkus import ( "fmt" - "regexp" - "strconv" - "strings" - "time" - "github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/common" "github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/metadata" "github.com/ory/viper" "github.com/spf13/cobra" + "regexp" + "strconv" + "strings" ) type BuildCmdConfig struct { - // Image options Image string // full image name Registry string // image registry (overrides image name) Repository string // image repository (overrides image name) @@ -48,12 +45,12 @@ type BuildCmdConfig struct { func NewBuildCommand() *cobra.Command { var cmd = &cobra.Command{ Use: "build", - Short: "Build a Kogito Serverless Workflow project and generate a container image", + Short: "Build a Quarkus SonataFlow project and generate a container image", Long: ` - Builds a Kogito Serverless Workflow project in the current directory + Builds a Quarkus SonataFlow project in the current directory resulting in a container image. By default the resultant container image will have the project name. It can be - overriten with the --image or with others image options, see help for more information. + overridden with the --image or with others image options, see help for more information. During the build, a knative.yml file will be generated on the ./target/kubernetes folder. If your workflow uses eventing, an additional kogito.yml is also generated. @@ -92,7 +89,7 @@ func NewBuildCommand() *cobra.Command { } cmd.RunE = func(cmd *cobra.Command, args []string) error { - _, err := runBuild(cmd, args) + _, err := runBuild(cmd) return err } @@ -112,8 +109,8 @@ func NewBuildCommand() *cobra.Command { return cmd } -func runBuild(cmd *cobra.Command, args []string) (out string, err error) { - start := time.Now() +func runBuild(cmd *cobra.Command) (out string, err error) { + fmt.Println("🔨 Building your Quarkus SonataFlow project...") cfg, err := runBuildCmdConfig(cmd) if err != nil { @@ -147,8 +144,8 @@ func runBuild(cmd *cobra.Command, args []string) (out string, err error) { return } - finish := time.Since(start) - fmt.Printf("🚀 Build took: %s \n", finish) + fmt.Println("✅ Quarkus SonataFlow project successfully built") + return } @@ -192,13 +189,13 @@ func runAddExtension(cfg BuildCmdConfig) error { fmt.Printf(" - Adding Quarkus Jib extension\n") if err := common.RunExtensionCommand( "quarkus:remove-extension", - metadata.QUARKUS_CONTAINER_IMAGE_DOCKER, + metadata.QuarkusContainerImageDocker, ); err != nil { return err } if err := common.RunExtensionCommand( "quarkus:add-extension", - metadata.QUARKUS_CONTAINER_IMAGE_JIB, + metadata.QuarkusContainerImageJib, ); err != nil { return err } @@ -206,13 +203,13 @@ func runAddExtension(cfg BuildCmdConfig) error { fmt.Printf(" - Adding Quarkus Docker extension\n") if err := common.RunExtensionCommand( "quarkus:remove-extension", - metadata.QUARKUS_CONTAINER_IMAGE_JIB, + metadata.QuarkusContainerImageJib, ); err != nil { return err } if err := common.RunExtensionCommand( "quarkus:add-extension", - metadata.QUARKUS_CONTAINER_IMAGE_DOCKER, + metadata.QuarkusContainerImageDocker, ); err != nil { return err } @@ -312,7 +309,7 @@ func getImageConfig(cfg BuildCmdConfig) (string, string, string, string) { name = imageArray[2] } - var tag = metadata.DEFAULT_TAG + var tag = metadata.DefaultTag if len(cfg.Tag) > 0 { tag = cfg.Tag } else if len(imageTagArray) > 1 && len(imageTagArray[1]) > 0 { diff --git a/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/command/quarkus/convert.go b/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/command/quarkus/convert.go new file mode 100644 index 0000000000..2ea102bd5d --- /dev/null +++ b/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/command/quarkus/convert.go @@ -0,0 +1,234 @@ +/* + * Copyright 2022 Red Hat, Inc. and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package quarkus + +import ( + "fmt" + "github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/common" + "github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/metadata" + "github.com/ory/viper" + "github.com/spf13/cobra" + "io" + "os" + "path/filepath" + "strings" +) + +func NewConvertCommand() *cobra.Command { + var cmd = &cobra.Command{ + Use: "convert", + Short: "Convert a SonataFlow project to a Quarkus SonataFlow project", + Long: ` + Convert a SonataFlow project to a Quarkus SonataFlow Project. + `, + Example: ` + # Run the local directory + {{.Name}} quarkus convert + `, + SuggestFor: []string{"convert-to-quarkus"}, + PreRunE: common.BindEnv("extension", "quarkus-platform-group-id", "quarkus-version"), + } + + cmd.RunE = func(cmd *cobra.Command, args []string) error { + return runConvert() + } + + quarkusDependencies := metadata.ResolveQuarkusDependencies() + + cmd.Flags().StringP("extension", "e", "", "On Quarkus projects, setup project custom Maven extensions, separated with a comma.") + cmd.Flags().StringP("quarkus-platform-group-id", "G", quarkusDependencies.QuarkusPlatformGroupId, "On Quarkus projects, setup project group id.") + cmd.Flags().StringP("quarkus-version", "V", quarkusDependencies.QuarkusVersion, "On Quarkus projects, setup the project version.") + + cmd.SetHelpFunc(common.DefaultTemplatedHelp) + + return cmd +} + +func runConvert() error { + if common.IsSonataFlowProject() { + return convert() + } else if common.IsQuarkusSonataFlowProject() { + return fmt.Errorf("looks like you are already inside a Quarkus project, so no need to convert it") + } else { + return fmt.Errorf("cannot find SonataFlow project") + } +} + +func loadConvertCmdConfig() (cfg CreateQuarkusProjectConfig, err error) { + quarkusPlatformGroupId := viper.GetString("quarkus-platform-group-id") + quarkusVersion := viper.GetString("quarkus-version") + + cfg = CreateQuarkusProjectConfig{ + Extensions: fmt.Sprintf("%s,%s,%s,%s,%s,%s,%s,%s,%s", + metadata.KogitoQuarkusServerlessWorkflowExtension, + metadata.KogitoAddonsQuarkusKnativeEventingExtension, + metadata.QuarkusKubernetesExtension, + metadata.QuarkusResteasyJacksonExtension, + metadata.KogitoQuarkusServerlessWorkflowDevUi, + metadata.KogitoAddonsQuarkusSourceFiles, + metadata.KogitoDataIndexInMemory, + metadata.SmallryeHealth, + viper.GetString("extension"), + ), + DependenciesVersion: metadata.DependenciesVersion{ + QuarkusPlatformGroupId: quarkusPlatformGroupId, + QuarkusVersion: quarkusVersion, + }, + } + if cfg.ProjectName == "" { + dir, err := os.Getwd() + if err != nil { + dir = "project-name" + } + cfg.ProjectName = filepath.Base(dir) + } + return +} +func convert() error { + + cfg, err := loadConvertCmdConfig() + + if err != nil { + return fmt.Errorf("initializing create config: %w", err) + } + + if err := common.CheckJavaDependencies(); err != nil { + return err + } + + if err = runConvertProject(cfg); err != nil { + return err + } + + return nil +} + +func runConvertProject(cfg CreateQuarkusProjectConfig) (err error) { + + fmt.Println("🔨 Creating a Quarkus SonataFlow project...") + if err = CreateQuarkusProject(cfg); err != nil { + fmt.Println("❌ Error creating Quarkus project", err) + return err + } + + fmt.Println("🔨 Moving SonataFlow files to Quarkus SonataFlow project...") + rootFolder, err := os.Getwd() + if err != nil { + return err + } + + if err := moveSWFFilesToQuarkusProject(cfg, rootFolder); err != nil { + return err + } + + generatedQuarkusProjectPath := rootFolder + "/" + cfg.ProjectName + + if err := copyDir(generatedQuarkusProjectPath, rootFolder); err != nil { + fmt.Println("❌ Error migrating Quarkus SonataFlow project files", err) + return err + } + if err := os.RemoveAll(generatedQuarkusProjectPath); err != nil { + fmt.Println("❌ Error migrating Quarkus SonataFlow project", err) + return err + } + + fmt.Println("✅ Quarkus SonataFlow project successfully created") + + return nil +} + +func moveSWFFilesToQuarkusProject(cfg CreateQuarkusProjectConfig, rootFolder string) error { + targetFolder := filepath.Join(rootFolder, cfg.ProjectName+"/src/main/resources") + + // ensure target directory exists + err := os.MkdirAll(targetFolder, os.ModePerm) + if err != nil { + return err + } + + files, err := os.ReadDir(rootFolder) + if err != nil { + return err + } + + for _, file := range files { + // Move *.sw.yaml, *.sw.json, application.properties to target + if strings.HasSuffix(file.Name(), ".sw.yaml") || strings.HasSuffix(file.Name(), ".sw.json") || file.Name() == "application.properties" { + oldPath := filepath.Join(rootFolder, file.Name()) + newPath := filepath.Join(targetFolder, file.Name()) + if err := os.Rename(oldPath, newPath); err != nil { + return fmt.Errorf("error moving file %s: %w", oldPath, err) + } + } + + // Move /specs directory to target + if file.IsDir() && file.Name() == "specs" { + oldPath := filepath.Join(rootFolder, file.Name()) + newPath := filepath.Join(targetFolder, file.Name()) + if err := os.Rename(oldPath, newPath); err != nil { + return fmt.Errorf("error moving directory %s: %w", oldPath, err) + } + } + } + return nil +} + +func copyFile(src, dst string) error { + srcFile, err := os.Open(src) + if err != nil { + return err + } + defer srcFile.Close() + + dstFile, err := os.Create(dst) + if err != nil { + return err + } + defer dstFile.Close() + + _, err = io.Copy(dstFile, srcFile) + if err != nil { + return err + } + + return nil +} + +func copyDir(src, dst string) error { + err := filepath.Walk(src, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + + dstPath := filepath.Join(dst, path[len(src):]) + if info.IsDir() { + err = os.MkdirAll(dstPath, info.Mode()) + if err != nil { + return err + } + } else { + err = copyFile(path, dstPath) + if err != nil { + return err + } + } + + return nil + }) + + return err +} diff --git a/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/command/quarkus/create.go b/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/command/quarkus/create.go new file mode 100644 index 0000000000..0eafc114a2 --- /dev/null +++ b/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/command/quarkus/create.go @@ -0,0 +1,151 @@ +/* + * Copyright 2022 Red Hat, Inc. and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package quarkus + +import ( + "fmt" + "github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/common" + "github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/metadata" + "github.com/ory/viper" + "github.com/spf13/cobra" +) + +func NewCreateCommand() *cobra.Command { + var cmd = &cobra.Command{ + Use: "create", + Short: "Create a Quarkus SonataFlow project", + Long: ` + Creates a Quarkus SonataFlow project in the current directory. + It sets up a Quarkus project with minimal extensions to build a workflow + project. + The generated project has a "hello world" workflow.sw.json located on the + .//src/main/resources directory. + `, + Example: ` + # Create a project in the local directory + # By default the project is named "new-project" + {{.Name}} create + + # Create a project with an specific name + {{.Name}} create --name myproject + + # Create a project with additional extensions + # You can add multiple extensions by separating them with a comma + {{.Name}} create --extensions kogito-addons-quarkus-persistence-postgresql,quarkus-core + `, + SuggestFor: []string{"vreate", "creaet", "craete", "new"}, + PreRunE: common.BindEnv("name", "extension", "quarkus-platform-group-id", "quarkus-version"), + } + + cmd.RunE = func(cmd *cobra.Command, args []string) error { + return runCreate() + } + + quarkusDependencies := metadata.ResolveQuarkusDependencies() + + cmd.Flags().StringP("name", "n", "new-project", "Project name created in the current directory.") + cmd.Flags().StringP("extension", "e", "", "On Quarkus projects, setup project custom Maven extensions, separated with a comma.") + cmd.Flags().StringP("quarkus-platform-group-id", "G", quarkusDependencies.QuarkusPlatformGroupId, "On Quarkus projects, setup project group id.") + cmd.Flags().StringP("quarkus-version", "V", quarkusDependencies.QuarkusVersion, "On Quarkus projects, setup the project version.") + cmd.SetHelpFunc(common.DefaultTemplatedHelp) + + return cmd +} + +func runCreate() error { + cfg, err := runCreateCmdConfig() + if err != nil { + return fmt.Errorf("initializing create config: %w", err) + } + + exists, err := common.CheckIfDirExists(cfg.ProjectName) + if exists { + return fmt.Errorf("directory with name \"%s\" already exists", cfg.ProjectName) + } + if err != nil { + return fmt.Errorf("directory with name \"%s\" already exists: %w", cfg.ProjectName, err) + } + + if err := common.CheckJavaDependencies(); err != nil { + return err + } + + fmt.Println("🛠️ Creating a Quarkus SonataFlow project...") + if err = CreateQuarkusProject(cfg); err != nil { + fmt.Println("❌ ERROR: creating Quarkus SonataFlow project", err) + return err + } + + workflowFilePath := fmt.Sprintf("./%s/src/main/resources/%s", cfg.ProjectName, metadata.WorkflowSwJson) + common.CreateWorkflow(workflowFilePath) + + fmt.Println("🎉 Quarkus SonataFlow project successfully created") + return nil +} + +func runCreateProject(cfg CreateQuarkusProjectConfig) (err error) { + if err = common.CheckProjectName(cfg.ProjectName); err != nil { + return err + } + exists, err := common.CheckIfDirExists(cfg.ProjectName) + if err != nil || exists { + return fmt.Errorf("directory with name \"%s\" already exists: %w", cfg.ProjectName, err) + } + + create := common.ExecCommand( + "mvn", + fmt.Sprintf("%s:%s:%s:create", cfg.DependenciesVersion.QuarkusPlatformGroupId, metadata.QuarkusMavenPlugin, cfg.DependenciesVersion.QuarkusVersion), + "-DprojectGroupId=org.acme", + "-DnoCode", + fmt.Sprintf("-DplatformVersion=%s", cfg.DependenciesVersion.QuarkusVersion), + fmt.Sprintf("-DprojectArtifactId=%s", cfg.ProjectName), + fmt.Sprintf("-Dextensions=%s", cfg.Extensions)) + + fmt.Println("Creating a Quarkus SonataFlow project...") + + if err := common.RunCommand( + create, + "create", + ); err != nil { + return err + } + return +} + +func runCreateCmdConfig() (cfg CreateQuarkusProjectConfig, err error) { + quarkusPlatformGroupId := viper.GetString("quarkus-platform-group-id") + quarkusVersion := viper.GetString("quarkus-version") + + cfg = CreateQuarkusProjectConfig{ + ProjectName: viper.GetString("name"), + Extensions: fmt.Sprintf("%s,%s,%s,%s,%s,%s,%s,%s", + metadata.KogitoQuarkusServerlessWorkflowExtension, + metadata.KogitoAddonsQuarkusKnativeEventingExtension, + metadata.QuarkusKubernetesExtension, + metadata.QuarkusResteasyJacksonExtension, + metadata.KogitoQuarkusServerlessWorkflowDevUi, + metadata.KogitoAddonsQuarkusSourceFiles, + metadata.SmallryeHealth, + viper.GetString("extension"), + ), + DependenciesVersion: metadata.DependenciesVersion{ + QuarkusPlatformGroupId: quarkusPlatformGroupId, + QuarkusVersion: quarkusVersion, + }, + } + return +} diff --git a/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/command/quarkus/deploy.go b/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/command/quarkus/deploy.go new file mode 100644 index 0000000000..6027058617 --- /dev/null +++ b/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/command/quarkus/deploy.go @@ -0,0 +1,128 @@ +/* + * Copyright 2022 Red Hat, Inc. and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package quarkus + +import ( + "fmt" + "github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/common" + "github.com/ory/viper" + "github.com/spf13/cobra" +) + +type DeployCmdConfig struct { + Path string // service name +} + +func NewDeployCommand() *cobra.Command { + var cmd = &cobra.Command{ + Use: "deploy", + Short: "Deploy a Quarkus SonataFlow project", + Long: ` + Deploys a Quarkus SonataFlow project in the current directory. + By default, this command uses the ./target/kubernetes folder to find + the deployment files generated in the build process. The build step + is required before using the deploy command. + + Before you use the deploy command, ensure that your cluster have + access to the build output image. + `, + Example: ` + # Deploy the workflow from the current directory's project. + # Deploy as Knative service. + {{.Name}} deploy + + # Specify the path of the directory containing the "knative.yml" + {{.Name}} deploy --path ./kubernetes + `, + SuggestFor: []string{"delpoy", "deplyo"}, + PreRunE: common.BindEnv("path"), + } + + cmd.RunE = func(cmd *cobra.Command, args []string) error { + return runDeploy(cmd, args) + } + + cmd.Flags().StringP("path", "p", "./target/kubernetes", fmt.Sprintf("%s path to knative deployment files", cmd.Name())) + + cmd.SetHelpFunc(common.DefaultTemplatedHelp) + + return cmd +} + +func runDeploy(cmd *cobra.Command, args []string) error { + fmt.Println("🛠️ Deploying your Quarkus SonataFlow project...") + + cfg, err := runDeployCmdConfig(cmd) + if err != nil { + return fmt.Errorf("initializing deploy config: %w", err) + } + + if err = common.CheckKubectl(); err != nil { + return err + } + + if _, err = deployKnativeServiceAndEventingBindings(cfg); err != nil { + return err + } + + fmt.Println("🎉 Quarkus SonataFlow project successfully deployed") + + return nil +} + +func deployKnativeServiceAndEventingBindings(cfg DeployCmdConfig) (bool, error) { + isKnativeEventingBindingsCreated := false + createService := common.ExecCommand("kubectl", "apply", "-f", fmt.Sprintf("%s/knative.yml", cfg.Path)) + if err := common.RunCommand( + createService, + "deploy", + ); err != nil { + fmt.Println("❌ ERROR: Deploy failed, Knative service was not created.") + return isKnativeEventingBindingsCreated, err + } + fmt.Println("🎉 Knative service successfully created") + + // Check if kogito.yml file exists + if exists, err := checkIfKogitoFileExists(cfg); exists && err == nil { + deploy := common.ExecCommand("kubectl", "apply", "-f", fmt.Sprintf("%s/kogito.yml", cfg.Path)) + if err := common.RunCommand( + deploy, + "deploy", + ); err != nil { + fmt.Println("❌ ERROR:Deploy failed, Knative Eventing binding was not created.") + return isKnativeEventingBindingsCreated, err + } + isKnativeEventingBindingsCreated = true + fmt.Println("✅ Knative Eventing bindings successfully created") + } + return isKnativeEventingBindingsCreated, nil +} + +func runDeployCmdConfig(cmd *cobra.Command) (cfg DeployCmdConfig, err error) { + cfg = DeployCmdConfig{ + Path: viper.GetString("path"), + } + return +} + +func checkIfKogitoFileExists(cfg DeployCmdConfig) (bool, error) { + if _, err := common.FS.Stat(fmt.Sprintf("%s/kogito.yml", cfg.Path)); err == nil { + return true, nil + } else { + return false, err + } +} diff --git a/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/command/quarkus/quarkus.go b/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/command/quarkus/quarkus.go new file mode 100644 index 0000000000..21465cdd02 --- /dev/null +++ b/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/command/quarkus/quarkus.go @@ -0,0 +1,40 @@ +/* + * Copyright 2023 Red Hat, Inc. and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package quarkus + +import ( + "github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/common" + "github.com/spf13/cobra" +) + +func NewQuarkusCommand() *cobra.Command { + var cmd = &cobra.Command{ + Use: "quarkus", + Short: "Manage SonataFlow projects built in Quarkus", + Long: `Manage SonataFlow projects built in Quarkus`, + SuggestFor: []string{"quaks", "qarkus"}, + } + + cmd.AddCommand(NewCreateCommand()) + cmd.AddCommand(NewBuildCommand()) + cmd.AddCommand(NewRunCommand()) + cmd.AddCommand(NewDeployCommand()) + cmd.AddCommand(NewConvertCommand()) + + cmd.SetHelpFunc(common.DefaultTemplatedHelp) + return cmd +} diff --git a/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/command/quarkus/quarkus_project.go b/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/command/quarkus/quarkus_project.go new file mode 100644 index 0000000000..3a1196e2f8 --- /dev/null +++ b/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/command/quarkus/quarkus_project.go @@ -0,0 +1,56 @@ +/* + * Copyright 2023 Red Hat, Inc. and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package quarkus + +import ( + "fmt" + "github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/common" + "github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/metadata" +) + +type CreateQuarkusProjectConfig struct { + ProjectName string + Extensions string // List of extensions separated by "," to be added to the Quarkus project + DependenciesVersion metadata.DependenciesVersion +} + +func CreateQuarkusProject(cfg CreateQuarkusProjectConfig) error { + if err := common.CheckProjectName(cfg.ProjectName); err != nil { + return err + } + exists, err := common.CheckIfDirExists(cfg.ProjectName) + if err != nil || exists { + return fmt.Errorf("directory with name \"%s\" already exists: %w", cfg.ProjectName, err) + } + create := common.ExecCommand( + "mvn", + fmt.Sprintf("%s:%s:%s:create", cfg.DependenciesVersion.QuarkusPlatformGroupId, metadata.QuarkusMavenPlugin, cfg.DependenciesVersion.QuarkusVersion), + "-DprojectGroupId=org.acme", + "-DnoCode", + fmt.Sprintf("-DplatformVersion=%s", cfg.DependenciesVersion.QuarkusVersion), + fmt.Sprintf("-DprojectArtifactId=%s", cfg.ProjectName), + fmt.Sprintf("-Dextensions=%s", cfg.Extensions)) + + if err := common.RunCommand( + create, + "create", + ); err != nil { + return err + } + + return nil +} diff --git a/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/command/quarkus/run.go b/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/command/quarkus/run.go new file mode 100644 index 0000000000..f07b98a5fc --- /dev/null +++ b/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/command/quarkus/run.go @@ -0,0 +1,113 @@ +/* + * Copyright 2023 Red Hat, Inc. and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package quarkus + +import ( + "fmt" + "github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/common" + "github.com/ory/viper" + "github.com/spf13/cobra" + "sync" + "time" +) + +type RunCmdConfig struct { + PortMapping string +} + +func NewRunCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "run", + Short: "Run a Quarkus SonataFlow project in development mode", + Long: ` + Run a Quarkus SonataFlow project based on Quarkus in development mode. + `, + Example: ` + # Run the local directory + {{.Name}} quarkus run + # Run the local directory mapping a different host port to the running container port. + {{.Name}} run --port 8081 + `, + SuggestFor: []string{"rnu", "start"}, //nolint:misspell + PreRunE: common.BindEnv("port"), + } + + cmd.RunE = func(cmd *cobra.Command, args []string) error { + return run(cmd, args) + } + cmd.Flags().StringP("port", "p", "8080", "Maps a different port to Quarkus dev mode.") + + cmd.SetHelpFunc(common.DefaultTemplatedHelp) + + return cmd +} + +func run(cmd *cobra.Command, args []string) error { + cfg, err := runDevCmdConfig(cmd) + if err != nil { + return fmt.Errorf("initializing create config: %w", err) + } + + if common.IsQuarkusSonataFlowProject() { + return runQuarkusSWFProject(cfg) + } + + return fmt.Errorf("cannot find Quarkus SonataFlow project") +} + +func runDevCmdConfig(cmd *cobra.Command) (cfg RunCmdConfig, err error) { + cfg = RunCmdConfig{ + PortMapping: viper.GetString("port"), + } + return cfg, nil +} + +func runQuarkusSWFProject(cfg RunCmdConfig) error { + + if err := common.CheckJavaDependencies(); err != nil { + return fmt.Errorf("error checking Java dependencies: %w", err) + } + + return runQuarkusProjectDevMode(cfg) +} + +func runQuarkusProjectDevMode(cfg RunCmdConfig) (err error) { + fmt.Println("🛠️ Starting your Quarkus SonataFlow in dev mode...") + create := common.ExecCommand( + "mvn", + "quarkus:dev", + "-Dquarkus.http.port="+fmt.Sprintf("%s", cfg.PortMapping), + ) + + var wg sync.WaitGroup + wg.Add(1) + + go func() { + defer wg.Done() + if err := common.RunCommand(create, "mvn quarkus:dev"); err != nil { + fmt.Printf("❌ ERROR: running Quarkus project: %v", err) + err = fmt.Errorf("Error running Quarkus project: %w", err) + } + }() + + readyCheckURL := fmt.Sprintf("http://localhost:%s/q/health/ready", cfg.PortMapping) + pollInterval := 5 * time.Second + common.ReadyCheck(readyCheckURL, pollInterval, cfg.PortMapping) + + wg.Wait() + return err +} diff --git a/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/command/run.go b/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/command/run.go new file mode 100644 index 0000000000..f33cf26fb3 --- /dev/null +++ b/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/command/run.go @@ -0,0 +1,134 @@ +/* + * Copyright 2023 Red Hat, Inc. and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package command + +import ( + "fmt" + "github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/common" + "github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/metadata" + "github.com/ory/viper" + "github.com/spf13/cobra" + "os" + "sync" + "time" +) + +type RunCmdConfig struct { + PortMapping string +} + +func NewRunCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "run", + Short: "Run a SonataFlow project in development mode", + Long: ` + Run a SonataFlow project in development mode. + By default, it runs over ` + metadata.DevModeImage + ` on Docker. + Alternatively, you can run the same image with Podman. + + `, + Example: ` + # Run the local directory + {{.Name}} run + + # Run the local directory mapping a different host port to the running container port. + {{.Name}} run --port 8081 + `, + SuggestFor: []string{"rnu", "start"}, //nolint:misspell + PreRunE: common.BindEnv("port"), + } + + cmd.RunE = func(cmd *cobra.Command, args []string) error { + return run() + } + + cmd.Flags().StringP("port", "p", "8080", "Maps a different host port to the running container port.") + cmd.SetHelpFunc(common.DefaultTemplatedHelp) + + return cmd +} + +func run() error { + cfg, err := runDevCmdConfig() + if err != nil { + return fmt.Errorf("initializing create config: %w", err) + } + + if common.IsSonataFlowProject() { + if err := runSWFProject(cfg); err != nil { + return err + } + return nil + } else if common.IsQuarkusSonataFlowProject() { + return fmt.Errorf("looks like you are inside a Quarkus project. If that is the case, you should run it with \"quarkus run\" command") + } else { + return fmt.Errorf("cannot find SonataFlow project") + } +} + +func runDevCmdConfig() (cfg RunCmdConfig, err error) { + cfg = RunCmdConfig{ + PortMapping: viper.GetString("port"), + } + return +} + +func runSWFProject(cfg RunCmdConfig) error { + + if errDocker := common.CheckDocker(); errDocker == nil { + if err := runSWFProjectDevMode(common.Docker, cfg); err != nil { + return err + } + } else if errDocker := common.CheckPodman(); errDocker == nil { + if err := runSWFProjectDevMode(common.Podman, cfg); err != nil { + return err + } + } else { + return fmt.Errorf("there is no docker or podman available") + } + return nil +} + +func runSWFProjectDevMode(containerTool string, cfg RunCmdConfig) (err error) { + fmt.Println("⏳ Starting your SonataFlow project in dev mode...") + path, err := os.Getwd() + if err != nil { + fmt.Errorf("❌ Error running SonataFlow project: %w", err) + } + + common.GracefullyStopTheContainerWhenInterrupted(containerTool) + + var wg sync.WaitGroup + wg.Add(1) + + go func() { + defer wg.Done() + if err := common.RunCommand( + common.RunContainerCommand(containerTool, cfg.PortMapping, path), + "container run", + ); err != nil { + err = fmt.Errorf("❌ Error running SonataFlow project: %w", err) + } + }() + + readyCheckURL := fmt.Sprintf("http://localhost:%s/q/health/ready", cfg.PortMapping) + pollInterval := 5 * time.Second + common.ReadyCheck(readyCheckURL, pollInterval, cfg.PortMapping) + + wg.Wait() + return err +} diff --git a/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/command/undeploy.go b/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/command/undeploy.go new file mode 100644 index 0000000000..facaf63425 --- /dev/null +++ b/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/command/undeploy.go @@ -0,0 +1,134 @@ +/* + * Copyright 2023 Red Hat, Inc. and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package command + +import ( + "fmt" + + "github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/common" + "github.com/ory/viper" + "github.com/spf13/cobra" + "os" + "path" +) + +func NewUndeployCommand() *cobra.Command { + var cmd = &cobra.Command{ + Use: "undeploy", + Short: "Undeploy a SonataFlow project on Kubernetes via SonataFlow Operator", + Long: ` + Undeploy a SonataFlow project in Kubernetes via the SonataFlow Operator. + `, + Example: ` + # Undeploy the workflow project from the current directory's project. + # You must provide target namespace. + {{.Name}} undeploy --namespace + # Persist the generated Kubernetes manifests on a given path and deploy the + # workflow from the current directory's project. + {{.Name}} undeploy --manifestPath= + `, + + PreRunE: common.BindEnv("namespace", "manifestPath"), + SuggestFor: []string{"undelpoy", "undeplyo"}, + } + + cmd.RunE = func(cmd *cobra.Command, args []string) error { + return runUndeploy(cmd, args) + } + + cmd.Flags().StringP("namespace", "n", "", "Target namespace of your deployment.") + cmd.Flags().StringP("manifestPath", "c", "", "Target directory of your generated Kubernetes manifests.") + + cmd.SetHelpFunc(common.DefaultTemplatedHelp) + + return cmd +} + +func runUndeploy(cmd *cobra.Command, args []string) error { + + cfg, err := runUndeployCmdConfig(cmd) + //temp dir cleanup + defer func(cfg *DeployUndeployCmdConfig) { + if cfg.TempDir != "" { + if err := os.RemoveAll(cfg.TempDir); err != nil { + fmt.Errorf("❌ ERROR: failed to remove temp dir: %v", err) + } + } + }(&cfg) + + if err != nil { + return fmt.Errorf("❌ ERROR: initializing undeploy config: %w", err) + } + + fmt.Println("🛠️️ Undeploy a SonataFlow project on Kubernetes via the SonataFlow Operator...") + + if err := checkEnvironment(&cfg); err != nil { + return fmt.Errorf("❌ ERROR: checking undeploy environment: %w", err) + } + + if err := generateManifests(&cfg); err != nil { + return fmt.Errorf("❌ ERROR: generating undeploy manifests: %w", err) + } + + if err = undeploy(&cfg); err != nil { + return fmt.Errorf("❌ ERROR: undeploying: %w", err) + } + + fmt.Println("\n🎉 SonataFlow project successfully undeployed.") + + return nil +} + +func undeploy(cfg *DeployUndeployCmdConfig) error { + fmt.Printf("🔨 Undeploying your SonataFlow project in namespace %s\n", cfg.NameSpace) + + files, err := common.FindServiceFiles(cfg.ManifestPath) + if err != nil { + return fmt.Errorf("❌ ERROR: failed to get kubernetes manifest service files: %w", err) + } + for _, file := range files { + if err = common.ExecuteKubectlDelete(file, cfg.NameSpace); err != nil { + return fmt.Errorf("❌ ERROR: failed to undeploy manifest %s, %w", file, err) + } + fmt.Printf(" - ✅ Manifest %s successfully undeployed in namespace %s\n", path.Base(file), cfg.NameSpace) + + } + return nil +} + +func runUndeployCmdConfig(cmd *cobra.Command) (cfg DeployUndeployCmdConfig, err error) { + + cfg = DeployUndeployCmdConfig{ + NameSpace: viper.GetString("namespace"), + SupportFileFolder: viper.GetString("supportFilesFolder"), + ManifestPath: viper.GetString("manifestPath"), + } + + if len(cfg.SupportFileFolder) == 0 { + dir, err := os.Getwd() + cfg.SupportFileFolder = dir + "/specs" + if err != nil { + return cfg, fmt.Errorf("❌ ERROR: failed to get current directory: %w", err) + } + } + //setup manifest path + if err := setupConfigManifestPath(&cfg); err != nil { + return cfg, err + } + + return cfg, nil +} diff --git a/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/command/version.go b/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/command/version.go index 86d80bddc3..318f22aa36 100644 --- a/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/command/version.go +++ b/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/command/version.go @@ -18,7 +18,6 @@ package command import ( "fmt" - "github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/common" "github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/metadata" "github.com/spf13/cobra" diff --git a/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/common/afero.go b/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/common/afero.go index 214e46361f..96f6adeba5 100644 --- a/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/common/afero.go +++ b/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/common/afero.go @@ -18,7 +18,5 @@ package common import "github.com/spf13/afero" -/* Global variable for Afero filesystem. -* Works as a wrapper for the OS package and can be mocked in tests. - */ +// FS /* Global variable for Afero filesystem. var FS afero.Fs = afero.NewOsFs() diff --git a/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/common/browser.go b/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/common/browser.go new file mode 100644 index 0000000000..4817d5b463 --- /dev/null +++ b/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/common/browser.go @@ -0,0 +1,40 @@ +/* + * Copyright 2023 Red Hat, Inc. and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package common + +import ( + "log" + "os/exec" + "runtime" +) + +func OpenBrowserURL(url string) { + var cmd *exec.Cmd + switch runtime.GOOS { + case "windows": + cmd = exec.Command("cmd", "/c", "start", url) + case "darwin": + cmd = exec.Command("open", url) + default: + cmd = exec.Command("xdg-open", url) + } + + err := cmd.Start() + if err != nil { + log.Printf("Error opening browser: %v", err) + } +} diff --git a/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/common/checks.go b/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/common/checks.go index afd5d9cb22..1dcad2744c 100644 --- a/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/common/checks.go +++ b/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/common/checks.go @@ -19,7 +19,8 @@ package common import ( "fmt" "os" - "os/exec" + "path/filepath" + "regexp" "strconv" "strings" @@ -42,7 +43,7 @@ func checkJava() error { version, err := javaCheck.CombinedOutput() if err != nil { fmt.Println("ERROR: Java not found") - fmt.Printf("At least Java %.2d is required to use this command\n", metadata.JAVA_VERSION) + fmt.Printf("At least Java %.2d is required to use this command\n", metadata.JavaVersion) return err } userJavaVersion, err := parseJavaVersion(string(version)) @@ -50,8 +51,8 @@ func checkJava() error { return fmt.Errorf("error while parsing Java version: %w", err) } - if userJavaVersion < metadata.JAVA_VERSION { - fmt.Printf("ERROR: Please make sure you are using Java version %.2d or later", metadata.JAVA_VERSION) + if userJavaVersion < metadata.JavaVersion { + fmt.Printf("ERROR: Please make sure you are using Java version %.2d or later", metadata.JavaVersion) fmt.Println("Installation stopped. Please upgrade Java and run again") os.Exit(1) } else { @@ -65,7 +66,7 @@ func checkMaven() error { version, err := mavenCheck.CombinedOutput() if err != nil { fmt.Println("ERROR: Maven not found") - fmt.Printf("At least Maven %.2d.%.2d.1 is required to use this command\n", metadata.MAVEN_MAJOR_VERSION, metadata.MAVEN_MINOR_VERSION) + fmt.Printf("At least Maven %.2d.%.2d.1 is required to use this command\n", metadata.MavenMajorVersion, metadata.MavenMinorVersion) return err } major, minor, err := parseMavenVersion(string(version)) @@ -73,7 +74,7 @@ func checkMaven() error { return fmt.Errorf("error while parsing Maven version: %w", err) } - if major < metadata.MAVEN_MAJOR_VERSION && minor < metadata.MAVEN_MINOR_VERSION { + if major < metadata.MavenMajorVersion && minor < metadata.MavenMinorVersion { fmt.Printf("ERROR: Please make sure you are using Maven version %d.%d.1 or later", major, minor) fmt.Println("Installation stopped. Please upgrade Maven and run again") os.Exit(1) @@ -112,21 +113,6 @@ func CheckPodman() error { return nil } -func CheckKubectl() error { - fmt.Println("✅ Checking if kubectl is available...") - _, kubectlCheck := exec.LookPath("kubectl") - if err := kubectlCheck; err != nil { - fmt.Println("ERROR: kubectl not found") - fmt.Println("kubectl is required for deploy") - fmt.Println("Download from https://kubectl.docs.kubernetes.io/installation/kubectl/") - os.Exit(1) - return err - } - - fmt.Println(" - kubectl is available") - return nil -} - func parseJavaVersion(version string) (int64, error) { dotVersion := strings.Split(strings.Split(version, "\"")[1], ".") intVersion, err := strconv.ParseInt(dotVersion[0], 10, 8) @@ -160,3 +146,44 @@ func CheckIfDirExists(dirName string) (bool, error) { } return false, err } + +func IsQuarkusSonataFlowProject() bool { + if fileExists("pom.xml") { + return true + } + return false +} + +func IsSonataFlowProject() bool { + if anyFileExists("*.sw.*") { + return true + } + return false +} + +func fileExists(filename string) bool { + _, err := os.Stat(filename) + return !os.IsNotExist(err) +} + +func anyFileExists(extension string) bool { + matches, err := filepath.Glob(extension) + if err != nil { + return false + } + + if len(matches) > 0 { + return true + } + return false +} + +func CheckProjectName(name string) (err error) { + matched, err := regexp.MatchString(`^([_\-\.a-zA-Z0-9]+)$`, name) + if !matched { + fmt.Printf("The project name (\"%s\") contains invalid characters. Valid characters are alphanumeric (A-Za-z), underscore, dash and dot.", name) + err = fmt.Errorf("invalid project name") + + } + return +} diff --git a/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/common/containers.go b/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/common/containers.go new file mode 100644 index 0000000000..cfff75c205 --- /dev/null +++ b/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/common/containers.go @@ -0,0 +1,137 @@ +/* + * Copyright 2023 Red Hat, Inc. and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package common + +import ( + "context" + "fmt" + "github.com/docker/docker/api/types" + "github.com/docker/docker/client" + "github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/metadata" + "os" + "os/exec" + "os/signal" + "strings" + "syscall" +) + +const ( + Docker = "docker" + Podman = "podman" +) + +func GetContainerID(containerTool string) (string, error) { + + switch containerTool { + case Docker: + return getDockerContainerID() + case Podman: + return getPodmanContainerID() + default: + return "", fmt.Errorf("no matching container type found") + } +} + +func getPodmanContainerID() (string, error) { + cmd := exec.Command("podman", + "ps", + "-a", + "--filter", + fmt.Sprintf("ancestor=%s", metadata.DevModeImage), + "--format", "{{.ID}}") + output, err := cmd.CombinedOutput() + if err != nil { + return "", fmt.Errorf("error getting container id: %w", err) + } + containerID := strings.TrimSpace(string(output)) + return containerID, nil +} + +func getDockerContainerID() (string, error) { + cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation()) + if err != nil { + return "", err + } + + containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{}) + if err != nil { + return "", err + } + + for _, container := range containers { + // Check if the container has the expected image name or other identifying information + if strings.Contains(container.Image, metadata.DevModeImage) { + return container.ID, nil + } + } + + return "", fmt.Errorf("no matching container found") +} + +func StopContainer(containerTool string, containerID string) error { + fmt.Printf("⏳ Stopping %s container.\n", containerID) + stopCmd := exec.Command(containerTool, "stop", containerID) + err := stopCmd.Run() + if err != nil { + fmt.Printf("Error stopping container: %v\n", err) + return err + } + fmt.Printf("🛑 Container %s stopped successfully.\n", containerID) + return nil +} + +func RunContainerCommand(containerTool string, portMapping string, path string) *exec.Cmd { + fmt.Printf("🔎 Warming up SonataFlow containers (%s), this could take some time...\n", metadata.DevModeImage) + return exec.Command( + containerTool, + "run", + "--rm", + "-p", + fmt.Sprintf("%s:8080", portMapping), + "-v", + fmt.Sprintf("%s:/home/kogito/serverless-workflow-project/src/main/resources:z", path), + fmt.Sprintf("%s", metadata.DevModeImage), + ) +} + +func GracefullyStopTheContainerWhenInterrupted(containerTool string) { + c := make(chan os.Signal, 1) + signal.Notify(c, os.Interrupt, syscall.SIGTERM) + + go func() { + <-c // Wait for the interrupt signal + + containerID, err := GetContainerID(containerTool) + if err != nil { + fmt.Printf("error getting container id: %v\n", err) + os.Exit(1) // Exit the program with error + } + + fmt.Println("🔨 Stopping the container id: " + containerID) + if containerID != "" { + err := StopContainer(containerTool, containerID) + if err != nil { + fmt.Println("❌ ERROR: Error stopping container id: " + containerID) + os.Exit(1) + } else { + fmt.Println("🎉 Successfully stopped container id: " + containerID) + } + } + + os.Exit(0) // Exit the program gracefully + }() +} diff --git a/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/command/create_workflow.go b/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/common/create_workflow.go similarity index 68% rename from vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/command/create_workflow.go rename to vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/common/create_workflow.go index db382d9989..94179bcf11 100644 --- a/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/command/create_workflow.go +++ b/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/common/create_workflow.go @@ -14,41 +14,44 @@ * limitations under the License. */ -package command +package common import ( "encoding/json" "fmt" - "github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/common" "github.com/spf13/afero" ) type WorkflowStates struct { - Name string `json:"name"` - Type string `json:"type"` - Actions []string `json:"actions"` - End bool `json:"end"` + Name string `json:"name"` + Type string `json:"type"` + Data map[string]string `json:"data"` + End bool `json:"end"` } type Workflow struct { Id string `json:"id"` + Version string `json:"version"` SpecVersion string `json:"specVersion"` Name string `json:"name"` Start string `json:"start"` States []WorkflowStates `json:"states"` } -func getWorkflowTemplate() (workflowJsonByte []byte, err error) { +func GetWorkflowTemplate() (workflowJsonByte []byte, err error) { workflowStates := WorkflowStates{ - Name: "HelloWorld", - Type: "operation", - Actions: []string{}, - End: true, + Name: "HelloWorld", + Type: "inject", + Data: map[string]string{ + "message": "Hello World", + }, + End: true, } workflow := Workflow{ Id: "hello", + Version: "1.0", SpecVersion: "0.8.0", Name: "Hello World", Start: "HelloWorld", @@ -57,21 +60,20 @@ func getWorkflowTemplate() (workflowJsonByte []byte, err error) { workflowJsonByte, err = json.MarshalIndent(workflow, "", " ") if err != nil { - fmt.Println("ERROR: marshaling the workflow json file.") + return nil, fmt.Errorf("error marshaling the workflow json file. %w", err) } return } func CreateWorkflow(workflowFilePath string) (err error) { - workflowFileData, err := getWorkflowTemplate() + workflowFileData, err := GetWorkflowTemplate() if err != nil { return err } - err = afero.WriteFile(common.FS, workflowFilePath, workflowFileData, 0644) + err = afero.WriteFile(FS, workflowFilePath, workflowFileData, 0644) if err != nil { - fmt.Println("ERROR: writing the workflow json file.") - return err + return fmt.Errorf("error writing the workflow json file. %w", err) } fmt.Printf("Workflow file created on %s \n", workflowFilePath) diff --git a/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/common/exec.go b/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/common/exec.go index 2032802df9..335b30b2df 100644 --- a/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/common/exec.go +++ b/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/common/exec.go @@ -18,5 +18,4 @@ package common import "os/exec" -// Make it a global var so it can be overrided in tests -var ExecCommand = exec.Command +var ExecCommand = exec.Command // Make it a global var, so it can be override in tests diff --git a/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/common/helper.go b/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/common/helper.go index 71bd36e6fd..1600a64c58 100644 --- a/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/common/helper.go +++ b/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/common/helper.go @@ -19,10 +19,9 @@ package common import ( "bufio" "fmt" + "github.com/spf13/cobra" "html/template" "os/exec" - - "github.com/spf13/cobra" ) func RunCommand(command *exec.Cmd, commandName string) error { diff --git a/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/common/io.go b/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/common/io.go new file mode 100644 index 0000000000..f5c35c478c --- /dev/null +++ b/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/common/io.go @@ -0,0 +1,66 @@ +/* + * Copyright 2023 Red Hat, Inc. and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package common + +import ( + "fmt" + "io" + "os" + "path/filepath" + "strings" +) + +func FindFilesWithExtensions(directoryPath string, extensions []string) ([]string, error) { + filePaths := []string{} + + _, err := os.Stat(directoryPath) + if os.IsNotExist(err) { + return filePaths, nil + } else if err != nil { + return nil, fmt.Errorf("❌ ERROR: failed to access directory: %s", err) + } + + files, err := os.ReadDir(directoryPath) + if err != nil { + return nil, fmt.Errorf("❌ ERROR: failed to read directory: %s", err) + } + + for _, file := range files { + if file.IsDir() { + continue + } + + fileExt := filepath.Ext(file.Name()) + for _, ext := range extensions { + if strings.EqualFold(fileExt, ext) { + filePath := filepath.Join(directoryPath, file.Name()) + filePaths = append(filePaths, filePath) + break + } + } + } + + return filePaths, nil +} + +func MustGetFile(filepath string) (io.Reader, error) { + file, err := os.OpenFile(filepath, os.O_RDONLY, os.ModePerm) + if err != nil { + return nil, fmt.Errorf("❌ ERROR: failed to read file: %s", err) + } + return file, nil +} diff --git a/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/common/kubectl.go b/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/common/kubectl.go new file mode 100644 index 0000000000..8c5c664c99 --- /dev/null +++ b/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/common/kubectl.go @@ -0,0 +1,67 @@ +/* + * Copyright 2023 Red Hat, Inc. and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package common + +import ( + "fmt" + "os/exec" + "strings" +) + +func GetKubectlNamespace() (string, error) { + fmt.Println("🔎 Checking current namespace in kubectl...") + cmd := ExecCommand("kubectl", "config", "view", "--minify", "--output", "jsonpath={..namespace}") + output, err := cmd.Output() + if err != nil { + return "", fmt.Errorf("❌ ERROR: Failed to get current kubectl namespace: %w", err) + } + namespace := strings.TrimSpace(string(output)) + if namespace == "" { + return "", fmt.Errorf("❌ ERROR: No current kubectl namespace found") + } + fmt.Printf(" - ✅ kubectl current namespace: %s\n", namespace) + return namespace, nil +} + +func CheckKubectlContext() (string, error) { + fmt.Println("🔎 Checking if kubectl has a context configured...") + cmd := ExecCommand("kubectl", "config", "current-context") + output, err := cmd.Output() + if err != nil { + return "", fmt.Errorf("❌ ERROR: No current kubectl context found %w", err) + } + context := strings.TrimSpace(string(output)) + if context == "" { + return "", fmt.Errorf("❌ ERROR: No current kubectl context found") + } + fmt.Printf(" - ✅ kubectl current context: %s \n", context) + return context, nil +} + +func CheckKubectl() error { + fmt.Println("🔎 Checking if kubectl is available...") + _, kubectlCheck := exec.LookPath("kubectl") + if err := kubectlCheck; err != nil { + fmt.Println("ERROR: kubectl not found") + fmt.Println("kubectl is required for deploy") + fmt.Println("Download it from https://kubectl.docs.kubernetes.io/installation/kubectl/") + return fmt.Errorf("❌ ERROR: kubectl not found %w", err) + } + + fmt.Println(" - ✅ kubectl is available") + return nil +} diff --git a/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/common/operator.go b/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/common/operator.go new file mode 100644 index 0000000000..520c4ad28a --- /dev/null +++ b/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/common/operator.go @@ -0,0 +1,159 @@ +/* + * Copyright 2023 Red Hat, Inc. and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package common + +import ( + "bufio" + "bytes" + "fmt" + "github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/metadata" + "gopkg.in/yaml.v2" + "io" + "os" + "os/exec" + "path/filepath" + "strings" +) + +type Document struct { + Kind string `yaml:"kind"` +} + +func ExecuteKubectlApply(crd, namespace string) error { + + cmd := exec.Command("kubectl", + "apply", + "-f", crd, + "-n", namespace, + "--validate=false") + + var stderror bytes.Buffer + + cmd.Stdout = os.Stdout + cmd.Stderr = &stderror //os.Stderr + + err := cmd.Run() + scanner := bufio.NewScanner(&stderror) + for scanner.Scan() { + line := scanner.Text() + //Temporarily removing the following warning: + //In this context, using apply or create are interchangeable, but generates a warning. + //Warning: resource configmaps/service-props is missing the kubectl.kubernetes.io/last-applied-configuration annotation which is required by kubectl apply. kubectl apply should only be used on resources created declaratively by either kubectl create --save-config or kubectl apply. The missing annotation will be patched automatically. + //This is tracked here: https://issues.redhat.com/browse/KOGITO-9391 and it will be fixed by + //https://issues.redhat.com/browse/KOGITO-9381 + if !strings.Contains(line, "kubectl.kubernetes.io/last-applied-configuration") { + fmt.Fprintln(os.Stderr, line) + } + } + if err != nil { + fmt.Printf("has a error") + return fmt.Errorf("❌ ERROR: failed to execute kubectl apply command for %s: %s", crd, err) + } + + return nil +} + +func ExecuteKubectlDelete(crd, namespace string) error { + + cmd := exec.Command("kubectl", + "delete", + "-f", crd, + "-n", namespace) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + + err := cmd.Run() + if err != nil { + return fmt.Errorf("❌ ERROR: failed to execute kubectl delete command for %s: %s", crd, err) + } + + return nil +} + +func CheckOperatorInstalled() error { + cmd := exec.Command("kubectl", "get", "pods", "-n", metadata.OperatorName) + + output, err := cmd.Output() + if err != nil { + return fmt.Errorf("❌ ERROR: SonataFlow Operator not found %w", err) + } + + // Check if the pod is running + operatorRunning := checkOperatorRunning(string(output)) + if !operatorRunning { + return fmt.Errorf("❌ ERROR: SonataFlow Operator not found") + } + + fmt.Println(" - ✅ SonataFlow Operator is available") + return nil +} + +func checkOperatorRunning(getPodsOutPut string) bool { + pods := strings.Split(getPodsOutPut, "\n") + for _, pod := range pods { + // Split each line into fields (NAME, READY, STATUS, RESTARTS, AGE) + fields := strings.Fields(pod) + + // Check if this line contains information about the desired operator manager pod + if len(fields) > 2 && strings.HasPrefix(fields[0], metadata.OperatorManagerPod) && fields[2] == "Running" { + return true + } + } + return false +} + +func FindServiceFiles(directory string) ([]string, error) { + var serviceFiles []string + + err := filepath.Walk(directory, func(path string, info os.FileInfo, err error) error { + if err != nil { + return fmt.Errorf("❌ ERROR: failure accessing a path %q: %v\n", path, err) + } + + if info.IsDir() || filepath.Ext(path) != ".yaml" { + return nil + } + + file, err := os.Open(path) + if err != nil { + return fmt.Errorf("❌ ERROR: failure opening file %q: %v\n", path, err) + } + defer file.Close() + + byteValue, err := io.ReadAll(file) + if err != nil { + return fmt.Errorf("❌ ERROR: failure reading file %q: %v\n", path, err) + } + + var doc Document + if err := yaml.Unmarshal(byteValue, &doc); err != nil { + return fmt.Errorf("❌ ERROR: failure unmarshalling YAML from file %q: %v\n", path, err) + } + + if doc.Kind == metadata.ManifestServiceFilesKind { + serviceFiles = append(serviceFiles, path) + } + + return nil + }) + + if err != nil { + return nil, err + } + + return serviceFiles, nil +} diff --git a/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/common/readyCheck.go b/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/common/readyCheck.go new file mode 100644 index 0000000000..42ecc90c1c --- /dev/null +++ b/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/common/readyCheck.go @@ -0,0 +1,56 @@ +/* + * Copyright 2023 Red Hat, Inc. and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package common + +import ( + "fmt" + "net/http" + "time" +) + +func ReadyCheck(healthCheckURL string, pollInterval time.Duration, portMapping string) { + ready := make(chan bool) + + go pollReadyCheckURL(healthCheckURL, pollInterval, ready) + + select { + case <-ready: + fmt.Println("✅ SonataFlow project is up and running") + OpenBrowserURL(fmt.Sprintf("http://localhost:%s/q/dev", portMapping)) + case <-time.After(10 * time.Minute): + fmt.Printf("Timeout reached. Server at %s is not ready.", healthCheckURL) + } +} + +func pollReadyCheckURL(healthCheckURL string, interval time.Duration, ready chan<- bool) { + client := http.Client{ + Timeout: 5 * time.Second, + } + + for { + resp, err := client.Get(healthCheckURL) + if err == nil && resp.StatusCode == http.StatusOK { + if resp.StatusCode == http.StatusOK { + resp.Body.Close() // close the response body right after checking status + ready <- true + return + } + resp.Body.Close() + } + time.Sleep(interval) + } +} diff --git a/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/metadata/constants.go b/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/metadata/constants.go index 8e82f9d7a3..6b05c5c8c8 100644 --- a/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/metadata/constants.go +++ b/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/metadata/constants.go @@ -17,20 +17,32 @@ package metadata const ( - QUARKUS_MAVEN_PLUGIN = "quarkus-maven-plugin" - QUARKUS_KUBERNETES_EXTENSION = "quarkus-kubernetes" - QUARKUS_RESTEASY_JACKSON_EXTENSION = "quarkus-resteasy-jackson" - QUARKUS_CONTAINER_IMAGE_JIB = "quarkus-container-image-jib" - QUARKUS_CONTAINER_IMAGE_DOCKER = "quarkus-container-image-docker" - KOGITO_QUARKUS_SERVERLESS_WORKFLOW_EXTENSION = "kogito-quarkus-serverless-workflow" - KOGITO_ADDONS_QUARKUS_KNATIVE_EVENTING_EXTENSION = "kogito-addons-quarkus-knative-eventing" + QuarkusMavenPlugin = "quarkus-maven-plugin" + QuarkusKubernetesExtension = "quarkus-kubernetes" + QuarkusResteasyJacksonExtension = "quarkus-resteasy-jackson" + QuarkusContainerImageJib = "quarkus-container-image-jib" + SmallryeHealth = "smallrye-health" + QuarkusContainerImageDocker = "quarkus-container-image-docker" + KogitoQuarkusServerlessWorkflowExtension = "kogito-quarkus-serverless-workflow" + KogitoAddonsQuarkusKnativeEventingExtension = "kogito-addons-quarkus-knative-eventing" + KogitoQuarkusServerlessWorkflowDevUi = "kogito-quarkus-serverless-workflow-devui" + KogitoAddonsQuarkusSourceFiles = "kogito-addons-quarkus-source-files" + KogitoDataIndexInMemory = "kogito-addons-quarkus-data-index-inmemory" - // Versions - JAVA_VERSION = 11 - MAVEN_MAJOR_VERSION = 3 - MAVEN_MINOR_VERSION = 8 + JavaVersion = 11 + MavenMajorVersion = 3 + MavenMinorVersion = 8 - // Default values - DEFAULT_TAG = "latest" - WORKFLOW_SW_JSON = "workflow.sw.json" + DefaultTag = "latest" + WorkflowSwJson = "workflow.sw.json" + + OperatorName = "sonataflow-operator-system" + OperatorManagerPod = "sonataflow-operator-controller-manager" + + YAMLExtension = "sw.yaml" + YAMLExtensionShort = "sw.yml" + JSONExtension = "sw.json" + ApplicationProperties = "application.properties" + + ManifestServiceFilesKind = "SonataFlow" ) diff --git a/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/metadata/devModeImage.go b/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/metadata/devModeImage.go new file mode 100644 index 0000000000..1d972ebf89 --- /dev/null +++ b/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/metadata/devModeImage.go @@ -0,0 +1,19 @@ +/* + * Copyright 2023 Red Hat, Inc. and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package metadata + +var DevModeImage string diff --git a/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/metadata/quarkus.go b/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/metadata/quarkus.go index 06169936e7..51af67d550 100644 --- a/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/metadata/quarkus.go +++ b/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/metadata/quarkus.go @@ -16,7 +16,8 @@ package metadata -var QuarkusPlatformGroupId, QuarkusVersion string +var QuarkusPlatformGroupId string +var QuarkusVersion string type DependenciesVersion struct { QuarkusPlatformGroupId string diff --git a/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/root/root.go b/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/root/root.go index 6e58c926b8..c790e0e9f2 100644 --- a/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/root/root.go +++ b/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/root/root.go @@ -1,5 +1,5 @@ /* - * Copyright 2022 Red Hat, Inc. and/or its affiliates. + * Copyright 2023 Red Hat, Inc. and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,6 +18,7 @@ package root import ( "fmt" + "github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/command/quarkus" "github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/command" "github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/common" @@ -33,19 +34,21 @@ type RootCmdConfig struct { func NewRootCommand(cfg RootCmdConfig) *cobra.Command { var cmd = &cobra.Command{ Use: cfg.Name, - Short: "Serverless Workflow", - Long: "Manage Kogito Serverless Workflow projects", + Short: "SonataFlow", + Long: "Manage SonataFlow projects", } viper.AutomaticEnv() // read in environment variables for WORKFLOW_ - viper.SetEnvPrefix("workflow") // ensure thay all have the prefix + viper.SetEnvPrefix("workflow") // ensure that all have the prefix cmd.Version = cfg.Version cmd.SetVersionTemplate(`{{printf "%s\n" .Version}}`) - cmd.AddCommand(command.NewBuildCommand()) cmd.AddCommand(command.NewCreateCommand()) + cmd.AddCommand(command.NewRunCommand()) cmd.AddCommand(command.NewDeployCommand()) + cmd.AddCommand(command.NewUndeployCommand()) + cmd.AddCommand(quarkus.NewQuarkusCommand()) cmd.AddCommand(command.NewVersionCommand(cfg.Version)) cmd.SetHelpFunc(func(cmd *cobra.Command, args []string) { diff --git a/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/plugin/plugin.go b/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/plugin/plugin.go index b344429f38..b4dabf11da 100644 --- a/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/plugin/plugin.go +++ b/vendor/github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/plugin/plugin.go @@ -1,5 +1,5 @@ /* - * Copyright 2022 Red Hat, Inc. and/or its affiliates. + * Copyright 2023 Red Hat, Inc. and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/vendor/github.com/kiegroup/kogito-serverless-operator/api/LICENSE b/vendor/github.com/kiegroup/kogito-serverless-operator/api/LICENSE new file mode 100644 index 0000000000..261eeb9e9f --- /dev/null +++ b/vendor/github.com/kiegroup/kogito-serverless-operator/api/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/kiegroup/kogito-serverless-operator/api/Makefile b/vendor/github.com/kiegroup/kogito-serverless-operator/api/Makefile new file mode 100644 index 0000000000..00c73d8184 --- /dev/null +++ b/vendor/github.com/kiegroup/kogito-serverless-operator/api/Makefile @@ -0,0 +1,3 @@ +.PHONY: test +test: + go test $(shell go list ./... | grep -v /test/) -coverprofile cover.out diff --git a/vendor/github.com/kiegroup/kogito-serverless-operator/api/condition_types.go b/vendor/github.com/kiegroup/kogito-serverless-operator/api/condition_types.go new file mode 100644 index 0000000000..6d948e8f94 --- /dev/null +++ b/vendor/github.com/kiegroup/kogito-serverless-operator/api/condition_types.go @@ -0,0 +1,104 @@ +// Copyright 2023 Red Hat, Inc. and/or its affiliates +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package api + +import ( + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// Conditions ... +// +kubebuilder:object:generate=true +type Conditions []Condition + +type ConditionType string + +const ( + // RunningConditionType describes the readiness condition of a "live" resource, like the workflow application + RunningConditionType ConditionType = "Running" + // SucceedConditionType describes the readiness condition of a static resource, like a platform, a builder, a configuration, etc. + SucceedConditionType ConditionType = "Succeed" + // BuiltConditionType describes the condition of a resource that needs to be build. + BuiltConditionType ConditionType = "Built" +) + +const ( + WaitingForDeploymentReason = "WaitingForDeployment" + ExternalResourcesNotFoundReason = "ExternalResourcesNotFound" + DeploymentFailureReason = "DeploymentFailure" + DeploymentUnavailableReason = "DeploymentIsUnavailable" + RedeploymentExhaustedReason = "AttemptToRedeployFailed" + WaitingForPlatformReason = "WaitingForPlatform" + BuildFailedReason = "BuildFailedReason" + WaitingForBuildReason = "WaitingForBuild" + BuildIsRunningReason = "BuildIsRunning" +) + +// Condition describes the common structure for conditions in our types +// +kubebuilder:object:generate=true +type Condition struct { + // Type condition for the given object + // +required + Type ConditionType `json:"type"` + // Status of the condition, one of True, False, Unknown. + // +required + Status v1.ConditionStatus `json:"status"` + // The last time this condition was updated. + LastUpdateTime metav1.Time `json:"lastUpdateTime,omitempty"` + // The reason for the condition's last transition. + Reason string `json:"reason,omitempty"` + // A human-readable message indicating details about the transition. + Message string `json:"message,omitempty"` +} + +// IsTrue is true if the condition is True +func (c *Condition) IsTrue() bool { + if c == nil { + return false + } + return c.Status == v1.ConditionTrue +} + +// IsFalse is true if the condition is False +func (c *Condition) IsFalse() bool { + if c == nil { + return false + } + return c.Status == v1.ConditionFalse +} + +// IsUnknown is true if the condition is Unknown +func (c *Condition) IsUnknown() bool { + if c == nil { + return true + } + return c.Status == v1.ConditionUnknown +} + +// GetReason returns a nil save string of Reason +func (c *Condition) GetReason() string { + if c == nil { + return "" + } + return c.Reason +} + +// GetMessage returns a nil save string of Message +func (c *Condition) GetMessage() string { + if c == nil { + return "" + } + return c.Message +} diff --git a/vendor/github.com/kiegroup/kogito-serverless-operator/api/metadata/annotations.go b/vendor/github.com/kiegroup/kogito-serverless-operator/api/metadata/annotations.go new file mode 100644 index 0000000000..b0bac52bc8 --- /dev/null +++ b/vendor/github.com/kiegroup/kogito-serverless-operator/api/metadata/annotations.go @@ -0,0 +1,42 @@ +// Copyright 2023 Red Hat, Inc. and/or its affiliates +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package metadata + +const ( + Domain = "sonataflow.org" + Key = Domain + "/key" + Name = Domain + "/name" + Description = Domain + "/description" + ExpressionLang = Domain + "/expressionLang" + Version = Domain + "/version" + Label = Domain + "/label" + Profile = Domain + "/profile" + SecondaryPlatformAnnotation = Domain + "/secondary.platform" + OperatorIDAnnotation = Domain + "/operator.id" +) + +const ( + // DefaultExpressionLang is the default serverless workflow specification language + DefaultExpressionLang = "jq" + // SpecVersion is the current CNCF Serverless Workflow version supported by the operator + SpecVersion = "0.8" +) + +type ProfileType string + +const ( + DevProfile ProfileType = "dev" + ProdProfile ProfileType = "prod" +) diff --git a/vendor/github.com/kiegroup/kogito-serverless-operator/api/status_types.go b/vendor/github.com/kiegroup/kogito-serverless-operator/api/status_types.go new file mode 100644 index 0000000000..765e90492a --- /dev/null +++ b/vendor/github.com/kiegroup/kogito-serverless-operator/api/status_types.go @@ -0,0 +1,324 @@ +// Copyright 2023 Red Hat, Inc. and/or its affiliates +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package api + +import ( + "fmt" + "reflect" + "sort" + "time" + + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// Based on https://github.com/knative/pkg/blob/980a33719a10024f45e44320316c5bd35cef18d6/apis/condition_set.go + +// Status ... +// +kubebuilder:object:generate=true +type Status struct { + // The latest available observations of a resource's current state. + // +optional + // +patchMergeKey=type + // +patchStrategy=merge + Conditions Conditions `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"` + // The generation observed by the deployment controller. + // +optional + ObservedGeneration int64 `json:"observedGeneration,omitempty"` +} + +func (s *Status) GetConditions() Conditions { + return s.Conditions +} + +// GetCondition finds and returns the Condition that matches the ConditionType +// previously set on Conditions. +func (s *Status) GetCondition(t ConditionType) *Condition { + for _, c := range s.Conditions { + if c.Type == t { + return &c + } + } + return nil +} + +func (s *Status) setConditions(c Conditions) { + s.Conditions = c +} + +// ConditionsReader gives read capability to Conditions. +type ConditionsReader interface { + GetConditions() Conditions + GetCondition(t ConditionType) *Condition + // setConditions overwrite the conditions in the Status instance. + // Private to not expose to client code. Writing to the conditions should be done via ConditionsManager + setConditions(c Conditions) +} + +// ConditionsAccessor describes access methods that every Status based struct implements. +type ConditionsAccessor interface { + ConditionsReader + GetTopLevelConditionType() ConditionType + IsReady() bool + GetTopLevelCondition() *Condition +} + +type ConditionsManager interface { + ClearCondition(t ConditionType) error + MarkTrue(t ConditionType) + MarkTrueWithReason(t ConditionType, reason, messageFormat string, messageA ...interface{}) + MarkUnknown(t ConditionType, reason, messageFormat string, messageA ...interface{}) + MarkFalse(t ConditionType, reason, messageFormat string, messageA ...interface{}) + InitializeConditions() +} + +var _ ConditionsManager = &conditionManager{} + +type conditionManager struct { + reader ConditionsReader + ready ConditionType + dependents []ConditionType +} + +func NewConditionManager(accessor ConditionsReader, ready ConditionType, dependents ...ConditionType) ConditionsManager { + return &conditionManager{ + reader: accessor, + ready: ready, + dependents: dependents, + } +} + +// setCondition sets or updates the Condition on Conditions for Condition.Type. +// If there is an update, Conditions are stored back sorted. +func (s *conditionManager) setCondition(cond Condition) { + if s.reader == nil { + return + } + t := cond.Type + var conditions Conditions + for _, c := range s.reader.GetConditions() { + if c.Type != t { + conditions = append(conditions, c) + } else { + // If we'd only update the LastTransitionTime, then return. + cond.LastUpdateTime = c.LastUpdateTime + if reflect.DeepEqual(cond, c) { + return + } + } + } + cond.LastUpdateTime = metav1.NewTime(time.Now()) + conditions = append(conditions, cond) + // Sorted for convenience of the consumer, i.e. kubectl. + sort.Slice(conditions, func(i, j int) bool { return conditions[i].Type < conditions[j].Type }) + s.reader.setConditions(conditions) +} + +func (s *conditionManager) isTerminal(t ConditionType) bool { + for _, cond := range s.dependents { + if cond == t { + return true + } + } + return t == s.ready +} + +// ClearCondition removes the non-terminal condition that matches the ConditionType +// Not implemented for terminal conditions +func (s *conditionManager) ClearCondition(t ConditionType) error { + var conditions Conditions + + if s.reader == nil { + return nil + } + // Terminal conditions are not handled as they can't be nil + if s.isTerminal(t) { + return fmt.Errorf("clearing terminal conditions not implemented") + } + cond := s.reader.GetCondition(t) + if cond == nil { + return nil + } + for _, c := range s.reader.GetConditions() { + if c.Type != t { + conditions = append(conditions, c) + } + } + + // Sorted for convenience of the consumer, i.e. kubectl. + sort.Slice(conditions, func(i, j int) bool { return conditions[i].Type < conditions[j].Type }) + s.reader.setConditions(conditions) + + return nil +} + +// MarkTrue sets the status of t to true +func (s *conditionManager) MarkTrue(t ConditionType) { + // Set the specified condition. + s.setCondition(Condition{ + Type: t, + Status: corev1.ConditionTrue, + }) +} + +// MarkTrueWithReason sets the status of t to true with the reason +func (s *conditionManager) MarkTrueWithReason(t ConditionType, reason, messageFormat string, messageA ...interface{}) { + // set the specified condition + s.setCondition(Condition{ + Type: t, + Status: corev1.ConditionTrue, + Reason: reason, + Message: fmt.Sprintf(messageFormat, messageA...), + }) +} + +func (s *conditionManager) findUnreadyDependent() *Condition { + // Do not modify the accessors condition order. + conditions := s.reader.GetConditions().DeepCopy() + + // Filter based on terminal status. + n := 0 + for _, c := range conditions { + if c.Type != s.ready { + conditions[n] = c + n++ + } + } + conditions = conditions[:n] + + // Sort set conditions by time. + sort.Slice(conditions, func(i, j int) bool { + return conditions[i].LastUpdateTime.Time.After(conditions[j].LastUpdateTime.Time) + }) + + // First check the conditions with Status == False. + for _, c := range conditions { + // False conditions trump Unknown. + if c.IsFalse() { + return &c + } + } + // Second check for conditions with Status == Unknown. + for _, c := range conditions { + if c.IsUnknown() { + return &c + } + } + + // If something was not initialized. + if len(s.dependents) > len(conditions) { + return &Condition{ + Status: corev1.ConditionUnknown, + } + } + + // All dependents are fine. + return nil +} + +// MarkUnknown sets the status of t to Unknown and also sets the ready condition +// to Unknown if no other dependent condition is in an error state. +func (s *conditionManager) MarkUnknown(t ConditionType, reason, messageFormat string, messageA ...interface{}) { + // set the specified condition + s.setCondition(Condition{ + Type: t, + Status: corev1.ConditionUnknown, + Reason: reason, + Message: fmt.Sprintf(messageFormat, messageA...), + }) + + // check the dependents. + isDependent := false + for _, cond := range s.dependents { + c := s.reader.GetCondition(cond) + // Failed conditions trump Unknown conditions + if c.IsFalse() { + // Double check that the ready condition is also false. + ready := s.reader.GetCondition(s.ready) + if !ready.IsFalse() { + s.MarkFalse(s.ready, reason, messageFormat, messageA...) + } + return + } + if cond == t { + isDependent = true + } + } + + if isDependent { + // set the ready condition, if it is one of our dependent subconditions. + s.setCondition(Condition{ + Type: s.ready, + Status: corev1.ConditionUnknown, + Reason: reason, + Message: fmt.Sprintf(messageFormat, messageA...), + }) + } +} + +// MarkFalse sets the status of t and the ready condition to False. +func (s *conditionManager) MarkFalse(t ConditionType, reason, messageFormat string, messageA ...interface{}) { + types := []ConditionType{t} + for _, cond := range s.dependents { + if cond == t { + types = append(types, s.ready) + } + } + + for _, t := range types { + s.setCondition(Condition{ + Type: t, + Status: corev1.ConditionFalse, + Reason: reason, + Message: fmt.Sprintf(messageFormat, messageA...), + }) + } +} + +// InitializeConditions updates all Conditions in the ConditionSet to Unknown +// if not set. +func (s *conditionManager) InitializeConditions() { + ready := s.reader.GetCondition(s.ready) + if ready == nil { + ready = &Condition{ + Type: s.ready, + Status: corev1.ConditionUnknown, + } + s.setCondition(*ready) + } + // If the ready state is true, it implies that all of the terminal + // subconditions must be true, so initialize any unset conditions to + // true if our ready condition is true, otherwise unknown. + status := corev1.ConditionUnknown + if ready.Status == corev1.ConditionTrue { + status = corev1.ConditionTrue + } + for _, t := range s.dependents { + s.initializeTerminalCondition(t, status) + } +} + +// initializeTerminalCondition initializes a Condition to the given status if unset. +func (s *conditionManager) initializeTerminalCondition(t ConditionType, status corev1.ConditionStatus) *Condition { + if c := s.reader.GetCondition(t); c != nil { + return c + } + c := Condition{ + Type: t, + Status: status, + } + s.setCondition(c) + return &c +} diff --git a/vendor/github.com/kiegroup/kogito-serverless-operator/api/v1alpha08/conversion.go b/vendor/github.com/kiegroup/kogito-serverless-operator/api/v1alpha08/conversion.go new file mode 100644 index 0000000000..c9b1adf770 --- /dev/null +++ b/vendor/github.com/kiegroup/kogito-serverless-operator/api/v1alpha08/conversion.go @@ -0,0 +1,166 @@ +// Copyright 2023 Red Hat, Inc. and/or its affiliates +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package v1alpha08 + +import ( + "context" + "errors" + "path" + "regexp" + "strings" + + cncfmodel "github.com/serverlessworkflow/sdk-go/v2/model" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + controllerruntime "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/yaml" + + "github.com/kiegroup/kogito-serverless-operator/api/metadata" +) + +var namingRegexp = regexp.MustCompile("^[a-z0-9](-?[a-z0-9])*$") +var allowedCharsRegexp = regexp.MustCompile("[^-a-z0-9]") +var startingDashRegexp = regexp.MustCompile("^-+") +var crdVersionRegexp = regexp.MustCompile("v[0-9](alpha|beta)?") + +const ( + // see https://kubernetes.io/docs/concepts/overview/working-with-objects/names/ + dash = "-" + charLimit = 253 +) + +// FromCNCFWorkflow converts the given CNCF Serverless Workflow instance in a new SonataFlow Custom Resource. +func FromCNCFWorkflow(cncfWorkflow *cncfmodel.Workflow, context context.Context) (*SonataFlow, error) { + if cncfWorkflow == nil { + return nil, errors.New("CNCF Workflow is nil") + } + workflowCR := &SonataFlow{ + ObjectMeta: metav1.ObjectMeta{ + Name: extractName(cncfWorkflow), + Annotations: map[string]string{ + metadata.ExpressionLang: string(cncfWorkflow.ExpressionLang), + metadata.Version: cncfWorkflow.Version, + metadata.Description: cncfWorkflow.Description, + }, + }, + } + workflowBytes, err := yaml.Marshal(cncfWorkflow) + if err != nil { + return nil, err + } + workflowCRFlow := &Flow{} + if err = yaml.Unmarshal(workflowBytes, workflowCRFlow); err != nil { + return nil, err + } + workflowCR.Spec.Flow = *workflowCRFlow + + s, _ := SchemeBuilder.Build() + gvks, _, err := s.ObjectKinds(workflowCR) + if err != nil { + return nil, err + } + for _, gvk := range gvks { + if len(gvk.Version) == 0 { + continue + } + workflowCR.SetGroupVersionKind(gvk) + } + warnIfSpecVersionNotSupported(cncfWorkflow, context) + + return workflowCR, nil +} + +// ToCNCFWorkflow converts a SonataFlow object to a Workflow one in order to be able to convert it to a YAML/Json +func ToCNCFWorkflow(workflowCR *SonataFlow, context context.Context) (*cncfmodel.Workflow, error) { + if workflowCR == nil { + return nil, errors.New("SonataFlow is nil") + } + cncfWorkflow := &cncfmodel.Workflow{} + + workflowBytes, err := yaml.Marshal(workflowCR.Spec.Flow) + if err != nil { + return nil, err + } + if err = yaml.Unmarshal(workflowBytes, cncfWorkflow); err != nil { + return nil, err + } + + cncfWorkflow.ID = workflowCR.ObjectMeta.Name + cncfWorkflow.Key = workflowCR.ObjectMeta.Annotations[metadata.Key] + cncfWorkflow.Description = workflowCR.ObjectMeta.Annotations[metadata.Description] + cncfWorkflow.Version = workflowCR.ObjectMeta.Annotations[metadata.Version] + cncfWorkflow.SpecVersion = extractSpecVersion(workflowCR) + cncfWorkflow.ExpressionLang = cncfmodel.ExpressionLangType(extractExpressionLang(workflowCR.ObjectMeta.Annotations)) + + warnIfSpecVersionNotSupported(cncfWorkflow, context) + + return cncfWorkflow, nil +} + +// warnIfSpecVersionNotSupported simple check if the version is not supported by the operator. +// Clearly this will be reviewed once we support 0.9. +func warnIfSpecVersionNotSupported(workflow *cncfmodel.Workflow, context context.Context) { + // simple guard to avoid polluting user's log. + if len(workflow.Version) == 0 { + workflow.Version = metadata.SpecVersion + return + } + if metadata.SpecVersion != workflow.Version { + controllerruntime.LoggerFrom(context).Info("SpecVersion not supported", "Workflow SpecVersion", workflow.Version) + } +} + +func extractExpressionLang(annotations map[string]string) string { + expressionLang := annotations[metadata.ExpressionLang] + if expressionLang != "" { + return expressionLang + } + return metadata.DefaultExpressionLang +} + +// Function to extract from the apiVersion the ServerlessWorkflow schema version +// For example given SonataFlow APIVersion, we would like to extract 0.8 +func extractSpecVersion(workflowCR *SonataFlow) string { + schemaVersion := path.Base(workflowCR.APIVersion) + if len(schemaVersion) == 0 { + return metadata.SpecVersion + } + schemaVersion = crdVersionRegexp.ReplaceAllString(schemaVersion, "") + // we only support major minor from the spec + return schemaVersion[0:1] + "." + "" + schemaVersion[1:] +} + +func extractName(workflow *cncfmodel.Workflow) string { + if len(workflow.ID) > 0 { + return sanitizeNaming(workflow.ID) + } + if len(workflow.Key) > 0 { + return sanitizeNaming(workflow.Key) + } + if len(workflow.Name) > 0 { + return sanitizeNaming(workflow.Name) + } + return "" +} + +func sanitizeNaming(name string) string { + if len(name) == 0 || namingRegexp.MatchString(name) { + return name + } + sanitized := startingDashRegexp.ReplaceAllString(allowedCharsRegexp.ReplaceAllString(strings.TrimSpace(strings.ToLower(name)), dash), "") + if len(sanitized) > charLimit { + return sanitized[:charLimit] + } + return sanitized +} diff --git a/vendor/github.com/kiegroup/kogito-serverless-operator/api/v1alpha08/groupversion_info.go b/vendor/github.com/kiegroup/kogito-serverless-operator/api/v1alpha08/groupversion_info.go new file mode 100644 index 0000000000..36a68565d6 --- /dev/null +++ b/vendor/github.com/kiegroup/kogito-serverless-operator/api/v1alpha08/groupversion_info.go @@ -0,0 +1,39 @@ +// Copyright 2023 Red Hat, Inc. and/or its affiliates +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package v1alpha08 contains API Schema definitions for the serverless v1alpha08 API group +// +kubebuilder:object:generate=true +// +groupName=sonataflow.org +package v1alpha08 + +import ( + "k8s.io/apimachinery/pkg/runtime/schema" + "sigs.k8s.io/controller-runtime/pkg/scheme" +) + +var ( + // GroupVersion is group version used to register these objects + GroupVersion = schema.GroupVersion{Group: "sonataflow.org", Version: "v1alpha08"} + + // SchemeBuilder is used to add go types to the GroupVersionKind scheme + SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} + + // AddToScheme adds the types in this group-version to the given scheme. + AddToScheme = SchemeBuilder.AddToScheme +) + +// Resource takes an unqualified resource and returns a Group qualified GroupResource. +func Resource(resource string) schema.GroupResource { + return GroupVersion.WithResource(resource).GroupResource() +} diff --git a/vendor/github.com/kiegroup/kogito-serverless-operator/api/v1alpha08/sonataflow_types.go b/vendor/github.com/kiegroup/kogito-serverless-operator/api/v1alpha08/sonataflow_types.go new file mode 100644 index 0000000000..095e2b1b52 --- /dev/null +++ b/vendor/github.com/kiegroup/kogito-serverless-operator/api/v1alpha08/sonataflow_types.go @@ -0,0 +1,210 @@ +// Copyright 2022 Red Hat, Inc. and/or its affiliates +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package v1alpha08 + +import ( + cncfmodel "github.com/serverlessworkflow/sdk-go/v2/model" + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "knative.dev/pkg/apis" + duckv1 "knative.dev/pkg/apis/duck/v1" + + "github.com/kiegroup/kogito-serverless-operator/api" +) + +// Flow describes the contents of the Workflow definition following the CNCF Serverless Workflow Specification. +// The attributes not part of the flow are defined by the Custom Resource metadata information, as follows: +// +// - Id, name, and key are replaced by the Custom Resource's name. Must follow the Kubernetes naming patterns (RFC1123). +// +// - Description can be added in the CR's annotation field sonataflow.org/description +// +// - Version is also defined in the CR's annotation, field sonataflow.org/version +// +// - SpecVersion is in the CR's apiVersion, for example v1alpha08 means that it follows the specification version 0.8. +type Flow struct { + // Workflow start definition. + // +kubebuilder:validation:Schemaless + // +kubebuilder:pruning:PreserveUnknownFields + // +optional + Start *cncfmodel.Start `json:"start,omitempty"` + // Annotations List of helpful terms describing the workflows intended purpose, subject areas, or other important + // qualities. + // +optional + Annotations []string `json:"annotations,omitempty"` + // DataInputSchema URI of the JSON Schema used to validate the workflow data input + // +optional + DataInputSchema *cncfmodel.DataInputSchema `json:"dataInputSchema,omitempty"` + // Secrets allow you to access sensitive information, such as passwords, OAuth tokens, ssh keys, etc, + // inside your Workflow Expressions. + // +optional + Secrets cncfmodel.Secrets `json:"secrets,omitempty"` + // Constants Workflow constants are used to define static, and immutable, data which is available to + // Workflow Expressions. + // +optional + Constants *cncfmodel.Constants `json:"constants,omitempty"` + // Defines the workflow default timeout settings. + // +optional + Timeouts *cncfmodel.Timeouts `json:"timeouts,omitempty"` + // Defines checked errors that can be explicitly handled during workflow execution. + // +optional + Errors cncfmodel.Errors `json:"errors,omitempty"` + // If "true", workflow instances is not terminated when there are no active execution paths. + // Instance can be terminated with "terminate end definition" or reaching defined "workflowExecTimeout" + // +optional + KeepActive bool `json:"keepActive,omitempty"` + // Metadata custom information shared with the runtime. + // +kubebuilder:validation:Schemaless + // +kubebuilder:pruning:PreserveUnknownFields + // +optional + Metadata cncfmodel.Metadata `json:"metadata,omitempty"` + // AutoRetries If set to true, actions should automatically be retried on unchecked errors. Default is false + // +optional + AutoRetries bool `json:"autoRetries,omitempty"` + // Auth definitions can be used to define authentication information that should be applied to resources defined + // in the operation property of function definitions. It is not used as authentication information for the + // function invocation, but just to access the resource containing the function invocation information. + // +kubebuilder:validation:Schemaless + // +kubebuilder:pruning:PreserveUnknownFields + // +optional + Auth cncfmodel.Auths `json:"auth,omitempty" validate:"omitempty"` + // +kubebuilder:validation:MinItems=1 + // +kubebuilder:pruning:PreserveUnknownFields + States []cncfmodel.State `json:"states" validate:"required,min=1,dive"` + // +optional + Events cncfmodel.Events `json:"events,omitempty"` + // +optional + Functions cncfmodel.Functions `json:"functions,omitempty"` + // +optional + Retries cncfmodel.Retries `json:"retries,omitempty" validate:"dive"` +} + +// WorkflowResources collection of local objects holding workflow resources, such as OpenAPI files +// that will be mounted in the workflow application. +type WorkflowResources struct { + ConfigMaps []ConfigMapWorkflowResource `json:"configMaps,omitempty"` +} + +// ConfigMapWorkflowResource ConfigMap local reference holding one or more workflow resources, such as OpenAPI files +// that will be mounted in the workflow application. +type ConfigMapWorkflowResource struct { + // ConfigMap the given configMap name in the same workflow context to find the resource + // +kubebuilder:validation:Required + ConfigMap v1.LocalObjectReference `json:"configMap"` + // WorkflowPath path relative to the workflow application root file system within the pod (//src/main/resources). + // Starting trailing slashes will be removed. + WorkflowPath string `json:"workflowPath,omitempty"` +} + +// SonataFlowSpec defines the desired state of SonataFlow +type SonataFlowSpec struct { + // +kubebuilder:validation:Required + Flow Flow `json:"flow"` + // Resources workflow resources that are linked to this workflow definition. + // For example, a collection of OpenAPI specification files. + Resources WorkflowResources `json:"resources,omitempty"` +} + +// SonataFlowStatus defines the observed state of SonataFlow +type SonataFlowStatus struct { + api.Status `json:",inline"` + // +optional + Address duckv1.Addressable `json:"address,omitempty"` + // keeps track of how many failure recovers a given workflow had so far + RecoverFailureAttempts int `json:"recoverFailureAttempts,omitempty"` + LastTimeRecoverAttempt metav1.Time `json:"lastTimeRecoverAttempt,omitempty"` + Endpoint *apis.URL `json:"endpoint,omitempty"` +} + +func (s *SonataFlowStatus) GetTopLevelConditionType() api.ConditionType { + return api.RunningConditionType +} + +func (s *SonataFlowStatus) IsReady() bool { + return s.GetTopLevelCondition().IsTrue() +} + +func (s *SonataFlowStatus) GetTopLevelCondition() *api.Condition { + return s.GetCondition(s.GetTopLevelConditionType()) +} + +func (s *SonataFlowStatus) Manager() api.ConditionsManager { + return api.NewConditionManager(s, api.RunningConditionType, api.BuiltConditionType) +} + +func (s *SonataFlowStatus) IsWaitingForPlatform() bool { + cond := s.GetCondition(api.RunningConditionType) + return cond.IsFalse() && cond.Reason == api.WaitingForPlatformReason +} + +func (s *SonataFlowStatus) IsWaitingForDeployment() bool { + cond := s.GetCondition(api.RunningConditionType) + return cond.IsFalse() && cond.Reason == api.WaitingForDeploymentReason +} + +// IsChildObjectsProblem indicates a problem during objects creation during reconciliation +// For example, a deployment that couldn't be created or a referenced object not found. +func (s *SonataFlowStatus) IsChildObjectsProblem() bool { + cond := s.GetCondition(api.RunningConditionType) + // You can add more conditions that meet this conditional here + return cond.IsFalse() && (cond.Reason == api.ExternalResourcesNotFoundReason) +} + +func (s *SonataFlowStatus) IsWaitingForBuild() bool { + cond := s.GetCondition(api.RunningConditionType) + return cond.IsFalse() && cond.Reason == api.WaitingForBuildReason +} + +func (s *SonataFlowStatus) IsBuildRunningOrUnknown() bool { + cond := s.GetCondition(api.BuiltConditionType) + return cond.IsUnknown() || (cond.IsFalse() && cond.Reason == api.BuildIsRunningReason) +} + +func (s *SonataFlowStatus) IsBuildFailed() bool { + cond := s.GetCondition(api.BuiltConditionType) + return cond.IsFalse() && cond.Reason == api.BuildFailedReason +} + +// SonataFlow is the Schema for the sonataflows API +// +kubebuilder:object:root=true +// +kubebuilder:object:generate=true +// +kubebuilder:subresource:status +// +kubebuilder:resource:shortName={"sf", "workflow", "workflows"} +// +k8s:openapi-gen=true +// +kubebuilder:printcolumn:name="Profile",type=string,JSONPath=`.metadata.annotations.sonataflow\.org\/profile` +// +kubebuilder:printcolumn:name="Version",type=string,JSONPath=`.metadata.annotations.sonataflow\.org\/version` +// +kubebuilder:printcolumn:name="URL",type=string,JSONPath=`.status.endpoint` +// +kubebuilder:printcolumn:name="Ready",type=string,JSONPath=`.status.conditions[?(@.type=='Running')].status` +// +kubebuilder:printcolumn:name="Reason",type=string,JSONPath=`.status.conditions[?(@.type=='Running')].reason` +type SonataFlow struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec SonataFlowSpec `json:"spec,omitempty"` + Status SonataFlowStatus `json:"status,omitempty"` +} + +// SonataFlowList contains a list of SonataFlow +// +kubebuilder:object:root=true +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +type SonataFlowList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []SonataFlow `json:"items"` +} + +func init() { + SchemeBuilder.Register(&SonataFlow{}, &SonataFlowList{}) +} diff --git a/vendor/github.com/kiegroup/kogito-serverless-operator/api/v1alpha08/sonataflowbuild_types.go b/vendor/github.com/kiegroup/kogito-serverless-operator/api/v1alpha08/sonataflowbuild_types.go new file mode 100644 index 0000000000..145f676be7 --- /dev/null +++ b/vendor/github.com/kiegroup/kogito-serverless-operator/api/v1alpha08/sonataflowbuild_types.go @@ -0,0 +1,128 @@ +// Copyright 2023 Red Hat, Inc. and/or its affiliates +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package v1alpha08 + +import ( + "encoding/json" + + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" +) + +type BuildPhase string + +const ( + // BuildPhaseNone -- + BuildPhaseNone BuildPhase = "" + // BuildPhaseInitialization -- + BuildPhaseInitialization BuildPhase = "Initialization" + // BuildPhaseScheduling -- + BuildPhaseScheduling BuildPhase = "Scheduling" + // BuildPhasePending -- + BuildPhasePending BuildPhase = "Pending" + // BuildPhaseRunning -- + BuildPhaseRunning BuildPhase = "Running" + // BuildPhaseSucceeded -- + BuildPhaseSucceeded BuildPhase = "Succeeded" + // BuildPhaseFailed -- + BuildPhaseFailed BuildPhase = "Failed" + // BuildPhaseInterrupted -- + BuildPhaseInterrupted BuildPhase = "Interrupted" + // BuildPhaseError -- + BuildPhaseError BuildPhase = "Error" +) + +type BuildTemplate struct { + // Timeout defines the Build maximum execution duration. + // The Build deadline is set to the Build start time plus the Timeout duration. + // If the Build deadline is exceeded, the Build context is canceled, + // and its phase set to BuildPhaseFailed. + // +kubebuilder:validation:Format=duration + Timeout metav1.Duration `json:"timeout,omitempty"` + // Resources optional compute resource requirements for the builder + Resources corev1.ResourceRequirements `json:"resources,omitempty"` + // Arguments lists the command line arguments to send to the builder + Arguments []string `json:"arguments,omitempty"` +} + +// SonataFlowBuildSpec an abstraction over the actual build process performed by the platform. +type SonataFlowBuildSpec struct { + BuildTemplate `json:",inline"` +} + +// SonataFlowBuildStatus defines the observed state of SonataFlowBuild +type SonataFlowBuildStatus struct { + // The final image tag produced by this build instance + ImageTag string `json:"imageTag,omitempty"` + // Current phase of the build + BuildPhase BuildPhase `json:"buildPhase,omitempty"` + // Last error found during build + Error string `json:"error,omitempty"` + // InnerBuild is a reference to an internal build object, which can be anything known only to internal builders. + // +kubebuilder:pruning:PreserveUnknownFields + InnerBuild runtime.RawExtension `json:"innerBuild,omitempty" patchStrategy:"replace"` +} + +// SetInnerBuild use to define a new object pointer to the inner build. +func (k *SonataFlowBuildStatus) SetInnerBuild(innerBuilder interface{}) error { + obj, err := json.Marshal(innerBuilder) + if err != nil { + return err + } + k.InnerBuild.Raw = obj + return nil +} + +// GetInnerBuild fetch into the given inner build the value from unstructured. +func (k *SonataFlowBuildStatus) GetInnerBuild(innerBuild interface{}) error { + if len(k.InnerBuild.Raw) == 0 { + return nil + } + if err := json.Unmarshal(k.InnerBuild.Raw, innerBuild); err != nil { + return err + } + return nil +} + +// SonataFlowBuild is the Schema for the sonataflowbuilds API +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +kubebuilder:object:root=true +// +kubebuilder:object:generate=true +// +kubebuilder:subresource:status +// +kubebuilder:printcolumn:name="Image",type=string,JSONPath=`.status.imageTag` +// +kubebuilder:printcolumn:name="Phase",type=string,JSONPath=`.status.buildPhase` +// +kubebuilder:resource:shortName={"sfb", "sfbuild", "sfbuilds"} +type SonataFlowBuild struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec SonataFlowBuildSpec `json:"spec,omitempty"` + Status SonataFlowBuildStatus `json:"status,omitempty"` +} + +// SonataFlowBuildList is the Schema for the sonataflowbuildsList API +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +kubebuilder:object:root=true +// +kubebuilder:object:generate=true +type SonataFlowBuildList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []SonataFlowBuild `json:"items"` +} + +func init() { + SchemeBuilder.Register(&SonataFlowBuild{}, &SonataFlowBuildList{}) +} diff --git a/vendor/github.com/kiegroup/kogito-serverless-operator/api/v1alpha08/sonataflowplatform_types.go b/vendor/github.com/kiegroup/kogito-serverless-operator/api/v1alpha08/sonataflowplatform_types.go new file mode 100644 index 0000000000..72a987779d --- /dev/null +++ b/vendor/github.com/kiegroup/kogito-serverless-operator/api/v1alpha08/sonataflowplatform_types.go @@ -0,0 +1,231 @@ +// Copyright 2023 Red Hat, Inc. and/or its affiliates +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package v1alpha08 + +import ( + "strconv" + + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// ConfigurationSpecType is used to define the enum values of the supported types for ConfigurationSpec +type ConfigurationSpecType string + +const ( + // PropertyConfigurationSpec ... + PropertyConfigurationSpec ConfigurationSpecType = "property" + // ConfigMapConfigurationSpec ... + ConfigMapConfigurationSpec ConfigurationSpecType = "configmap" + // SecretConfigurationSpec ... + SecretConfigurationSpec ConfigurationSpecType = "secret" +) + +// ConfigurationSpec represents a generic configuration specification +type ConfigurationSpec struct { + // Type represents the type of configuration, ie: property, configmap, secret, ... + Type ConfigurationSpecType `json:"type"` + // Value a reference to the object for this configuration (syntax may vary depending on the `Type`) + Value corev1.ObjectReference `json:"value"` +} + +const ( + // SonataFlowPlatformKind is the Kind name of the SonataFlowPlatform CR + SonataFlowPlatformKind string = "SonataFlowPlatform" +) + +// PlatformCluster is the kind of orchestration cluster the platform is installed into +// +kubebuilder:validation:Enum=kubernetes;openshift +type PlatformCluster string + +const ( + // PlatformClusterOpenShift is used when targeting an OpenShift cluster + PlatformClusterOpenShift PlatformCluster = "openshift" + // PlatformClusterKubernetes is used when targeting a Kubernetes cluster + PlatformClusterKubernetes PlatformCluster = "kubernetes" +) + +// RegistrySpec provides the configuration for the container registry +type RegistrySpec struct { + // if the container registry is insecure (ie, http only) + Insecure bool `json:"insecure,omitempty"` + // the URI to access + Address string `json:"address,omitempty"` + // the secret where credentials are stored + Secret string `json:"secret,omitempty"` + // the configmap which stores the Certificate Authority + CA string `json:"ca,omitempty"` + // the registry organization + Organization string `json:"organization,omitempty"` +} + +type BuildStrategy string + +const ( + // OperatorBuildStrategy uses the operator builder to perform the workflow build + // E.g. on Minikube or Kubernetes the container-builder strategies + OperatorBuildStrategy BuildStrategy = "operator" + // PlatformBuildStrategy uses the cluster to perform the build. + // E.g. on OpenShift, BuildConfig. + PlatformBuildStrategy BuildStrategy = "platform" + + // In the future we can have "custom" which will delegate the build to an external actor provided by the administrator + // See https://issues.redhat.com/browse/KOGITO-9084 +) + +type BuildPlatformTemplate struct { + // a base image that can be used as base layer for all images. + // It can be useful if you want to provide some custom base image with further utility software + BaseImage string `json:"baseImage,omitempty"` + // how much time to wait before time out the build process + Timeout *metav1.Duration `json:"timeout,omitempty"` + // BuildStrategy to use to build workflows in the platform. + // Usually, the operator elect the strategy based on the platform. + // Note that this field might be read only in certain scenarios. + BuildStrategy BuildStrategy `json:"buildStrategy,omitempty"` + // TODO: add a link to the documentation where the user can find more info about this field + // BuildStrategyOptions additional options to add to the build strategy. + BuildStrategyOptions map[string]string `json:"buildStrategyOptions,omitempty"` + // Registry the registry where to publish the built image + Registry RegistrySpec `json:"registry,omitempty"` +} + +// GetTimeout returns the specified duration or a default one +func (b *BuildPlatformTemplate) GetTimeout() metav1.Duration { + if b.Timeout == nil { + return metav1.Duration{} + } + return *b.Timeout +} + +// IsOptionEnabled return whether the BuildStrategyOptions is enabled or not +func (b *BuildPlatformTemplate) IsOptionEnabled(option string) bool { + if enabled, ok := b.BuildStrategyOptions[option]; ok { + res, err := strconv.ParseBool(enabled) + if err != nil { + return false + } + return res + } + return false +} + +func (b *BuildPlatformTemplate) IsOptionEmpty(option string) bool { + if v, ok := b.BuildStrategyOptions[option]; ok { + return len(v) == 0 + } + return false +} + +// SonataFlowPlatformSpec defines the desired state of SonataFlowPlatform +type SonataFlowPlatformSpec struct { + // BuildTemplate specify how to build the Workflow. It's used as a template for the SonataFlowBuild + BuildTemplate BuildTemplate `json:"build,omitempty"` + // BuildPlatform specify how is the platform where we want to build the Workflow + BuildPlatform BuildPlatformTemplate `json:"platform,omitempty"` + // Configuration list of configuration properties to be attached to all the Workflow built from this Platform + Configuration ConfigurationSpec `json:"configuration,omitempty"` + // DevBaseImage Base image to run the Workflow in dev mode instead of the operator's default. + // Optional, used for the dev profile only + DevBaseImage string `json:"devBaseImage,omitempty"` +} + +// PlatformPhase is the phase of a Platform +type PlatformPhase string + +const ( + // PlatformPhaseNone when the SonataFlowPlatform does not exist + PlatformPhaseNone PlatformPhase = "" + // PlatformPhaseCreating when the SonataFlowPlatform is under creation process + PlatformPhaseCreating PlatformPhase = "Creating" + // PlatformPhaseWarming when the SonataFlowPlatform is warming (ie, creating Kaniko cache) + PlatformPhaseWarming PlatformPhase = "Warming" + // PlatformPhaseReady when the SonataFlowPlatform is ready + PlatformPhaseReady PlatformPhase = "Ready" + // PlatformPhaseError when the SonataFlowPlatform had some error (see Conditions) + PlatformPhaseError PlatformPhase = "Error" + // PlatformPhaseDuplicate when the SonataFlowPlatform is duplicated + PlatformPhaseDuplicate PlatformPhase = "Duplicate" +) + +// PlatformConditionType defines the type of condition +type PlatformConditionType string + +// PlatformCondition describes the state of a resource at a certain point. +type PlatformCondition struct { + // TODO: the Type can't be Kubernetes or OpenShift, but the actual condition like "Ready". See the Conditions implementation in the workflow. + // TODO: also, we already have the `Cluster` field for that matter. + // TODO: see https://issues.redhat.com/browse/KOGITO-9218 + + // Type of platform condition (i.e. Kubernetes, OpenShift). + Type PlatformConditionType `json:"type"` + // Status of the condition, one of True, False, Unknown. + Status corev1.ConditionStatus `json:"status"` + // The last time this condition was updated. + LastUpdateTime metav1.Time `json:"lastUpdateTime,omitempty"` + // Last time the condition transitioned from one status to another. + LastTransitionTime metav1.Time `json:"lastTransitionTime,omitempty"` + // The reason for the condition's last transition. + Reason string `json:"reason,omitempty"` + // A human-readable message indicating details about the transition. + Message string `json:"message,omitempty"` +} + +// SonataFlowPlatformStatus defines the observed state of SonataFlowPlatform +type SonataFlowPlatformStatus struct { + // Cluster what kind of cluster you're running (ie, plain Kubernetes or OpenShift) + Cluster PlatformCluster `json:"cluster,omitempty"` + // ObservedGeneration is the most recent generation observed for this Platform. + ObservedGeneration int64 `json:"observedGeneration,omitempty"` + // Phase defines in what phase the Platform is found + Phase PlatformPhase `json:"phase,omitempty"` + // Conditions which are the conditions met (particularly useful when in ERROR phase) + Conditions []PlatformCondition `json:"conditions,omitempty"` + // Version the operator version controlling this Platform + Version string `json:"version,omitempty"` + // Info generic information related to the build + Info map[string]string `json:"info,omitempty"` +} + +// SonataFlowPlatform is the Schema for the sonataflowplatforms API +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +kubebuilder:object:root=true +// +kubebuilder:object:generate=true +// +kubebuilder:subresource:status +// +kubebuilder:resource:shortName={"sfp", "sfplatform", "sfplatforms"} +// +kubebuilder:printcolumn:name="Cluster",type=string,JSONPath=`.status.cluster` +// +kubebuilder:printcolumn:name="Phase",type=string,JSONPath=`.status.phase` +// +kubebuilder:printcolumn:name="Ready",type=string,JSONPath=`.status.phase=='Ready'` +type SonataFlowPlatform struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec SonataFlowPlatformSpec `json:"spec,omitempty"` + Status SonataFlowPlatformStatus `json:"status,omitempty"` +} + +// SonataFlowPlatformList contains a list of SonataFlowPlatform +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +kubebuilder:object:root=true +// +kubebuilder:object:generate=true +type SonataFlowPlatformList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []SonataFlowPlatform `json:"items"` +} + +func init() { + SchemeBuilder.Register(&SonataFlowPlatform{}, &SonataFlowPlatformList{}) +} diff --git a/vendor/github.com/kiegroup/kogito-serverless-operator/api/v1alpha08/sonataflowplatform_types_support.go b/vendor/github.com/kiegroup/kogito-serverless-operator/api/v1alpha08/sonataflowplatform_types_support.go new file mode 100644 index 0000000000..d895286370 --- /dev/null +++ b/vendor/github.com/kiegroup/kogito-serverless-operator/api/v1alpha08/sonataflowplatform_types_support.go @@ -0,0 +1,164 @@ +// Copyright 2023 Red Hat, Inc. and/or its affiliates +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package v1alpha08 + +import ( + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// NewSonataFlowPlatformList returns an empty list of Platform objects +func NewSonataFlowPlatformList() SonataFlowPlatformList { + return SonataFlowPlatformList{ + TypeMeta: metav1.TypeMeta{ + APIVersion: GroupVersion.String(), + Kind: SonataFlowPlatformKind, + }, + } +} + +// NewSonataFlowPlatform returns the basic Platform definition +func NewSonataFlowPlatform(namespace string, name string) SonataFlowPlatform { + return SonataFlowPlatform{ + TypeMeta: metav1.TypeMeta{ + APIVersion: GroupVersion.String(), + Kind: SonataFlowPlatformKind, + }, + ObjectMeta: metav1.ObjectMeta{ + Namespace: namespace, + Name: name, + }, + } +} + +// GetCondition returns the condition with the provided type. +func (in *SonataFlowPlatformStatus) GetCondition(condType PlatformConditionType) *PlatformCondition { + for i := range in.Conditions { + c := in.Conditions[i] + if c.Type == condType { + return &c + } + } + return nil +} + +// SetErrorCondition sets the condition error for the given platform +func (in *SonataFlowPlatformStatus) SetErrorCondition(condType PlatformConditionType, reason string, err error) { + in.SetConditions(PlatformCondition{ + Type: condType, + Status: corev1.ConditionFalse, + LastUpdateTime: metav1.Now(), + LastTransitionTime: metav1.Now(), + Reason: reason, + Message: err.Error(), + }) +} + +// SetConditions updates the resource to include the provided conditions. +// +// If a condition that we are about to add already exists and has the same status and +// reason then we are not going to update. +func (in *SonataFlowPlatformStatus) SetConditions(conditions ...PlatformCondition) { + for _, condition := range conditions { + if condition.LastUpdateTime.IsZero() { + condition.LastUpdateTime = metav1.Now() + } + if condition.LastTransitionTime.IsZero() { + condition.LastTransitionTime = metav1.Now() + } + + currentCond := in.GetCondition(condition.Type) + + if currentCond != nil && currentCond.Status == condition.Status && currentCond.Reason == condition.Reason { + return + } + // Do not update lastTransitionTime if the status of the condition doesn't change. + if currentCond != nil && currentCond.Status == condition.Status { + condition.LastTransitionTime = currentCond.LastTransitionTime + } + + in.RemoveCondition(condition.Type) + in.Conditions = append(in.Conditions, condition) + } +} + +// RemoveCondition removes the resource condition with the provided type. +func (in *SonataFlowPlatformStatus) RemoveCondition(condType PlatformConditionType) { + newConditions := in.Conditions[:0] + for _, c := range in.Conditions { + if c.Type != condType { + newConditions = append(newConditions, c) + } + } + + in.Conditions = newConditions +} + +const ( + // ServiceTypeUser service user type label marker + ServiceTypeUser = "user" +) + +// +kubebuilder:object:generate=false +// ResourceCondition is a common type for all conditions +type ResourceCondition interface { + GetType() string + GetStatus() corev1.ConditionStatus + GetLastUpdateTime() metav1.Time + GetLastTransitionTime() metav1.Time + GetReason() string + GetMessage() string +} + +var _ ResourceCondition = PlatformCondition{} + +// GetConditions -- +func (in *SonataFlowPlatformStatus) GetConditions() []ResourceCondition { + res := make([]ResourceCondition, 0, len(in.Conditions)) + for _, c := range in.Conditions { + res = append(res, c) + } + return res +} + +// GetType -- +func (c PlatformCondition) GetType() string { + return string(c.Type) +} + +// GetStatus -- +func (c PlatformCondition) GetStatus() corev1.ConditionStatus { + return c.Status +} + +// GetLastUpdateTime -- +func (c PlatformCondition) GetLastUpdateTime() metav1.Time { + return c.LastUpdateTime +} + +// GetLastTransitionTime -- +func (c PlatformCondition) GetLastTransitionTime() metav1.Time { + return c.LastTransitionTime +} + +// GetReason -- +func (c PlatformCondition) GetReason() string { + return c.Reason +} + +// GetMessage -- +func (c PlatformCondition) GetMessage() string { + return c.Message +} diff --git a/vendor/github.com/kiegroup/kogito-serverless-operator/api/v1alpha08/zz_generated.deepcopy.go b/vendor/github.com/kiegroup/kogito-serverless-operator/api/v1alpha08/zz_generated.deepcopy.go new file mode 100644 index 0000000000..d44f215200 --- /dev/null +++ b/vendor/github.com/kiegroup/kogito-serverless-operator/api/v1alpha08/zz_generated.deepcopy.go @@ -0,0 +1,549 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +// Copyright 2023 Red Hat, Inc. and/or its affiliates +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by controller-gen. DO NOT EDIT. + +package v1alpha08 + +import ( + "github.com/serverlessworkflow/sdk-go/v2/model" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "knative.dev/pkg/apis" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BuildPlatformTemplate) DeepCopyInto(out *BuildPlatformTemplate) { + *out = *in + if in.Timeout != nil { + in, out := &in.Timeout, &out.Timeout + *out = new(v1.Duration) + **out = **in + } + if in.BuildStrategyOptions != nil { + in, out := &in.BuildStrategyOptions, &out.BuildStrategyOptions + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + out.Registry = in.Registry +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BuildPlatformTemplate. +func (in *BuildPlatformTemplate) DeepCopy() *BuildPlatformTemplate { + if in == nil { + return nil + } + out := new(BuildPlatformTemplate) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BuildTemplate) DeepCopyInto(out *BuildTemplate) { + *out = *in + out.Timeout = in.Timeout + in.Resources.DeepCopyInto(&out.Resources) + if in.Arguments != nil { + in, out := &in.Arguments, &out.Arguments + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BuildTemplate. +func (in *BuildTemplate) DeepCopy() *BuildTemplate { + if in == nil { + return nil + } + out := new(BuildTemplate) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ConfigMapWorkflowResource) DeepCopyInto(out *ConfigMapWorkflowResource) { + *out = *in + out.ConfigMap = in.ConfigMap +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConfigMapWorkflowResource. +func (in *ConfigMapWorkflowResource) DeepCopy() *ConfigMapWorkflowResource { + if in == nil { + return nil + } + out := new(ConfigMapWorkflowResource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ConfigurationSpec) DeepCopyInto(out *ConfigurationSpec) { + *out = *in + out.Value = in.Value +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConfigurationSpec. +func (in *ConfigurationSpec) DeepCopy() *ConfigurationSpec { + if in == nil { + return nil + } + out := new(ConfigurationSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Flow) DeepCopyInto(out *Flow) { + *out = *in + if in.Start != nil { + in, out := &in.Start, &out.Start + *out = new(model.Start) + (*in).DeepCopyInto(*out) + } + if in.Annotations != nil { + in, out := &in.Annotations, &out.Annotations + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.DataInputSchema != nil { + in, out := &in.DataInputSchema, &out.DataInputSchema + *out = new(model.DataInputSchema) + **out = **in + } + if in.Secrets != nil { + in, out := &in.Secrets, &out.Secrets + *out = make(model.Secrets, len(*in)) + copy(*out, *in) + } + if in.Constants != nil { + in, out := &in.Constants, &out.Constants + *out = new(model.Constants) + (*in).DeepCopyInto(*out) + } + if in.Timeouts != nil { + in, out := &in.Timeouts, &out.Timeouts + *out = new(model.Timeouts) + (*in).DeepCopyInto(*out) + } + if in.Errors != nil { + in, out := &in.Errors, &out.Errors + *out = make(model.Errors, len(*in)) + copy(*out, *in) + } + if in.Metadata != nil { + in, out := &in.Metadata, &out.Metadata + *out = make(model.Metadata, len(*in)) + for key, val := range *in { + (*out)[key] = *val.DeepCopy() + } + } + if in.Auth != nil { + in, out := &in.Auth, &out.Auth + *out = make(model.Auths, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.States != nil { + in, out := &in.States, &out.States + *out = make([]model.State, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Events != nil { + in, out := &in.Events, &out.Events + *out = make(model.Events, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Functions != nil { + in, out := &in.Functions, &out.Functions + *out = make(model.Functions, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Retries != nil { + in, out := &in.Retries, &out.Retries + *out = make(model.Retries, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Flow. +func (in *Flow) DeepCopy() *Flow { + if in == nil { + return nil + } + out := new(Flow) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PlatformCondition) DeepCopyInto(out *PlatformCondition) { + *out = *in + in.LastUpdateTime.DeepCopyInto(&out.LastUpdateTime) + in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PlatformCondition. +func (in *PlatformCondition) DeepCopy() *PlatformCondition { + if in == nil { + return nil + } + out := new(PlatformCondition) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RegistrySpec) DeepCopyInto(out *RegistrySpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RegistrySpec. +func (in *RegistrySpec) DeepCopy() *RegistrySpec { + if in == nil { + return nil + } + out := new(RegistrySpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SonataFlow) DeepCopyInto(out *SonataFlow) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SonataFlow. +func (in *SonataFlow) DeepCopy() *SonataFlow { + if in == nil { + return nil + } + out := new(SonataFlow) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *SonataFlow) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SonataFlowBuild) DeepCopyInto(out *SonataFlowBuild) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SonataFlowBuild. +func (in *SonataFlowBuild) DeepCopy() *SonataFlowBuild { + if in == nil { + return nil + } + out := new(SonataFlowBuild) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *SonataFlowBuild) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SonataFlowBuildList) DeepCopyInto(out *SonataFlowBuildList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]SonataFlowBuild, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SonataFlowBuildList. +func (in *SonataFlowBuildList) DeepCopy() *SonataFlowBuildList { + if in == nil { + return nil + } + out := new(SonataFlowBuildList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *SonataFlowBuildList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SonataFlowBuildSpec) DeepCopyInto(out *SonataFlowBuildSpec) { + *out = *in + in.BuildTemplate.DeepCopyInto(&out.BuildTemplate) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SonataFlowBuildSpec. +func (in *SonataFlowBuildSpec) DeepCopy() *SonataFlowBuildSpec { + if in == nil { + return nil + } + out := new(SonataFlowBuildSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SonataFlowBuildStatus) DeepCopyInto(out *SonataFlowBuildStatus) { + *out = *in + in.InnerBuild.DeepCopyInto(&out.InnerBuild) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SonataFlowBuildStatus. +func (in *SonataFlowBuildStatus) DeepCopy() *SonataFlowBuildStatus { + if in == nil { + return nil + } + out := new(SonataFlowBuildStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SonataFlowList) DeepCopyInto(out *SonataFlowList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]SonataFlow, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SonataFlowList. +func (in *SonataFlowList) DeepCopy() *SonataFlowList { + if in == nil { + return nil + } + out := new(SonataFlowList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *SonataFlowList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SonataFlowPlatform) DeepCopyInto(out *SonataFlowPlatform) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SonataFlowPlatform. +func (in *SonataFlowPlatform) DeepCopy() *SonataFlowPlatform { + if in == nil { + return nil + } + out := new(SonataFlowPlatform) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *SonataFlowPlatform) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SonataFlowPlatformList) DeepCopyInto(out *SonataFlowPlatformList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]SonataFlowPlatform, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SonataFlowPlatformList. +func (in *SonataFlowPlatformList) DeepCopy() *SonataFlowPlatformList { + if in == nil { + return nil + } + out := new(SonataFlowPlatformList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *SonataFlowPlatformList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SonataFlowPlatformSpec) DeepCopyInto(out *SonataFlowPlatformSpec) { + *out = *in + in.BuildTemplate.DeepCopyInto(&out.BuildTemplate) + in.BuildPlatform.DeepCopyInto(&out.BuildPlatform) + out.Configuration = in.Configuration +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SonataFlowPlatformSpec. +func (in *SonataFlowPlatformSpec) DeepCopy() *SonataFlowPlatformSpec { + if in == nil { + return nil + } + out := new(SonataFlowPlatformSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SonataFlowPlatformStatus) DeepCopyInto(out *SonataFlowPlatformStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]PlatformCondition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Info != nil { + in, out := &in.Info, &out.Info + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SonataFlowPlatformStatus. +func (in *SonataFlowPlatformStatus) DeepCopy() *SonataFlowPlatformStatus { + if in == nil { + return nil + } + out := new(SonataFlowPlatformStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SonataFlowSpec) DeepCopyInto(out *SonataFlowSpec) { + *out = *in + in.Flow.DeepCopyInto(&out.Flow) + in.Resources.DeepCopyInto(&out.Resources) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SonataFlowSpec. +func (in *SonataFlowSpec) DeepCopy() *SonataFlowSpec { + if in == nil { + return nil + } + out := new(SonataFlowSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SonataFlowStatus) DeepCopyInto(out *SonataFlowStatus) { + *out = *in + in.Status.DeepCopyInto(&out.Status) + in.Address.DeepCopyInto(&out.Address) + in.LastTimeRecoverAttempt.DeepCopyInto(&out.LastTimeRecoverAttempt) + if in.Endpoint != nil { + in, out := &in.Endpoint, &out.Endpoint + *out = new(apis.URL) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SonataFlowStatus. +func (in *SonataFlowStatus) DeepCopy() *SonataFlowStatus { + if in == nil { + return nil + } + out := new(SonataFlowStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *WorkflowResources) DeepCopyInto(out *WorkflowResources) { + *out = *in + if in.ConfigMaps != nil { + in, out := &in.ConfigMaps, &out.ConfigMaps + *out = make([]ConfigMapWorkflowResource, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkflowResources. +func (in *WorkflowResources) DeepCopy() *WorkflowResources { + if in == nil { + return nil + } + out := new(WorkflowResources) + in.DeepCopyInto(out) + return out +} diff --git a/vendor/github.com/kiegroup/kogito-serverless-operator/api/zz_generated.deepcopy.go b/vendor/github.com/kiegroup/kogito-serverless-operator/api/zz_generated.deepcopy.go new file mode 100644 index 0000000000..095b01498d --- /dev/null +++ b/vendor/github.com/kiegroup/kogito-serverless-operator/api/zz_generated.deepcopy.go @@ -0,0 +1,79 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +// Copyright 2023 Red Hat, Inc. and/or its affiliates +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by controller-gen. DO NOT EDIT. + +package api + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Condition) DeepCopyInto(out *Condition) { + *out = *in + in.LastUpdateTime.DeepCopyInto(&out.LastUpdateTime) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Condition. +func (in *Condition) DeepCopy() *Condition { + if in == nil { + return nil + } + out := new(Condition) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in Conditions) DeepCopyInto(out *Conditions) { + { + in := &in + *out = make(Conditions, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Conditions. +func (in Conditions) DeepCopy() Conditions { + if in == nil { + return nil + } + out := new(Conditions) + in.DeepCopyInto(out) + return *out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Status) DeepCopyInto(out *Status) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make(Conditions, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Status. +func (in *Status) DeepCopy() *Status { + if in == nil { + return nil + } + out := new(Status) + in.DeepCopyInto(out) + return out +} diff --git a/vendor/github.com/kiegroup/kogito-serverless-operator/workflowproj/LICENSE b/vendor/github.com/kiegroup/kogito-serverless-operator/workflowproj/LICENSE new file mode 100644 index 0000000000..261eeb9e9f --- /dev/null +++ b/vendor/github.com/kiegroup/kogito-serverless-operator/workflowproj/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/kiegroup/kogito-serverless-operator/workflowproj/Makefile b/vendor/github.com/kiegroup/kogito-serverless-operator/workflowproj/Makefile new file mode 100644 index 0000000000..21599a4092 --- /dev/null +++ b/vendor/github.com/kiegroup/kogito-serverless-operator/workflowproj/Makefile @@ -0,0 +1,21 @@ +.PHONY: all +all: test + +##@ Development + +.PHONY: fmt +fmt: ## Run go fmt against code. + go fmt ./... + +.PHONY: vet +vet: ## Run go vet against code. + go vet ./... + +.PHONY: test +test: fmt vet ## Run tests. + go test ./... -coverprofile cover.out + +.PHONY: clean +clean: + rm -rf bin/ + diff --git a/vendor/github.com/kiegroup/kogito-serverless-operator/workflowproj/README.md b/vendor/github.com/kiegroup/kogito-serverless-operator/workflowproj/README.md new file mode 100644 index 0000000000..0bcf9d6876 --- /dev/null +++ b/vendor/github.com/kiegroup/kogito-serverless-operator/workflowproj/README.md @@ -0,0 +1,62 @@ +# Workflow Project Handler + +Handler to programmatically convert a local SonataFlow project into Kubernetes manifests to deploy with +the operator. + +## How to + +Add this module to your project's dependencies: + +```shell +go get github.com/kiegroup/kogito-serverless-workflow/workflowproj +``` + +Then you should have access to the main entry point of this package, which is the workflow project handler builder. + +The API is simple enough to describe in a few lines: + +```go +package main + +import ( + "os" + + "github.com/kiegroup/kogito-serverless-operator/workflowproj" +) + +func Main() { + // we are ignoring errors just for demo purposes, but don't do this! + workflowFile, _ := os.Open("myworkflow.sw.json") + propertiesFile, _ := os.Open("application.properties") + specFile, _ := os.Open("myopenapi.yaml") + defer workflowFile.Close() + defer propertiesFile.Close() + defer specFile.Close() + + // create the handler + handler := workflowproj.New("mynamespace"). + WithWorkflow(workflowFile). + WithAppProperties(propertiesFile). + AddResource("myopenapi.yaml", specFile) + + // You can easily generate the Kubernetes manifests to later use client-go to deploy them in the cluster... + objs, _ := handler.AsObjects() + // client.Create(...), other stuff + + // ... or you can save the files locally to use them later or to integrate in a GitOps process + _ = handler.SaveAsKubernetesResources("/my/dir/") +} +``` + +The `SonataFlow` custom resource generated is annotated with +the [devmode profile](https://kiegroup.github.io/kogito-docs/serverlessworkflow/latest/cloud/operator/developing-workflows.html) +. +Every other resource added to the project is a `ConfigMap` handling these resources for you. + +Given that you already have the SonataFlow +Operator [installed](https://kiegroup.github.io/kogito-docs/serverlessworkflow/latest/cloud/operator/install-serverless-operator.html) +, to deploy the generated project you can simply run: + +```shell +kubectl apply -f /my/dir/* -n "mynamespace" +``` diff --git a/vendor/github.com/kiegroup/kogito-serverless-operator/workflowproj/camelschema.go b/vendor/github.com/kiegroup/kogito-serverless-operator/workflowproj/camelschema.go new file mode 100644 index 0000000000..4e074744c1 --- /dev/null +++ b/vendor/github.com/kiegroup/kogito-serverless-operator/workflowproj/camelschema.go @@ -0,0 +1,19 @@ +// Copyright 2023 Red Hat, Inc. and/or its affiliates +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package workflowproj + +// camelSchema version 3.20.5. We can update this schema as we go, or add support to more than one in the future. +// See https://github.com/apache/camel/blob/camel-3.20.5/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camel-yaml-dsl.json +const camelSchema = "{ \"$schema\" : \"http://json-schema.org/draft-04/schema#\", \"type\" : \"array\", \"items\" : { \"maxProperties\" : 1, \"definitions\" : { \"org.apache.camel.model.ProcessorDefinition\" : { \"type\" : \"object\", \"maxProperties\" : 1, \"properties\" : { \"aggregate\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.AggregateDefinition\" }, \"bean\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.BeanDefinition\" }, \"do-catch\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.CatchDefinition\" }, \"doCatch\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.CatchDefinition\" }, \"choice\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.ChoiceDefinition\" }, \"circuit-breaker\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.CircuitBreakerDefinition\" }, \"circuitBreaker\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.CircuitBreakerDefinition\" }, \"claim-check\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.ClaimCheckDefinition\" }, \"claimCheck\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.ClaimCheckDefinition\" }, \"convert-body-to\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.ConvertBodyDefinition\" }, \"convertBodyTo\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.ConvertBodyDefinition\" }, \"delay\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.DelayDefinition\" }, \"dynamic-router\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.DynamicRouterDefinition\" }, \"dynamicRouter\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.DynamicRouterDefinition\" }, \"enrich\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.EnrichDefinition\" }, \"filter\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.FilterDefinition\" }, \"do-finally\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.FinallyDefinition\" }, \"doFinally\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.FinallyDefinition\" }, \"idempotent-consumer\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.IdempotentConsumerDefinition\" }, \"idempotentConsumer\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.IdempotentConsumerDefinition\" }, \"in-only\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.InOnlyDefinition\" }, \"inOnly\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.InOnlyDefinition\" }, \"in-out\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.InOutDefinition\" }, \"inOut\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.InOutDefinition\" }, \"intercept\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.InterceptDefinition\" }, \"intercept-from\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.InterceptFromDefinition\" }, \"interceptFrom\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.InterceptFromDefinition\" }, \"intercept-send-to-endpoint\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.InterceptSendToEndpointDefinition\" }, \"interceptSendToEndpoint\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.InterceptSendToEndpointDefinition\" }, \"kamelet\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.KameletDefinition\" }, \"load-balance\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.LoadBalanceDefinition\" }, \"loadBalance\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.LoadBalanceDefinition\" }, \"log\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.LogDefinition\" }, \"loop\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.LoopDefinition\" }, \"marshal\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.MarshalDefinition\" }, \"multicast\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.MulticastDefinition\" }, \"on-completion\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.OnCompletionDefinition\" }, \"onCompletion\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.OnCompletionDefinition\" }, \"on-fallback\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.OnFallbackDefinition\" }, \"onFallback\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.OnFallbackDefinition\" }, \"otherwise\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.OtherwiseDefinition\" }, \"pausable\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.PausableDefinition\" }, \"pipeline\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.PipelineDefinition\" }, \"policy\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.PolicyDefinition\" }, \"poll-enrich\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.PollEnrichDefinition\" }, \"pollEnrich\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.PollEnrichDefinition\" }, \"process\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.ProcessDefinition\" }, \"recipient-list\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.RecipientListDefinition\" }, \"recipientList\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.RecipientListDefinition\" }, \"remove-header\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.RemoveHeaderDefinition\" }, \"removeHeader\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.RemoveHeaderDefinition\" }, \"remove-headers\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.RemoveHeadersDefinition\" }, \"removeHeaders\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.RemoveHeadersDefinition\" }, \"remove-properties\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.RemovePropertiesDefinition\" }, \"removeProperties\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.RemovePropertiesDefinition\" }, \"remove-property\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.RemovePropertyDefinition\" }, \"removeProperty\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.RemovePropertyDefinition\" }, \"resequence\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.ResequenceDefinition\" }, \"resumable\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.ResumableDefinition\" }, \"rollback\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.RollbackDefinition\" }, \"routing-slip\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.RoutingSlipDefinition\" }, \"routingSlip\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.RoutingSlipDefinition\" }, \"saga\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.SagaDefinition\" }, \"sample\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.SamplingDefinition\" }, \"script\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.ScriptDefinition\" }, \"set-body\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.SetBodyDefinition\" }, \"setBody\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.SetBodyDefinition\" }, \"set-exchange-pattern\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.SetExchangePatternDefinition\" }, \"setExchangePattern\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.SetExchangePatternDefinition\" }, \"set-header\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.SetHeaderDefinition\" }, \"setHeader\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.SetHeaderDefinition\" }, \"set-property\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.SetPropertyDefinition\" }, \"setProperty\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.SetPropertyDefinition\" }, \"sort\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.SortDefinition\" }, \"split\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.SplitDefinition\" }, \"step\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.StepDefinition\" }, \"stop\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.StopDefinition\" }, \"threads\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.ThreadsDefinition\" }, \"throttle\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.ThrottleDefinition\" }, \"throw-exception\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.ThrowExceptionDefinition\" }, \"throwException\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.ThrowExceptionDefinition\" }, \"to\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.ToDefinition\" }, \"to-d\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.ToDynamicDefinition\" }, \"toD\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.ToDynamicDefinition\" }, \"transacted\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.TransactedDefinition\" }, \"transform\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.TransformDefinition\" }, \"do-try\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.TryDefinition\" }, \"doTry\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.TryDefinition\" }, \"unmarshal\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.UnmarshalDefinition\" }, \"validate\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.ValidateDefinition\" }, \"when\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.WhenDefinition\" }, \"when-skip-send-to-endpoint\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.WhenSkipSendToEndpointDefinition\" }, \"whenSkipSendToEndpoint\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.WhenSkipSendToEndpointDefinition\" }, \"wire-tap\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.WireTapDefinition\" }, \"wireTap\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.WireTapDefinition\" }, \"service-call\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.cloud.ServiceCallDefinition\" }, \"serviceCall\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.cloud.ServiceCallDefinition\" } } }, \"org.apache.camel.dsl.yaml.deserializers.BeansDeserializer\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.dsl.yaml.deserializers.NamedBeanDefinition\" } }, \"org.apache.camel.dsl.yaml.deserializers.ErrorHandlerBuilderDeserializer\" : { \"type\" : \"object\", \"properties\" : { \"dead-letter-channel\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.errorhandler.DeadLetterChannelDefinition\" }, \"default-error-handler\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.errorhandler.DefaultErrorHandlerDefinition\" }, \"jta-transaction-error-handler\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.errorhandler.JtaTransactionErrorHandlerDefinition\" }, \"no-error-handler\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.errorhandler.NoErrorHandlerDefinition\" }, \"ref-error-handler\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.errorhandler.RefErrorHandlerDefinition\" }, \"spring-transaction-error-handler\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.errorhandler.SpringTransactionErrorHandlerDefinition\" } } }, \"org.apache.camel.dsl.yaml.deserializers.NamedBeanDefinition\" : { \"type\" : \"object\", \"properties\" : { \"name\" : { \"type\" : \"string\" }, \"properties\" : { \"type\" : \"object\" }, \"type\" : { \"type\" : \"string\" } }, \"required\" : [ \"name\", \"type\" ] }, \"org.apache.camel.dsl.yaml.deserializers.OutputAwareFromDefinition\" : { \"type\" : \"object\", \"properties\" : { \"description\" : { \"type\" : \"string\" }, \"id\" : { \"type\" : \"string\" }, \"parameters\" : { \"type\" : \"object\" }, \"steps\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.ProcessorDefinition\" } }, \"uri\" : { \"type\" : \"string\" } }, \"required\" : [ \"steps\", \"uri\" ] }, \"org.apache.camel.dsl.yaml.deserializers.RouteFromDefinitionDeserializer\" : { \"type\" : \"object\", \"anyOf\" : [ { \"$ref\" : \"#/items/definitions/org.apache.camel.dsl.yaml.deserializers.OutputAwareFromDefinition\" } ], \"properties\" : { \"description\" : { \"type\" : \"string\" }, \"id\" : { \"type\" : \"string\" }, \"parameters\" : { \"type\" : \"object\" }, \"steps\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.ProcessorDefinition\" } }, \"uri\" : { \"type\" : \"string\" } }, \"required\" : [ \"steps\", \"uri\" ] }, \"org.apache.camel.model.AggregateDefinition\" : { \"type\" : \"object\", \"properties\" : { \"aggregate-controller\" : { \"type\" : \"string\" }, \"aggregation-repository\" : { \"type\" : \"string\" }, \"aggregation-strategy\" : { \"type\" : \"string\" }, \"aggregation-strategy-method-allow-null\" : { \"type\" : \"boolean\" }, \"aggregation-strategy-method-name\" : { \"type\" : \"string\" }, \"close-correlation-key-on-completion\" : { \"type\" : \"number\" }, \"complete-all-on-stop\" : { \"type\" : \"boolean\" }, \"completion-from-batch-consumer\" : { \"type\" : \"boolean\" }, \"completion-interval\" : { \"type\" : \"string\" }, \"completion-on-new-correlation-group\" : { \"type\" : \"boolean\" }, \"completion-predicate\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.ExpressionSubElementDefinition\" }, \"completion-size\" : { \"type\" : \"number\" }, \"completion-size-expression\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.ExpressionSubElementDefinition\" }, \"completion-timeout\" : { \"type\" : \"string\" }, \"completion-timeout-checker-interval\" : { \"type\" : \"string\" }, \"completion-timeout-expression\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.ExpressionSubElementDefinition\" }, \"correlation-expression\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.ExpressionSubElementDefinition\" }, \"description\" : { \"type\" : \"string\" }, \"disabled\" : { \"type\" : \"boolean\" }, \"discard-on-aggregation-failure\" : { \"type\" : \"boolean\" }, \"discard-on-completion-timeout\" : { \"type\" : \"boolean\" }, \"eager-check-completion\" : { \"type\" : \"boolean\" }, \"executor-service\" : { \"type\" : \"string\" }, \"force-completion-on-stop\" : { \"type\" : \"boolean\" }, \"id\" : { \"type\" : \"string\" }, \"ignore-invalid-correlation-keys\" : { \"type\" : \"boolean\" }, \"inherit-error-handler\" : { \"type\" : \"boolean\" }, \"optimistic-lock-retry-policy\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.OptimisticLockRetryPolicyDefinition\" }, \"optimistic-locking\" : { \"type\" : \"boolean\" }, \"parallel-processing\" : { \"type\" : \"boolean\" }, \"steps\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.ProcessorDefinition\" } }, \"timeout-checker-executor-service\" : { \"type\" : \"string\" } }, \"required\" : [ \"aggregation-strategy\" ] }, \"org.apache.camel.model.BeanDefinition\" : { \"oneOf\" : [ { \"type\" : \"string\" }, { \"type\" : \"object\", \"properties\" : { \"bean-type\" : { \"type\" : \"string\" }, \"description\" : { \"type\" : \"string\" }, \"disabled\" : { \"type\" : \"boolean\" }, \"id\" : { \"type\" : \"string\" }, \"inherit-error-handler\" : { \"type\" : \"boolean\" }, \"method\" : { \"type\" : \"string\" }, \"ref\" : { \"type\" : \"string\" }, \"scope\" : { \"type\" : \"string\", \"enum\" : [ \"Singleton\", \"Request\", \"Prototype\" ] } } } ] }, \"org.apache.camel.model.CatchDefinition\" : { \"type\" : \"object\", \"properties\" : { \"description\" : { \"type\" : \"string\" }, \"disabled\" : { \"type\" : \"boolean\" }, \"exception\" : { \"type\" : \"array\", \"items\" : { \"type\" : \"string\" } }, \"id\" : { \"type\" : \"string\" }, \"inherit-error-handler\" : { \"type\" : \"boolean\" }, \"on-when\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.WhenDefinition\" }, \"steps\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.ProcessorDefinition\" } } } }, \"org.apache.camel.model.ChoiceDefinition\" : { \"type\" : \"object\", \"properties\" : { \"description\" : { \"type\" : \"string\" }, \"disabled\" : { \"type\" : \"boolean\" }, \"id\" : { \"type\" : \"string\" }, \"inherit-error-handler\" : { \"type\" : \"boolean\" }, \"otherwise\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.OtherwiseDefinition\" }, \"precondition\" : { \"type\" : \"boolean\" }, \"steps\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.ProcessorDefinition\" } }, \"when\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.WhenDefinition\" } } } }, \"org.apache.camel.model.CircuitBreakerDefinition\" : { \"type\" : \"object\", \"properties\" : { \"configuration\" : { \"type\" : \"string\" }, \"description\" : { \"type\" : \"string\" }, \"disabled\" : { \"type\" : \"boolean\" }, \"fault-tolerance-configuration\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.FaultToleranceConfigurationDefinition\" }, \"id\" : { \"type\" : \"string\" }, \"inherit-error-handler\" : { \"type\" : \"boolean\" }, \"on-fallback\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.OnFallbackDefinition\" }, \"resilience4j-configuration\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.Resilience4jConfigurationDefinition\" }, \"steps\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.ProcessorDefinition\" } } } }, \"org.apache.camel.model.ClaimCheckDefinition\" : { \"type\" : \"object\", \"properties\" : { \"aggregation-strategy\" : { \"type\" : \"string\" }, \"aggregation-strategy-method-name\" : { \"type\" : \"string\" }, \"description\" : { \"type\" : \"string\" }, \"disabled\" : { \"type\" : \"boolean\" }, \"filter\" : { \"type\" : \"string\" }, \"id\" : { \"type\" : \"string\" }, \"inherit-error-handler\" : { \"type\" : \"boolean\" }, \"key\" : { \"type\" : \"string\" }, \"operation\" : { \"type\" : \"string\", \"enum\" : [ \"Get\", \"GetAndRemove\", \"Set\", \"Push\", \"Pop\" ] } }, \"required\" : [ \"operation\" ] }, \"org.apache.camel.model.ContextScanDefinition\" : { \"type\" : \"object\", \"properties\" : { \"excludes\" : { \"type\" : \"array\", \"items\" : { \"type\" : \"string\" } }, \"include-non-singletons\" : { \"type\" : \"boolean\" }, \"includes\" : { \"type\" : \"array\", \"items\" : { \"type\" : \"string\" } } } }, \"org.apache.camel.model.ConvertBodyDefinition\" : { \"oneOf\" : [ { \"type\" : \"string\" }, { \"type\" : \"object\", \"properties\" : { \"charset\" : { \"type\" : \"string\" }, \"description\" : { \"type\" : \"string\" }, \"disabled\" : { \"type\" : \"boolean\" }, \"id\" : { \"type\" : \"string\" }, \"inherit-error-handler\" : { \"type\" : \"boolean\" }, \"mandatory\" : { \"type\" : \"boolean\" }, \"type\" : { \"type\" : \"string\" } } } ], \"required\" : [ \"type\" ] }, \"org.apache.camel.model.DataFormatDefinition\" : { \"type\" : \"object\", \"properties\" : { \"id\" : { \"type\" : \"string\" } } }, \"org.apache.camel.model.DelayDefinition\" : { \"type\" : \"object\", \"anyOf\" : [ { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.ExpressionDefinition\" } ], \"properties\" : { \"async-delayed\" : { \"type\" : \"boolean\" }, \"caller-runs-when-rejected\" : { \"type\" : \"boolean\" }, \"description\" : { \"type\" : \"string\" }, \"disabled\" : { \"type\" : \"boolean\" }, \"executor-service\" : { \"type\" : \"string\" }, \"expression\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.ExpressionDefinition\" }, \"id\" : { \"type\" : \"string\" }, \"inherit-error-handler\" : { \"type\" : \"boolean\" } } }, \"org.apache.camel.model.DescriptionDefinition\" : { \"oneOf\" : [ { \"type\" : \"string\" }, { \"type\" : \"object\", \"properties\" : { \"lang\" : { \"type\" : \"string\" }, \"text\" : { \"type\" : \"string\" } } } ] }, \"org.apache.camel.model.DynamicRouterDefinition\" : { \"type\" : \"object\", \"anyOf\" : [ { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.ExpressionDefinition\" } ], \"properties\" : { \"cache-size\" : { \"type\" : \"number\" }, \"description\" : { \"type\" : \"string\" }, \"disabled\" : { \"type\" : \"boolean\" }, \"expression\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.ExpressionDefinition\" }, \"id\" : { \"type\" : \"string\" }, \"ignore-invalid-endpoints\" : { \"type\" : \"boolean\" }, \"inherit-error-handler\" : { \"type\" : \"boolean\" }, \"uri-delimiter\" : { \"type\" : \"string\" } } }, \"org.apache.camel.model.EnrichDefinition\" : { \"type\" : \"object\", \"anyOf\" : [ { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.ExpressionDefinition\" } ], \"properties\" : { \"aggregate-on-exception\" : { \"type\" : \"boolean\" }, \"aggregation-strategy\" : { \"type\" : \"string\" }, \"aggregation-strategy-method-allow-null\" : { \"type\" : \"string\" }, \"aggregation-strategy-method-name\" : { \"type\" : \"string\" }, \"allow-optimised-components\" : { \"type\" : \"boolean\" }, \"cache-size\" : { \"type\" : \"number\" }, \"description\" : { \"type\" : \"string\" }, \"disabled\" : { \"type\" : \"boolean\" }, \"expression\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.ExpressionDefinition\" }, \"id\" : { \"type\" : \"string\" }, \"ignore-invalid-endpoint\" : { \"type\" : \"boolean\" }, \"inherit-error-handler\" : { \"type\" : \"boolean\" }, \"share-unit-of-work\" : { \"type\" : \"boolean\" } } }, \"org.apache.camel.model.ErrorHandlerDefinition\" : { \"type\" : \"object\", \"properties\" : { \"dead-letter-channel\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.errorhandler.DeadLetterChannelDefinition\" }, \"default-error-handler\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.errorhandler.DefaultErrorHandlerDefinition\" }, \"id\" : { \"type\" : \"string\" }, \"jta-transaction-error-handler\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.errorhandler.JtaTransactionErrorHandlerDefinition\" }, \"no-error-handler\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.errorhandler.NoErrorHandlerDefinition\" }, \"spring-transaction-error-handler\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.errorhandler.SpringTransactionErrorHandlerDefinition\" } } }, \"org.apache.camel.model.ExpressionSubElementDefinition\" : { \"type\" : \"object\", \"properties\" : { \"constant\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.ConstantExpression\" }, \"csimple\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.CSimpleExpression\" }, \"datasonnet\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.DatasonnetExpression\" }, \"exchange-property\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.ExchangePropertyExpression\" }, \"exchangeProperty\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.ExchangePropertyExpression\" }, \"groovy\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.GroovyExpression\" }, \"header\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.HeaderExpression\" }, \"hl7terser\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.Hl7TerserExpression\" }, \"joor\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.JoorExpression\" }, \"jq\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.JqExpression\" }, \"js\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.JavaScriptExpression\" }, \"jsonpath\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.JsonPathExpression\" }, \"language\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.LanguageExpression\" }, \"method\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.MethodCallExpression\" }, \"mvel\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.MvelExpression\" }, \"ognl\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.OgnlExpression\" }, \"python\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.PythonExpression\" }, \"ref\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.RefExpression\" }, \"simple\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.SimpleExpression\" }, \"spel\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.SpELExpression\" }, \"tokenize\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.TokenizerExpression\" }, \"xpath\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.XPathExpression\" }, \"xquery\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.XQueryExpression\" }, \"xtokenize\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.XMLTokenizerExpression\" } } }, \"org.apache.camel.model.FaultToleranceConfigurationDefinition\" : { \"type\" : \"object\", \"properties\" : { \"bulkhead-enabled\" : { \"type\" : \"boolean\" }, \"bulkhead-executor-service\" : { \"type\" : \"string\" }, \"bulkhead-max-concurrent-calls\" : { \"type\" : \"number\" }, \"bulkhead-waiting-task-queue\" : { \"type\" : \"number\" }, \"circuit-breaker\" : { \"type\" : \"string\" }, \"delay\" : { \"type\" : \"string\" }, \"failure-ratio\" : { \"type\" : \"number\" }, \"id\" : { \"type\" : \"string\" }, \"request-volume-threshold\" : { \"type\" : \"number\" }, \"success-threshold\" : { \"type\" : \"number\" }, \"timeout-duration\" : { \"type\" : \"string\" }, \"timeout-enabled\" : { \"type\" : \"boolean\" }, \"timeout-pool-size\" : { \"type\" : \"number\" }, \"timeout-scheduled-executor-service\" : { \"type\" : \"string\" } } }, \"org.apache.camel.model.FilterDefinition\" : { \"type\" : \"object\", \"anyOf\" : [ { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.ExpressionDefinition\" } ], \"properties\" : { \"description\" : { \"type\" : \"string\" }, \"disabled\" : { \"type\" : \"boolean\" }, \"expression\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.ExpressionDefinition\" }, \"id\" : { \"type\" : \"string\" }, \"inherit-error-handler\" : { \"type\" : \"boolean\" }, \"status-property-name\" : { \"type\" : \"string\" }, \"steps\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.ProcessorDefinition\" } } } }, \"org.apache.camel.model.FinallyDefinition\" : { \"type\" : \"object\", \"properties\" : { \"description\" : { \"type\" : \"string\" }, \"disabled\" : { \"type\" : \"boolean\" }, \"id\" : { \"type\" : \"string\" }, \"inherit-error-handler\" : { \"type\" : \"boolean\" }, \"steps\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.ProcessorDefinition\" } } } }, \"org.apache.camel.model.FromDefinition\" : { \"type\" : \"object\", \"properties\" : { \"description\" : { \"type\" : \"string\" }, \"id\" : { \"type\" : \"string\" }, \"parameters\" : { \"type\" : \"object\" }, \"steps\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.ProcessorDefinition\" } }, \"uri\" : { \"type\" : \"string\" } }, \"required\" : [ \"steps\", \"uri\" ] }, \"org.apache.camel.model.GlobalOptionDefinition\" : { \"type\" : \"object\", \"properties\" : { \"key\" : { \"type\" : \"string\" }, \"value\" : { \"type\" : \"string\" } }, \"required\" : [ \"key\", \"value\" ] }, \"org.apache.camel.model.GlobalOptionsDefinition\" : { \"type\" : \"object\", \"properties\" : { \"global-option\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.GlobalOptionDefinition\" } } } }, \"org.apache.camel.model.IdempotentConsumerDefinition\" : { \"type\" : \"object\", \"anyOf\" : [ { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.ExpressionDefinition\" } ], \"properties\" : { \"completion-eager\" : { \"type\" : \"boolean\" }, \"description\" : { \"type\" : \"string\" }, \"disabled\" : { \"type\" : \"boolean\" }, \"eager\" : { \"type\" : \"boolean\" }, \"expression\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.ExpressionDefinition\" }, \"id\" : { \"type\" : \"string\" }, \"idempotent-repository\" : { \"type\" : \"string\" }, \"inherit-error-handler\" : { \"type\" : \"boolean\" }, \"remove-on-failure\" : { \"type\" : \"boolean\" }, \"skip-duplicate\" : { \"type\" : \"boolean\" }, \"steps\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.ProcessorDefinition\" } } }, \"required\" : [ \"idempotent-repository\" ] }, \"org.apache.camel.model.InOnlyDefinition\" : { \"oneOf\" : [ { \"type\" : \"string\" }, { \"type\" : \"object\", \"properties\" : { \"description\" : { \"type\" : \"string\" }, \"disabled\" : { \"type\" : \"boolean\" }, \"id\" : { \"type\" : \"string\" }, \"inherit-error-handler\" : { \"type\" : \"boolean\" }, \"parameters\" : { \"type\" : \"object\" }, \"uri\" : { \"type\" : \"string\" } } } ], \"required\" : [ \"uri\" ] }, \"org.apache.camel.model.InOutDefinition\" : { \"oneOf\" : [ { \"type\" : \"string\" }, { \"type\" : \"object\", \"properties\" : { \"description\" : { \"type\" : \"string\" }, \"disabled\" : { \"type\" : \"boolean\" }, \"id\" : { \"type\" : \"string\" }, \"inherit-error-handler\" : { \"type\" : \"boolean\" }, \"parameters\" : { \"type\" : \"object\" }, \"uri\" : { \"type\" : \"string\" } } } ], \"required\" : [ \"uri\" ] }, \"org.apache.camel.model.InputTypeDefinition\" : { \"type\" : \"object\", \"properties\" : { \"description\" : { \"type\" : \"string\" }, \"id\" : { \"type\" : \"string\" }, \"urn\" : { \"type\" : \"string\" }, \"validate\" : { \"type\" : \"boolean\" } }, \"required\" : [ \"urn\" ] }, \"org.apache.camel.model.InterceptDefinition\" : { \"type\" : \"object\", \"properties\" : { \"description\" : { \"type\" : \"string\" }, \"disabled\" : { \"type\" : \"boolean\" }, \"id\" : { \"type\" : \"string\" }, \"inherit-error-handler\" : { \"type\" : \"boolean\" }, \"steps\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.ProcessorDefinition\" } } } }, \"org.apache.camel.model.InterceptFromDefinition\" : { \"oneOf\" : [ { \"type\" : \"string\" }, { \"type\" : \"object\", \"properties\" : { \"description\" : { \"type\" : \"string\" }, \"disabled\" : { \"type\" : \"boolean\" }, \"id\" : { \"type\" : \"string\" }, \"inherit-error-handler\" : { \"type\" : \"boolean\" }, \"steps\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.ProcessorDefinition\" } }, \"uri\" : { \"type\" : \"string\" } } } ] }, \"org.apache.camel.model.InterceptSendToEndpointDefinition\" : { \"oneOf\" : [ { \"type\" : \"string\" }, { \"type\" : \"object\", \"properties\" : { \"after-uri\" : { \"type\" : \"string\" }, \"description\" : { \"type\" : \"string\" }, \"disabled\" : { \"type\" : \"boolean\" }, \"id\" : { \"type\" : \"string\" }, \"inherit-error-handler\" : { \"type\" : \"boolean\" }, \"skip-send-to-original-endpoint\" : { \"type\" : \"string\" }, \"steps\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.ProcessorDefinition\" } }, \"uri\" : { \"type\" : \"string\" } } } ], \"required\" : [ \"uri\" ] }, \"org.apache.camel.model.KameletDefinition\" : { \"oneOf\" : [ { \"type\" : \"string\" }, { \"type\" : \"object\", \"properties\" : { \"inherit-error-handler\" : { \"type\" : \"boolean\" }, \"name\" : { \"type\" : \"string\" }, \"parameters\" : { \"type\" : \"object\" }, \"steps\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.ProcessorDefinition\" } } } } ], \"required\" : [ \"name\" ] }, \"org.apache.camel.model.LoadBalanceDefinition\" : { \"type\" : \"object\", \"properties\" : { \"custom-load-balancer\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.loadbalancer.CustomLoadBalancerDefinition\" }, \"description\" : { \"type\" : \"string\" }, \"disabled\" : { \"type\" : \"boolean\" }, \"failover\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.loadbalancer.FailoverLoadBalancerDefinition\" }, \"id\" : { \"type\" : \"string\" }, \"inherit-error-handler\" : { \"type\" : \"boolean\" }, \"random\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.loadbalancer.RandomLoadBalancerDefinition\" }, \"round-robin\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.loadbalancer.RoundRobinLoadBalancerDefinition\" }, \"steps\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.ProcessorDefinition\" } }, \"sticky\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.loadbalancer.StickyLoadBalancerDefinition\" }, \"topic\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.loadbalancer.TopicLoadBalancerDefinition\" }, \"weighted\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.loadbalancer.WeightedLoadBalancerDefinition\" } } }, \"org.apache.camel.model.LogDefinition\" : { \"oneOf\" : [ { \"type\" : \"string\" }, { \"type\" : \"object\", \"properties\" : { \"description\" : { \"type\" : \"string\" }, \"disabled\" : { \"type\" : \"boolean\" }, \"id\" : { \"type\" : \"string\" }, \"inherit-error-handler\" : { \"type\" : \"boolean\" }, \"log-name\" : { \"type\" : \"string\" }, \"logger\" : { \"type\" : \"string\" }, \"logging-level\" : { \"type\" : \"string\", \"enum\" : [ \"TRACE\", \"DEBUG\", \"INFO\", \"WARN\", \"ERROR\", \"OFF\" ] }, \"marker\" : { \"type\" : \"string\" }, \"message\" : { \"type\" : \"string\" } } } ], \"required\" : [ \"message\" ] }, \"org.apache.camel.model.LoopDefinition\" : { \"type\" : \"object\", \"anyOf\" : [ { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.ExpressionDefinition\" } ], \"properties\" : { \"break-on-shutdown\" : { \"type\" : \"boolean\" }, \"copy\" : { \"type\" : \"boolean\" }, \"description\" : { \"type\" : \"string\" }, \"disabled\" : { \"type\" : \"boolean\" }, \"do-while\" : { \"type\" : \"boolean\" }, \"expression\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.ExpressionDefinition\" }, \"id\" : { \"type\" : \"string\" }, \"inherit-error-handler\" : { \"type\" : \"boolean\" }, \"steps\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.ProcessorDefinition\" } } } }, \"org.apache.camel.model.MarshalDefinition\" : { \"type\" : \"object\", \"properties\" : { \"any23\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.Any23DataFormat\" }, \"asn1\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.ASN1DataFormat\" }, \"avro\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.AvroDataFormat\" }, \"barcode\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.BarcodeDataFormat\" }, \"base64\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.Base64DataFormat\" }, \"bindy\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.BindyDataFormat\" }, \"cbor\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.CBORDataFormat\" }, \"crypto\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.CryptoDataFormat\" }, \"csv\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.CsvDataFormat\" }, \"custom\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.CustomDataFormat\" }, \"description\" : { \"type\" : \"string\" }, \"disabled\" : { \"type\" : \"boolean\" }, \"fhir-json\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.FhirJsonDataFormat\" }, \"fhir-xml\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.FhirXmlDataFormat\" }, \"flatpack\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.FlatpackDataFormat\" }, \"grok\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.GrokDataFormat\" }, \"gzip-deflater\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.GzipDeflaterDataFormat\" }, \"hl7\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.HL7DataFormat\" }, \"ical\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.IcalDataFormat\" }, \"id\" : { \"type\" : \"string\" }, \"inherit-error-handler\" : { \"type\" : \"boolean\" }, \"jackson-xml\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.JacksonXMLDataFormat\" }, \"jaxb\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.JaxbDataFormat\" }, \"json\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.JsonDataFormat\" }, \"json-api\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.JsonApiDataFormat\" }, \"lzf\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.LZFDataFormat\" }, \"mime-multipart\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.MimeMultipartDataFormat\" }, \"pgp\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.PGPDataFormat\" }, \"protobuf\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.ProtobufDataFormat\" }, \"rss\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.RssDataFormat\" }, \"soap\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.SoapDataFormat\" }, \"swift-mt\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.SwiftMtDataFormat\" }, \"swift-mx\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.SwiftMxDataFormat\" }, \"syslog\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.SyslogDataFormat\" }, \"tar-file\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.TarFileDataFormat\" }, \"thrift\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.ThriftDataFormat\" }, \"tidy-markup\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.TidyMarkupDataFormat\" }, \"univocity-csv\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.UniVocityCsvDataFormat\" }, \"univocity-fixed\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.UniVocityFixedDataFormat\" }, \"univocity-tsv\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.UniVocityTsvDataFormat\" }, \"xml-security\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.XMLSecurityDataFormat\" }, \"xstream\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.XStreamDataFormat\" }, \"yaml\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.YAMLDataFormat\" }, \"zip-deflater\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.ZipDeflaterDataFormat\" }, \"zip-file\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.ZipFileDataFormat\" } } }, \"org.apache.camel.model.MulticastDefinition\" : { \"type\" : \"object\", \"properties\" : { \"aggregation-strategy\" : { \"type\" : \"string\" }, \"aggregation-strategy-method-allow-null\" : { \"type\" : \"boolean\" }, \"aggregation-strategy-method-name\" : { \"type\" : \"string\" }, \"description\" : { \"type\" : \"string\" }, \"disabled\" : { \"type\" : \"boolean\" }, \"executor-service\" : { \"type\" : \"string\" }, \"id\" : { \"type\" : \"string\" }, \"inherit-error-handler\" : { \"type\" : \"boolean\" }, \"on-prepare\" : { \"type\" : \"string\" }, \"parallel-aggregate\" : { \"type\" : \"boolean\" }, \"parallel-processing\" : { \"type\" : \"boolean\" }, \"share-unit-of-work\" : { \"type\" : \"boolean\" }, \"steps\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.ProcessorDefinition\" } }, \"stop-on-exception\" : { \"type\" : \"boolean\" }, \"streaming\" : { \"type\" : \"boolean\" }, \"timeout\" : { \"type\" : \"string\" } } }, \"org.apache.camel.model.OnCompletionDefinition\" : { \"type\" : \"object\", \"properties\" : { \"description\" : { \"type\" : \"string\" }, \"disabled\" : { \"type\" : \"boolean\" }, \"executor-service\" : { \"type\" : \"string\" }, \"id\" : { \"type\" : \"string\" }, \"inherit-error-handler\" : { \"type\" : \"boolean\" }, \"mode\" : { \"type\" : \"string\", \"enum\" : [ \"AfterConsumer\", \"BeforeConsumer\" ] }, \"on-complete-only\" : { \"type\" : \"boolean\" }, \"on-failure-only\" : { \"type\" : \"boolean\" }, \"on-when\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.WhenDefinition\" }, \"parallel-processing\" : { \"type\" : \"boolean\" }, \"steps\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.ProcessorDefinition\" } }, \"use-original-message\" : { \"type\" : \"boolean\" } } }, \"org.apache.camel.model.OnExceptionDefinition\" : { \"type\" : \"object\", \"properties\" : { \"continued\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.ExpressionSubElementDefinition\" }, \"description\" : { \"type\" : \"string\" }, \"disabled\" : { \"type\" : \"boolean\" }, \"exception\" : { \"type\" : \"array\", \"items\" : { \"type\" : \"string\" } }, \"handled\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.ExpressionSubElementDefinition\" }, \"id\" : { \"type\" : \"string\" }, \"inherit-error-handler\" : { \"type\" : \"boolean\" }, \"on-exception-occurred-ref\" : { \"type\" : \"string\" }, \"on-redelivery-ref\" : { \"type\" : \"string\" }, \"on-when\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.WhenDefinition\" }, \"redelivery-policy\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.RedeliveryPolicyDefinition\" }, \"redelivery-policy-ref\" : { \"type\" : \"string\" }, \"retry-while\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.ExpressionSubElementDefinition\" }, \"steps\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.ProcessorDefinition\" } }, \"use-original-body\" : { \"type\" : \"boolean\" }, \"use-original-message\" : { \"type\" : \"boolean\" } } }, \"org.apache.camel.model.OnFallbackDefinition\" : { \"type\" : \"object\", \"properties\" : { \"description\" : { \"type\" : \"string\" }, \"disabled\" : { \"type\" : \"boolean\" }, \"fallback-via-network\" : { \"type\" : \"boolean\" }, \"id\" : { \"type\" : \"string\" }, \"inherit-error-handler\" : { \"type\" : \"boolean\" }, \"steps\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.ProcessorDefinition\" } } } }, \"org.apache.camel.model.OptimisticLockRetryPolicyDefinition\" : { \"type\" : \"object\", \"properties\" : { \"exponential-back-off\" : { \"type\" : \"boolean\" }, \"maximum-retries\" : { \"type\" : \"number\" }, \"maximum-retry-delay\" : { \"type\" : \"string\" }, \"random-back-off\" : { \"type\" : \"boolean\" }, \"retry-delay\" : { \"type\" : \"string\" } } }, \"org.apache.camel.model.OtherwiseDefinition\" : { \"type\" : \"object\", \"properties\" : { \"description\" : { \"type\" : \"string\" }, \"disabled\" : { \"type\" : \"boolean\" }, \"id\" : { \"type\" : \"string\" }, \"inherit-error-handler\" : { \"type\" : \"boolean\" }, \"steps\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.ProcessorDefinition\" } } } }, \"org.apache.camel.model.OutputDefinition\" : { \"type\" : \"object\", \"properties\" : { \"description\" : { \"type\" : \"string\" }, \"disabled\" : { \"type\" : \"boolean\" }, \"id\" : { \"type\" : \"string\" }, \"inherit-error-handler\" : { \"type\" : \"boolean\" }, \"steps\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.ProcessorDefinition\" } } } }, \"org.apache.camel.model.OutputTypeDefinition\" : { \"type\" : \"object\", \"properties\" : { \"description\" : { \"type\" : \"string\" }, \"id\" : { \"type\" : \"string\" }, \"urn\" : { \"type\" : \"string\" }, \"validate\" : { \"type\" : \"boolean\" } }, \"required\" : [ \"urn\" ] }, \"org.apache.camel.model.PackageScanDefinition\" : { \"type\" : \"object\", \"properties\" : { \"excludes\" : { \"type\" : \"array\", \"items\" : { \"type\" : \"string\" } }, \"includes\" : { \"type\" : \"array\", \"items\" : { \"type\" : \"string\" } }, \"package\" : { \"type\" : \"array\", \"items\" : { \"type\" : \"string\" } } } }, \"org.apache.camel.model.PausableDefinition\" : { \"type\" : \"object\", \"properties\" : { \"consumer-listener\" : { \"type\" : \"string\" }, \"description\" : { \"type\" : \"string\" }, \"disabled\" : { \"type\" : \"boolean\" }, \"id\" : { \"type\" : \"string\" }, \"inherit-error-handler\" : { \"type\" : \"boolean\" }, \"until-check\" : { \"type\" : \"string\" } }, \"required\" : [ \"consumer-listener\", \"until-check\" ] }, \"org.apache.camel.model.PipelineDefinition\" : { \"type\" : \"object\", \"properties\" : { \"description\" : { \"type\" : \"string\" }, \"disabled\" : { \"type\" : \"boolean\" }, \"id\" : { \"type\" : \"string\" }, \"inherit-error-handler\" : { \"type\" : \"boolean\" }, \"steps\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.ProcessorDefinition\" } } } }, \"org.apache.camel.model.PolicyDefinition\" : { \"type\" : \"object\", \"properties\" : { \"description\" : { \"type\" : \"string\" }, \"disabled\" : { \"type\" : \"boolean\" }, \"id\" : { \"type\" : \"string\" }, \"inherit-error-handler\" : { \"type\" : \"boolean\" }, \"ref\" : { \"type\" : \"string\" }, \"steps\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.ProcessorDefinition\" } } }, \"required\" : [ \"ref\" ] }, \"org.apache.camel.model.PollEnrichDefinition\" : { \"type\" : \"object\", \"anyOf\" : [ { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.ExpressionDefinition\" } ], \"properties\" : { \"aggregate-on-exception\" : { \"type\" : \"boolean\" }, \"aggregation-strategy\" : { \"type\" : \"string\" }, \"aggregation-strategy-method-allow-null\" : { \"type\" : \"string\" }, \"aggregation-strategy-method-name\" : { \"type\" : \"string\" }, \"cache-size\" : { \"type\" : \"number\" }, \"description\" : { \"type\" : \"string\" }, \"disabled\" : { \"type\" : \"boolean\" }, \"expression\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.ExpressionDefinition\" }, \"id\" : { \"type\" : \"string\" }, \"ignore-invalid-endpoint\" : { \"type\" : \"boolean\" }, \"inherit-error-handler\" : { \"type\" : \"boolean\" }, \"timeout\" : { \"type\" : \"string\" } } }, \"org.apache.camel.model.ProcessDefinition\" : { \"type\" : \"object\", \"properties\" : { \"description\" : { \"type\" : \"string\" }, \"disabled\" : { \"type\" : \"boolean\" }, \"id\" : { \"type\" : \"string\" }, \"inherit-error-handler\" : { \"type\" : \"boolean\" }, \"ref\" : { \"type\" : \"string\" } }, \"required\" : [ \"ref\" ] }, \"org.apache.camel.model.PropertyDefinition\" : { \"type\" : \"object\", \"properties\" : { \"key\" : { \"type\" : \"string\" }, \"value\" : { \"type\" : \"string\" } }, \"required\" : [ \"key\", \"value\" ] }, \"org.apache.camel.model.PropertyExpressionDefinition\" : { \"type\" : \"object\", \"properties\" : { \"expression\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.ExpressionDefinition\" }, \"key\" : { \"type\" : \"string\" } }, \"required\" : [ \"key\" ] }, \"org.apache.camel.model.RecipientListDefinition\" : { \"type\" : \"object\", \"anyOf\" : [ { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.ExpressionDefinition\" } ], \"properties\" : { \"aggregation-strategy\" : { \"type\" : \"string\" }, \"aggregation-strategy-method-allow-null\" : { \"type\" : \"boolean\" }, \"aggregation-strategy-method-name\" : { \"type\" : \"string\" }, \"cache-size\" : { \"type\" : \"number\" }, \"delimiter\" : { \"type\" : \"string\" }, \"description\" : { \"type\" : \"string\" }, \"disabled\" : { \"type\" : \"boolean\" }, \"executor-service\" : { \"type\" : \"string\" }, \"expression\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.ExpressionDefinition\" }, \"id\" : { \"type\" : \"string\" }, \"ignore-invalid-endpoints\" : { \"type\" : \"boolean\" }, \"inherit-error-handler\" : { \"type\" : \"boolean\" }, \"on-prepare\" : { \"type\" : \"string\" }, \"parallel-aggregate\" : { \"type\" : \"boolean\" }, \"parallel-processing\" : { \"type\" : \"boolean\" }, \"share-unit-of-work\" : { \"type\" : \"boolean\" }, \"stop-on-exception\" : { \"type\" : \"boolean\" }, \"streaming\" : { \"type\" : \"boolean\" }, \"timeout\" : { \"type\" : \"string\" } } }, \"org.apache.camel.model.RedeliveryPolicyDefinition\" : { \"type\" : \"object\", \"properties\" : { \"allow-redelivery-while-stopping\" : { \"type\" : \"boolean\" }, \"async-delayed-redelivery\" : { \"type\" : \"boolean\" }, \"back-off-multiplier\" : { \"type\" : \"number\" }, \"collision-avoidance-factor\" : { \"type\" : \"number\" }, \"delay-pattern\" : { \"type\" : \"string\" }, \"disable-redelivery\" : { \"type\" : \"boolean\" }, \"exchange-formatter-ref\" : { \"type\" : \"string\" }, \"id\" : { \"type\" : \"string\" }, \"log-continued\" : { \"type\" : \"boolean\" }, \"log-exhausted\" : { \"type\" : \"boolean\" }, \"log-exhausted-message-body\" : { \"type\" : \"boolean\" }, \"log-exhausted-message-history\" : { \"type\" : \"boolean\" }, \"log-handled\" : { \"type\" : \"boolean\" }, \"log-new-exception\" : { \"type\" : \"boolean\" }, \"log-retry-attempted\" : { \"type\" : \"boolean\" }, \"log-retry-stack-trace\" : { \"type\" : \"boolean\" }, \"log-stack-trace\" : { \"type\" : \"boolean\" }, \"maximum-redeliveries\" : { \"type\" : \"number\" }, \"maximum-redelivery-delay\" : { \"type\" : \"string\" }, \"redelivery-delay\" : { \"type\" : \"string\" }, \"retries-exhausted-log-level\" : { \"type\" : \"string\" }, \"retry-attempted-log-interval\" : { \"type\" : \"number\" }, \"retry-attempted-log-level\" : { \"type\" : \"string\" }, \"use-collision-avoidance\" : { \"type\" : \"boolean\" }, \"use-exponential-back-off\" : { \"type\" : \"boolean\" } } }, \"org.apache.camel.model.RemoveHeaderDefinition\" : { \"oneOf\" : [ { \"type\" : \"string\" }, { \"type\" : \"object\", \"properties\" : { \"description\" : { \"type\" : \"string\" }, \"disabled\" : { \"type\" : \"boolean\" }, \"id\" : { \"type\" : \"string\" }, \"inherit-error-handler\" : { \"type\" : \"boolean\" }, \"name\" : { \"type\" : \"string\" } } } ], \"required\" : [ \"name\" ] }, \"org.apache.camel.model.RemoveHeadersDefinition\" : { \"oneOf\" : [ { \"type\" : \"string\" }, { \"type\" : \"object\", \"properties\" : { \"description\" : { \"type\" : \"string\" }, \"disabled\" : { \"type\" : \"boolean\" }, \"exclude-pattern\" : { \"type\" : \"string\" }, \"id\" : { \"type\" : \"string\" }, \"inherit-error-handler\" : { \"type\" : \"boolean\" }, \"pattern\" : { \"type\" : \"string\" } } } ], \"required\" : [ \"pattern\" ] }, \"org.apache.camel.model.RemovePropertiesDefinition\" : { \"oneOf\" : [ { \"type\" : \"string\" }, { \"type\" : \"object\", \"properties\" : { \"description\" : { \"type\" : \"string\" }, \"disabled\" : { \"type\" : \"boolean\" }, \"exclude-pattern\" : { \"type\" : \"string\" }, \"id\" : { \"type\" : \"string\" }, \"inherit-error-handler\" : { \"type\" : \"boolean\" }, \"pattern\" : { \"type\" : \"string\" } } } ], \"required\" : [ \"pattern\" ] }, \"org.apache.camel.model.RemovePropertyDefinition\" : { \"oneOf\" : [ { \"type\" : \"string\" }, { \"type\" : \"object\", \"properties\" : { \"description\" : { \"type\" : \"string\" }, \"disabled\" : { \"type\" : \"boolean\" }, \"id\" : { \"type\" : \"string\" }, \"inherit-error-handler\" : { \"type\" : \"boolean\" }, \"name\" : { \"type\" : \"string\" } } } ], \"required\" : [ \"name\" ] }, \"org.apache.camel.model.ResequenceDefinition\" : { \"type\" : \"object\", \"anyOf\" : [ { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.ExpressionDefinition\" } ], \"properties\" : { \"batch-config\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.config.BatchResequencerConfig\" }, \"description\" : { \"type\" : \"string\" }, \"disabled\" : { \"type\" : \"boolean\" }, \"expression\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.ExpressionDefinition\" }, \"id\" : { \"type\" : \"string\" }, \"inherit-error-handler\" : { \"type\" : \"boolean\" }, \"steps\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.ProcessorDefinition\" } }, \"stream-config\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.config.StreamResequencerConfig\" } }, \"required\" : [ \"expression\" ] }, \"org.apache.camel.model.Resilience4jConfigurationDefinition\" : { \"type\" : \"object\", \"properties\" : { \"automatic-transition-from-open-to-half-open-enabled\" : { \"type\" : \"boolean\" }, \"circuit-breaker\" : { \"type\" : \"string\" }, \"config\" : { \"type\" : \"string\" }, \"failure-rate-threshold\" : { \"type\" : \"number\" }, \"id\" : { \"type\" : \"string\" }, \"minimum-number-of-calls\" : { \"type\" : \"number\" }, \"permitted-number-of-calls-in-half-open-state\" : { \"type\" : \"number\" }, \"sliding-window-size\" : { \"type\" : \"number\" }, \"sliding-window-type\" : { \"type\" : \"string\", \"enum\" : [ \"TIME_BASED\", \"COUNT_BASED\" ] }, \"slow-call-duration-threshold\" : { \"type\" : \"number\" }, \"slow-call-rate-threshold\" : { \"type\" : \"number\" }, \"throw-exception-when-half-open-or-open-state\" : { \"type\" : \"boolean\" }, \"wait-duration-in-open-state\" : { \"type\" : \"number\" }, \"writable-stack-trace-enabled\" : { \"type\" : \"boolean\" } } }, \"org.apache.camel.model.RestContextRefDefinition\" : { \"oneOf\" : [ { \"type\" : \"string\" }, { \"type\" : \"object\", \"properties\" : { \"ref\" : { \"type\" : \"string\" } } } ], \"required\" : [ \"ref\" ] }, \"org.apache.camel.model.ResumableDefinition\" : { \"type\" : \"object\", \"properties\" : { \"description\" : { \"type\" : \"string\" }, \"disabled\" : { \"type\" : \"boolean\" }, \"id\" : { \"type\" : \"string\" }, \"inherit-error-handler\" : { \"type\" : \"boolean\" }, \"intermittent\" : { \"type\" : \"boolean\" }, \"resume-strategy\" : { \"type\" : \"string\" } }, \"required\" : [ \"resume-strategy\" ] }, \"org.apache.camel.model.RollbackDefinition\" : { \"oneOf\" : [ { \"type\" : \"string\" }, { \"type\" : \"object\", \"properties\" : { \"description\" : { \"type\" : \"string\" }, \"disabled\" : { \"type\" : \"boolean\" }, \"id\" : { \"type\" : \"string\" }, \"inherit-error-handler\" : { \"type\" : \"boolean\" }, \"mark-rollback-only\" : { \"type\" : \"boolean\" }, \"mark-rollback-only-last\" : { \"type\" : \"boolean\" }, \"message\" : { \"type\" : \"string\" } } } ] }, \"org.apache.camel.model.RouteBuilderDefinition\" : { \"oneOf\" : [ { \"type\" : \"string\" }, { \"type\" : \"object\", \"properties\" : { \"id\" : { \"type\" : \"string\" }, \"ref\" : { \"type\" : \"string\" } } } ], \"required\" : [ \"ref\" ] }, \"org.apache.camel.model.RouteConfigurationContextRefDefinition\" : { \"oneOf\" : [ { \"type\" : \"string\" }, { \"type\" : \"object\", \"properties\" : { \"ref\" : { \"type\" : \"string\" } } } ], \"required\" : [ \"ref\" ] }, \"org.apache.camel.model.RouteConfigurationDefinition\" : { \"type\" : \"object\", \"properties\" : { \"error-handler\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.ErrorHandlerDefinition\" }, \"id\" : { \"type\" : \"string\" }, \"intercept\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.InterceptDefinition\" } }, \"intercept-from\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.InterceptFromDefinition\" } }, \"intercept-send-to-endpoint\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.InterceptSendToEndpointDefinition\" } }, \"on-completion\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.OnCompletionDefinition\" } }, \"on-exception\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.OnExceptionDefinition\" } }, \"precondition\" : { \"type\" : \"string\" } } }, \"org.apache.camel.model.RouteContextRefDefinition\" : { \"oneOf\" : [ { \"type\" : \"string\" }, { \"type\" : \"object\", \"properties\" : { \"ref\" : { \"type\" : \"string\" } } } ], \"required\" : [ \"ref\" ] }, \"org.apache.camel.model.RouteDefinition\" : { \"type\" : \"object\", \"properties\" : { \"auto-startup\" : { \"type\" : \"boolean\" }, \"description\" : { \"type\" : \"string\" }, \"from\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.FromDefinition\" }, \"group\" : { \"type\" : \"string\" }, \"id\" : { \"type\" : \"string\" }, \"log-mask\" : { \"type\" : \"boolean\" }, \"message-history\" : { \"type\" : \"boolean\" }, \"node-prefix-id\" : { \"type\" : \"string\" }, \"precondition\" : { \"type\" : \"string\" }, \"route-configuration-id\" : { \"type\" : \"string\" }, \"route-policy\" : { \"type\" : \"string\" }, \"startup-order\" : { \"type\" : \"number\" }, \"stream-caching\" : { \"type\" : \"boolean\" }, \"trace\" : { \"type\" : \"boolean\" } }, \"required\" : [ \"from\" ] }, \"org.apache.camel.model.RouteTemplateBeanDefinition\" : { \"type\" : \"object\", \"properties\" : { \"bean-type\" : { \"type\" : \"string\" }, \"name\" : { \"type\" : \"string\" }, \"properties\" : { \"type\" : \"object\" }, \"property\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.PropertyDefinition\" } }, \"script\" : { \"type\" : \"string\" }, \"type\" : { \"type\" : \"string\" } }, \"required\" : [ \"name\", \"type\" ] }, \"org.apache.camel.model.RouteTemplateDefinition\" : { \"type\" : \"object\", \"properties\" : { \"beans\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.dsl.yaml.deserializers.NamedBeanDefinition\" } }, \"from\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.FromDefinition\" }, \"id\" : { \"type\" : \"string\" }, \"parameters\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.RouteTemplateParameterDefinition\" } }, \"route\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.RouteDefinition\" } }, \"required\" : [ \"id\" ] }, \"org.apache.camel.model.RouteTemplateParameterDefinition\" : { \"type\" : \"object\", \"properties\" : { \"default-value\" : { \"type\" : \"string\" }, \"description\" : { \"type\" : \"string\" }, \"name\" : { \"type\" : \"string\" }, \"required\" : { \"type\" : \"boolean\" } }, \"required\" : [ \"name\" ] }, \"org.apache.camel.model.RoutingSlipDefinition\" : { \"oneOf\" : [ { \"type\" : \"string\" }, { \"type\" : \"object\", \"properties\" : { \"cache-size\" : { \"type\" : \"number\" }, \"description\" : { \"type\" : \"string\" }, \"disabled\" : { \"type\" : \"boolean\" }, \"expression\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.ExpressionDefinition\" }, \"id\" : { \"type\" : \"string\" }, \"ignore-invalid-endpoints\" : { \"type\" : \"boolean\" }, \"inherit-error-handler\" : { \"type\" : \"boolean\" }, \"uri-delimiter\" : { \"type\" : \"string\" } } } ], \"anyOf\" : [ { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.ExpressionDefinition\" } ] }, \"org.apache.camel.model.SagaActionUriDefinition\" : { \"oneOf\" : [ { \"type\" : \"string\" }, { \"type\" : \"object\", \"properties\" : { \"description\" : { \"type\" : \"string\" }, \"disabled\" : { \"type\" : \"boolean\" }, \"id\" : { \"type\" : \"string\" }, \"inherit-error-handler\" : { \"type\" : \"boolean\" }, \"parameters\" : { \"type\" : \"object\" }, \"uri\" : { \"type\" : \"string\" } } } ], \"required\" : [ \"uri\" ] }, \"org.apache.camel.model.SagaDefinition\" : { \"type\" : \"object\", \"properties\" : { \"compensation\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.SagaActionUriDefinition\" }, \"completion\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.SagaActionUriDefinition\" }, \"completion-mode\" : { \"type\" : \"string\", \"enum\" : [ \"AUTO\", \"MANUAL\" ] }, \"description\" : { \"type\" : \"string\" }, \"disabled\" : { \"type\" : \"boolean\" }, \"id\" : { \"type\" : \"string\" }, \"inherit-error-handler\" : { \"type\" : \"boolean\" }, \"option\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.PropertyExpressionDefinition\" } }, \"propagation\" : { \"type\" : \"string\", \"enum\" : [ \"REQUIRED\", \"REQUIRES_NEW\", \"MANDATORY\", \"SUPPORTS\", \"NOT_SUPPORTED\", \"NEVER\" ] }, \"saga-service\" : { \"type\" : \"string\" }, \"steps\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.ProcessorDefinition\" } }, \"timeout\" : { \"type\" : \"string\" } } }, \"org.apache.camel.model.SamplingDefinition\" : { \"oneOf\" : [ { \"type\" : \"string\" }, { \"type\" : \"object\", \"properties\" : { \"description\" : { \"type\" : \"string\" }, \"disabled\" : { \"type\" : \"boolean\" }, \"id\" : { \"type\" : \"string\" }, \"inherit-error-handler\" : { \"type\" : \"boolean\" }, \"message-frequency\" : { \"type\" : \"number\" }, \"sample-period\" : { \"type\" : \"string\" } } } ] }, \"org.apache.camel.model.ScriptDefinition\" : { \"type\" : \"object\", \"anyOf\" : [ { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.ExpressionDefinition\" } ], \"properties\" : { \"description\" : { \"type\" : \"string\" }, \"disabled\" : { \"type\" : \"boolean\" }, \"expression\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.ExpressionDefinition\" }, \"id\" : { \"type\" : \"string\" }, \"inherit-error-handler\" : { \"type\" : \"boolean\" } } }, \"org.apache.camel.model.SetBodyDefinition\" : { \"type\" : \"object\", \"anyOf\" : [ { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.ExpressionDefinition\" } ], \"properties\" : { \"description\" : { \"type\" : \"string\" }, \"disabled\" : { \"type\" : \"boolean\" }, \"expression\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.ExpressionDefinition\" }, \"id\" : { \"type\" : \"string\" }, \"inherit-error-handler\" : { \"type\" : \"boolean\" } } }, \"org.apache.camel.model.SetExchangePatternDefinition\" : { \"oneOf\" : [ { \"type\" : \"string\" }, { \"type\" : \"object\", \"properties\" : { \"description\" : { \"type\" : \"string\" }, \"disabled\" : { \"type\" : \"boolean\" }, \"id\" : { \"type\" : \"string\" }, \"inherit-error-handler\" : { \"type\" : \"boolean\" }, \"pattern\" : { \"type\" : \"string\", \"enum\" : [ \"InOnly\", \"InOut\", \"InOptionalOut\" ] } } } ], \"required\" : [ \"pattern\" ] }, \"org.apache.camel.model.SetHeaderDefinition\" : { \"type\" : \"object\", \"anyOf\" : [ { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.ExpressionDefinition\" } ], \"properties\" : { \"description\" : { \"type\" : \"string\" }, \"disabled\" : { \"type\" : \"boolean\" }, \"expression\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.ExpressionDefinition\" }, \"id\" : { \"type\" : \"string\" }, \"inherit-error-handler\" : { \"type\" : \"boolean\" }, \"name\" : { \"type\" : \"string\" } }, \"required\" : [ \"name\" ] }, \"org.apache.camel.model.SetPropertyDefinition\" : { \"type\" : \"object\", \"anyOf\" : [ { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.ExpressionDefinition\" } ], \"properties\" : { \"description\" : { \"type\" : \"string\" }, \"disabled\" : { \"type\" : \"boolean\" }, \"expression\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.ExpressionDefinition\" }, \"id\" : { \"type\" : \"string\" }, \"inherit-error-handler\" : { \"type\" : \"boolean\" }, \"name\" : { \"type\" : \"string\" } }, \"required\" : [ \"name\" ] }, \"org.apache.camel.model.SortDefinition\" : { \"type\" : \"object\", \"anyOf\" : [ { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.ExpressionDefinition\" } ], \"properties\" : { \"comparator\" : { \"type\" : \"string\" }, \"description\" : { \"type\" : \"string\" }, \"disabled\" : { \"type\" : \"boolean\" }, \"expression\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.ExpressionDefinition\" }, \"id\" : { \"type\" : \"string\" }, \"inherit-error-handler\" : { \"type\" : \"boolean\" } } }, \"org.apache.camel.model.SplitDefinition\" : { \"type\" : \"object\", \"anyOf\" : [ { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.ExpressionDefinition\" } ], \"properties\" : { \"aggregation-strategy\" : { \"type\" : \"string\" }, \"aggregation-strategy-method-allow-null\" : { \"type\" : \"boolean\" }, \"aggregation-strategy-method-name\" : { \"type\" : \"string\" }, \"delimiter\" : { \"type\" : \"string\" }, \"description\" : { \"type\" : \"string\" }, \"disabled\" : { \"type\" : \"boolean\" }, \"executor-service\" : { \"type\" : \"string\" }, \"expression\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.ExpressionDefinition\" }, \"id\" : { \"type\" : \"string\" }, \"inherit-error-handler\" : { \"type\" : \"boolean\" }, \"on-prepare\" : { \"type\" : \"string\" }, \"parallel-aggregate\" : { \"type\" : \"boolean\" }, \"parallel-processing\" : { \"type\" : \"boolean\" }, \"share-unit-of-work\" : { \"type\" : \"boolean\" }, \"steps\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.ProcessorDefinition\" } }, \"stop-on-exception\" : { \"type\" : \"boolean\" }, \"streaming\" : { \"type\" : \"boolean\" }, \"timeout\" : { \"type\" : \"string\" } } }, \"org.apache.camel.model.StepDefinition\" : { \"type\" : \"object\", \"properties\" : { \"description\" : { \"type\" : \"string\" }, \"disabled\" : { \"type\" : \"boolean\" }, \"id\" : { \"type\" : \"string\" }, \"inherit-error-handler\" : { \"type\" : \"boolean\" }, \"steps\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.ProcessorDefinition\" } } } }, \"org.apache.camel.model.StopDefinition\" : { \"type\" : \"object\", \"properties\" : { \"description\" : { \"type\" : \"string\" }, \"disabled\" : { \"type\" : \"boolean\" }, \"id\" : { \"type\" : \"string\" }, \"inherit-error-handler\" : { \"type\" : \"boolean\" } } }, \"org.apache.camel.model.TemplatedRouteBeanDefinition\" : { \"type\" : \"object\", \"properties\" : { \"bean-type\" : { \"type\" : \"string\" }, \"name\" : { \"type\" : \"string\" }, \"properties\" : { \"type\" : \"object\" }, \"property\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.PropertyDefinition\" } }, \"script\" : { \"type\" : \"string\" }, \"type\" : { \"type\" : \"string\" } }, \"required\" : [ \"name\", \"type\" ] }, \"org.apache.camel.model.TemplatedRouteDefinition\" : { \"type\" : \"object\", \"properties\" : { \"beans\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.dsl.yaml.deserializers.NamedBeanDefinition\" } }, \"parameters\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.TemplatedRouteParameterDefinition\" } }, \"prefix-id\" : { \"type\" : \"string\" }, \"route-id\" : { \"type\" : \"string\" }, \"route-template-ref\" : { \"type\" : \"string\" } }, \"required\" : [ \"route-template-ref\" ] }, \"org.apache.camel.model.TemplatedRouteParameterDefinition\" : { \"type\" : \"object\", \"properties\" : { \"name\" : { \"type\" : \"string\" }, \"value\" : { \"type\" : \"string\" } }, \"required\" : [ \"name\", \"value\" ] }, \"org.apache.camel.model.ThreadPoolProfileDefinition\" : { \"type\" : \"object\", \"properties\" : { \"allow-core-thread-time-out\" : { \"type\" : \"boolean\" }, \"default-profile\" : { \"type\" : \"boolean\" }, \"description\" : { \"type\" : \"string\" }, \"id\" : { \"type\" : \"string\" }, \"keep-alive-time\" : { \"type\" : \"number\" }, \"max-pool-size\" : { \"type\" : \"number\" }, \"max-queue-size\" : { \"type\" : \"number\" }, \"pool-size\" : { \"type\" : \"number\" }, \"rejected-policy\" : { \"type\" : \"string\", \"enum\" : [ \"Abort\", \"CallerRuns\", \"DiscardOldest\", \"Discard\" ] }, \"time-unit\" : { \"type\" : \"string\", \"enum\" : [ \"NANOSECONDS\", \"MICROSECONDS\", \"MILLISECONDS\", \"SECONDS\", \"MINUTES\", \"HOURS\", \"DAYS\" ] } } }, \"org.apache.camel.model.ThreadsDefinition\" : { \"type\" : \"object\", \"properties\" : { \"allow-core-thread-time-out\" : { \"type\" : \"boolean\" }, \"caller-runs-when-rejected\" : { \"type\" : \"string\" }, \"description\" : { \"type\" : \"string\" }, \"disabled\" : { \"type\" : \"boolean\" }, \"executor-service\" : { \"type\" : \"string\" }, \"id\" : { \"type\" : \"string\" }, \"inherit-error-handler\" : { \"type\" : \"boolean\" }, \"keep-alive-time\" : { \"type\" : \"number\" }, \"max-pool-size\" : { \"type\" : \"number\" }, \"max-queue-size\" : { \"type\" : \"number\" }, \"pool-size\" : { \"type\" : \"number\" }, \"rejected-policy\" : { \"type\" : \"string\", \"enum\" : [ \"Abort\", \"CallerRuns\", \"DiscardOldest\", \"Discard\" ] }, \"thread-name\" : { \"type\" : \"string\" }, \"time-unit\" : { \"type\" : \"string\", \"enum\" : [ \"NANOSECONDS\", \"MICROSECONDS\", \"MILLISECONDS\", \"SECONDS\", \"MINUTES\", \"HOURS\", \"DAYS\" ] } } }, \"org.apache.camel.model.ThrottleDefinition\" : { \"type\" : \"object\", \"anyOf\" : [ { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.ExpressionDefinition\" } ], \"properties\" : { \"async-delayed\" : { \"type\" : \"boolean\" }, \"caller-runs-when-rejected\" : { \"type\" : \"boolean\" }, \"correlation-expression\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.ExpressionSubElementDefinition\" }, \"description\" : { \"type\" : \"string\" }, \"disabled\" : { \"type\" : \"boolean\" }, \"executor-service\" : { \"type\" : \"string\" }, \"expression\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.ExpressionDefinition\" }, \"id\" : { \"type\" : \"string\" }, \"inherit-error-handler\" : { \"type\" : \"boolean\" }, \"reject-execution\" : { \"type\" : \"boolean\" }, \"time-period-millis\" : { \"type\" : \"string\" } } }, \"org.apache.camel.model.ThrowExceptionDefinition\" : { \"type\" : \"object\", \"properties\" : { \"description\" : { \"type\" : \"string\" }, \"disabled\" : { \"type\" : \"boolean\" }, \"exception-type\" : { \"type\" : \"string\" }, \"id\" : { \"type\" : \"string\" }, \"inherit-error-handler\" : { \"type\" : \"boolean\" }, \"message\" : { \"type\" : \"string\" }, \"ref\" : { \"type\" : \"string\" } } }, \"org.apache.camel.model.ToDefinition\" : { \"oneOf\" : [ { \"type\" : \"string\" }, { \"type\" : \"object\", \"properties\" : { \"description\" : { \"type\" : \"string\" }, \"disabled\" : { \"type\" : \"boolean\" }, \"id\" : { \"type\" : \"string\" }, \"inherit-error-handler\" : { \"type\" : \"boolean\" }, \"parameters\" : { \"type\" : \"object\" }, \"pattern\" : { \"type\" : \"string\", \"enum\" : [ \"InOnly\", \"InOut\", \"InOptionalOut\" ] }, \"uri\" : { \"type\" : \"string\" } } } ], \"required\" : [ \"uri\" ] }, \"org.apache.camel.model.ToDynamicDefinition\" : { \"oneOf\" : [ { \"type\" : \"string\" }, { \"type\" : \"object\", \"properties\" : { \"allow-optimised-components\" : { \"type\" : \"boolean\" }, \"auto-start-components\" : { \"type\" : \"boolean\" }, \"cache-size\" : { \"type\" : \"number\" }, \"description\" : { \"type\" : \"string\" }, \"disabled\" : { \"type\" : \"boolean\" }, \"id\" : { \"type\" : \"string\" }, \"ignore-invalid-endpoint\" : { \"type\" : \"boolean\" }, \"inherit-error-handler\" : { \"type\" : \"boolean\" }, \"parameters\" : { \"type\" : \"object\" }, \"pattern\" : { \"type\" : \"string\", \"enum\" : [ \"InOnly\", \"InOut\", \"InOptionalOut\" ] }, \"uri\" : { \"type\" : \"string\" } } } ], \"required\" : [ \"uri\" ] }, \"org.apache.camel.model.TransactedDefinition\" : { \"type\" : \"object\", \"properties\" : { \"description\" : { \"type\" : \"string\" }, \"disabled\" : { \"type\" : \"boolean\" }, \"id\" : { \"type\" : \"string\" }, \"inherit-error-handler\" : { \"type\" : \"boolean\" }, \"ref\" : { \"type\" : \"string\" }, \"steps\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.ProcessorDefinition\" } } } }, \"org.apache.camel.model.TransformDefinition\" : { \"type\" : \"object\", \"anyOf\" : [ { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.ExpressionDefinition\" } ], \"properties\" : { \"description\" : { \"type\" : \"string\" }, \"disabled\" : { \"type\" : \"boolean\" }, \"expression\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.ExpressionDefinition\" }, \"id\" : { \"type\" : \"string\" }, \"inherit-error-handler\" : { \"type\" : \"boolean\" } } }, \"org.apache.camel.model.TryDefinition\" : { \"type\" : \"object\", \"properties\" : { \"description\" : { \"type\" : \"string\" }, \"disabled\" : { \"type\" : \"boolean\" }, \"do-catch\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.CatchDefinition\" } }, \"do-finally\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.FinallyDefinition\" }, \"id\" : { \"type\" : \"string\" }, \"inherit-error-handler\" : { \"type\" : \"boolean\" }, \"steps\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.ProcessorDefinition\" } } } }, \"org.apache.camel.model.UnmarshalDefinition\" : { \"type\" : \"object\", \"properties\" : { \"allow-null-body\" : { \"type\" : \"boolean\" }, \"any23\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.Any23DataFormat\" }, \"asn1\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.ASN1DataFormat\" }, \"avro\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.AvroDataFormat\" }, \"barcode\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.BarcodeDataFormat\" }, \"base64\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.Base64DataFormat\" }, \"bindy\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.BindyDataFormat\" }, \"cbor\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.CBORDataFormat\" }, \"crypto\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.CryptoDataFormat\" }, \"csv\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.CsvDataFormat\" }, \"custom\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.CustomDataFormat\" }, \"description\" : { \"type\" : \"string\" }, \"disabled\" : { \"type\" : \"boolean\" }, \"fhir-json\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.FhirJsonDataFormat\" }, \"fhir-xml\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.FhirXmlDataFormat\" }, \"flatpack\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.FlatpackDataFormat\" }, \"grok\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.GrokDataFormat\" }, \"gzip-deflater\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.GzipDeflaterDataFormat\" }, \"hl7\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.HL7DataFormat\" }, \"ical\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.IcalDataFormat\" }, \"id\" : { \"type\" : \"string\" }, \"inherit-error-handler\" : { \"type\" : \"boolean\" }, \"jackson-xml\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.JacksonXMLDataFormat\" }, \"jaxb\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.JaxbDataFormat\" }, \"json\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.JsonDataFormat\" }, \"json-api\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.JsonApiDataFormat\" }, \"lzf\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.LZFDataFormat\" }, \"mime-multipart\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.MimeMultipartDataFormat\" }, \"pgp\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.PGPDataFormat\" }, \"protobuf\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.ProtobufDataFormat\" }, \"rss\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.RssDataFormat\" }, \"soap\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.SoapDataFormat\" }, \"swift-mt\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.SwiftMtDataFormat\" }, \"swift-mx\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.SwiftMxDataFormat\" }, \"syslog\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.SyslogDataFormat\" }, \"tar-file\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.TarFileDataFormat\" }, \"thrift\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.ThriftDataFormat\" }, \"tidy-markup\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.TidyMarkupDataFormat\" }, \"univocity-csv\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.UniVocityCsvDataFormat\" }, \"univocity-fixed\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.UniVocityFixedDataFormat\" }, \"univocity-tsv\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.UniVocityTsvDataFormat\" }, \"xml-security\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.XMLSecurityDataFormat\" }, \"xstream\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.XStreamDataFormat\" }, \"yaml\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.YAMLDataFormat\" }, \"zip-deflater\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.ZipDeflaterDataFormat\" }, \"zip-file\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.ZipFileDataFormat\" } } }, \"org.apache.camel.model.ValidateDefinition\" : { \"type\" : \"object\", \"anyOf\" : [ { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.ExpressionDefinition\" } ], \"properties\" : { \"description\" : { \"type\" : \"string\" }, \"disabled\" : { \"type\" : \"boolean\" }, \"expression\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.ExpressionDefinition\" }, \"id\" : { \"type\" : \"string\" }, \"inherit-error-handler\" : { \"type\" : \"boolean\" }, \"predicate-exception-factory\" : { \"type\" : \"string\" } } }, \"org.apache.camel.model.ValueDefinition\" : { \"oneOf\" : [ { \"type\" : \"string\" }, { \"type\" : \"object\", \"properties\" : { \"value\" : { \"type\" : \"string\" } } } ] }, \"org.apache.camel.model.WhenDefinition\" : { \"type\" : \"object\", \"anyOf\" : [ { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.ExpressionDefinition\" } ], \"properties\" : { \"description\" : { \"type\" : \"string\" }, \"disabled\" : { \"type\" : \"boolean\" }, \"expression\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.ExpressionDefinition\" }, \"id\" : { \"type\" : \"string\" }, \"inherit-error-handler\" : { \"type\" : \"boolean\" }, \"steps\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.ProcessorDefinition\" } } } }, \"org.apache.camel.model.WhenSkipSendToEndpointDefinition\" : { \"type\" : \"object\", \"anyOf\" : [ { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.ExpressionDefinition\" } ], \"properties\" : { \"description\" : { \"type\" : \"string\" }, \"disabled\" : { \"type\" : \"boolean\" }, \"expression\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.ExpressionDefinition\" }, \"id\" : { \"type\" : \"string\" }, \"inherit-error-handler\" : { \"type\" : \"boolean\" }, \"steps\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.ProcessorDefinition\" } } } }, \"org.apache.camel.model.WireTapDefinition\" : { \"type\" : \"object\", \"properties\" : { \"allow-optimised-components\" : { \"type\" : \"boolean\" }, \"auto-start-components\" : { \"type\" : \"boolean\" }, \"cache-size\" : { \"type\" : \"number\" }, \"copy\" : { \"type\" : \"boolean\" }, \"description\" : { \"type\" : \"string\" }, \"disabled\" : { \"type\" : \"boolean\" }, \"dynamic-uri\" : { \"type\" : \"boolean\" }, \"executor-service\" : { \"type\" : \"string\" }, \"id\" : { \"type\" : \"string\" }, \"ignore-invalid-endpoint\" : { \"type\" : \"boolean\" }, \"inherit-error-handler\" : { \"type\" : \"boolean\" }, \"on-prepare\" : { \"type\" : \"string\" }, \"parameters\" : { \"type\" : \"object\" }, \"pattern\" : { \"type\" : \"string\", \"enum\" : [ \"InOnly\", \"InOut\", \"InOptionalOut\" ] }, \"uri\" : { \"type\" : \"string\" } }, \"required\" : [ \"uri\" ] }, \"org.apache.camel.model.cloud.BlacklistServiceCallServiceFilterConfiguration\" : { \"type\" : \"object\", \"properties\" : { \"id\" : { \"type\" : \"string\" }, \"properties\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.PropertyDefinition\" } }, \"servers\" : { \"type\" : \"array\", \"items\" : { \"type\" : \"string\" } } } }, \"org.apache.camel.model.cloud.CachingServiceCallServiceDiscoveryConfiguration\" : { \"type\" : \"object\", \"properties\" : { \"combined-service-discovery\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.cloud.CombinedServiceCallServiceDiscoveryConfiguration\" }, \"consul-service-discovery\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.cloud.ConsulServiceCallServiceDiscoveryConfiguration\" }, \"dns-service-discovery\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.cloud.DnsServiceCallServiceDiscoveryConfiguration\" }, \"id\" : { \"type\" : \"string\" }, \"kubernetes-service-discovery\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.cloud.KubernetesServiceCallServiceDiscoveryConfiguration\" }, \"properties\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.PropertyDefinition\" } }, \"static-service-discovery\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.cloud.StaticServiceCallServiceDiscoveryConfiguration\" }, \"timeout\" : { \"type\" : \"number\" }, \"units\" : { \"type\" : \"string\", \"enum\" : [ \"NANOSECONDS\", \"MICROSECONDS\", \"MILLISECONDS\", \"SECONDS\", \"MINUTES\", \"HOURS\", \"DAYS\" ] } } }, \"org.apache.camel.model.cloud.CombinedServiceCallServiceDiscoveryConfiguration\" : { \"type\" : \"object\", \"properties\" : { \"caching-service-discovery\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.cloud.CachingServiceCallServiceDiscoveryConfiguration\" }, \"consul-service-discovery\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.cloud.ConsulServiceCallServiceDiscoveryConfiguration\" }, \"dns-service-discovery\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.cloud.DnsServiceCallServiceDiscoveryConfiguration\" }, \"id\" : { \"type\" : \"string\" }, \"kubernetes-service-discovery\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.cloud.KubernetesServiceCallServiceDiscoveryConfiguration\" }, \"properties\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.PropertyDefinition\" } }, \"static-service-discovery\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.cloud.StaticServiceCallServiceDiscoveryConfiguration\" } } }, \"org.apache.camel.model.cloud.CombinedServiceCallServiceFilterConfiguration\" : { \"type\" : \"object\", \"properties\" : { \"blacklist-service-filter\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.cloud.BlacklistServiceCallServiceFilterConfiguration\" }, \"custom-service-filter\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.cloud.CustomServiceCallServiceFilterConfiguration\" }, \"healthy-service-filter\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.cloud.HealthyServiceCallServiceFilterConfiguration\" }, \"id\" : { \"type\" : \"string\" }, \"pass-through-service-filter\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.cloud.PassThroughServiceCallServiceFilterConfiguration\" }, \"properties\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.PropertyDefinition\" } } } }, \"org.apache.camel.model.cloud.ConsulServiceCallServiceDiscoveryConfiguration\" : { \"type\" : \"object\", \"properties\" : { \"acl-token\" : { \"type\" : \"string\" }, \"block-seconds\" : { \"type\" : \"number\" }, \"connect-timeout-millis\" : { \"type\" : \"number\" }, \"datacenter\" : { \"type\" : \"string\" }, \"id\" : { \"type\" : \"string\" }, \"password\" : { \"type\" : \"string\" }, \"properties\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.PropertyDefinition\" } }, \"read-timeout-millis\" : { \"type\" : \"number\" }, \"url\" : { \"type\" : \"string\" }, \"user-name\" : { \"type\" : \"string\" }, \"write-timeout-millis\" : { \"type\" : \"number\" } } }, \"org.apache.camel.model.cloud.CustomServiceCallServiceFilterConfiguration\" : { \"type\" : \"object\", \"properties\" : { \"id\" : { \"type\" : \"string\" }, \"properties\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.PropertyDefinition\" } }, \"ref\" : { \"type\" : \"string\" } } }, \"org.apache.camel.model.cloud.DefaultServiceCallServiceLoadBalancerConfiguration\" : { \"type\" : \"object\", \"properties\" : { \"id\" : { \"type\" : \"string\" }, \"properties\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.PropertyDefinition\" } } } }, \"org.apache.camel.model.cloud.DnsServiceCallServiceDiscoveryConfiguration\" : { \"type\" : \"object\", \"properties\" : { \"domain\" : { \"type\" : \"string\" }, \"id\" : { \"type\" : \"string\" }, \"properties\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.PropertyDefinition\" } }, \"proto\" : { \"type\" : \"string\" } } }, \"org.apache.camel.model.cloud.HealthyServiceCallServiceFilterConfiguration\" : { \"type\" : \"object\", \"properties\" : { \"id\" : { \"type\" : \"string\" }, \"properties\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.PropertyDefinition\" } } } }, \"org.apache.camel.model.cloud.KubernetesServiceCallServiceDiscoveryConfiguration\" : { \"type\" : \"object\", \"properties\" : { \"api-version\" : { \"type\" : \"string\" }, \"ca-cert-data\" : { \"type\" : \"string\" }, \"ca-cert-file\" : { \"type\" : \"string\" }, \"client-cert-data\" : { \"type\" : \"string\" }, \"client-cert-file\" : { \"type\" : \"string\" }, \"client-key-algo\" : { \"type\" : \"string\" }, \"client-key-data\" : { \"type\" : \"string\" }, \"client-key-file\" : { \"type\" : \"string\" }, \"client-key-passphrase\" : { \"type\" : \"string\" }, \"dns-domain\" : { \"type\" : \"string\" }, \"id\" : { \"type\" : \"string\" }, \"lookup\" : { \"type\" : \"string\", \"enum\" : [ \"environment\", \"dns\", \"client\" ] }, \"master-url\" : { \"type\" : \"string\" }, \"namespace\" : { \"type\" : \"string\" }, \"oauth-token\" : { \"type\" : \"string\" }, \"password\" : { \"type\" : \"string\" }, \"port-name\" : { \"type\" : \"string\" }, \"port-protocol\" : { \"type\" : \"string\" }, \"properties\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.PropertyDefinition\" } }, \"trust-certs\" : { \"type\" : \"boolean\" }, \"username\" : { \"type\" : \"string\" } } }, \"org.apache.camel.model.cloud.PassThroughServiceCallServiceFilterConfiguration\" : { \"type\" : \"object\", \"properties\" : { \"id\" : { \"type\" : \"string\" }, \"properties\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.PropertyDefinition\" } } } }, \"org.apache.camel.model.cloud.ServiceCallConfigurationDefinition\" : { \"type\" : \"object\", \"properties\" : { \"blacklist-service-filter\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.cloud.BlacklistServiceCallServiceFilterConfiguration\" }, \"caching-service-discovery\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.cloud.CachingServiceCallServiceDiscoveryConfiguration\" }, \"combined-service-discovery\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.cloud.CombinedServiceCallServiceDiscoveryConfiguration\" }, \"combined-service-filter\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.cloud.CombinedServiceCallServiceFilterConfiguration\" }, \"component\" : { \"type\" : \"string\" }, \"consul-service-discovery\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.cloud.ConsulServiceCallServiceDiscoveryConfiguration\" }, \"custom-service-filter\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.cloud.CustomServiceCallServiceFilterConfiguration\" }, \"default-load-balancer\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.cloud.DefaultServiceCallServiceLoadBalancerConfiguration\" }, \"dns-service-discovery\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.cloud.DnsServiceCallServiceDiscoveryConfiguration\" }, \"expression\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.cloud.ServiceCallExpressionConfiguration\" }, \"expression-ref\" : { \"type\" : \"string\" }, \"healthy-service-filter\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.cloud.HealthyServiceCallServiceFilterConfiguration\" }, \"id\" : { \"type\" : \"string\" }, \"kubernetes-service-discovery\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.cloud.KubernetesServiceCallServiceDiscoveryConfiguration\" }, \"load-balancer-ref\" : { \"type\" : \"string\" }, \"pass-through-service-filter\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.cloud.PassThroughServiceCallServiceFilterConfiguration\" }, \"pattern\" : { \"type\" : \"string\", \"enum\" : [ \"InOnly\", \"InOut\", \"InOptionalOut\" ] }, \"service-chooser-ref\" : { \"type\" : \"string\" }, \"service-discovery-ref\" : { \"type\" : \"string\" }, \"service-filter-ref\" : { \"type\" : \"string\" }, \"static-service-discovery\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.cloud.StaticServiceCallServiceDiscoveryConfiguration\" }, \"uri\" : { \"type\" : \"string\" }, \"zookeeper-service-discovery\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.cloud.ZooKeeperServiceCallServiceDiscoveryConfiguration\" } } }, \"org.apache.camel.model.cloud.ServiceCallDefinition\" : { \"oneOf\" : [ { \"type\" : \"string\" }, { \"type\" : \"object\", \"properties\" : { \"blacklist-service-filter\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.cloud.BlacklistServiceCallServiceFilterConfiguration\" }, \"caching-service-discovery\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.cloud.CachingServiceCallServiceDiscoveryConfiguration\" }, \"combined-service-discovery\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.cloud.CombinedServiceCallServiceDiscoveryConfiguration\" }, \"combined-service-filter\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.cloud.CombinedServiceCallServiceFilterConfiguration\" }, \"component\" : { \"type\" : \"string\" }, \"configuration-ref\" : { \"type\" : \"string\" }, \"consul-service-discovery\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.cloud.ConsulServiceCallServiceDiscoveryConfiguration\" }, \"custom-service-filter\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.cloud.CustomServiceCallServiceFilterConfiguration\" }, \"default-load-balancer\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.cloud.DefaultServiceCallServiceLoadBalancerConfiguration\" }, \"description\" : { \"type\" : \"string\" }, \"disabled\" : { \"type\" : \"boolean\" }, \"dns-service-discovery\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.cloud.DnsServiceCallServiceDiscoveryConfiguration\" }, \"expression\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.cloud.ServiceCallExpressionConfiguration\" }, \"expression-ref\" : { \"type\" : \"string\" }, \"healthy-service-filter\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.cloud.HealthyServiceCallServiceFilterConfiguration\" }, \"id\" : { \"type\" : \"string\" }, \"inherit-error-handler\" : { \"type\" : \"boolean\" }, \"kubernetes-service-discovery\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.cloud.KubernetesServiceCallServiceDiscoveryConfiguration\" }, \"load-balancer-ref\" : { \"type\" : \"string\" }, \"name\" : { \"type\" : \"string\" }, \"pass-through-service-filter\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.cloud.PassThroughServiceCallServiceFilterConfiguration\" }, \"pattern\" : { \"type\" : \"string\", \"enum\" : [ \"InOnly\", \"InOut\", \"InOptionalOut\" ] }, \"service-chooser-ref\" : { \"type\" : \"string\" }, \"service-discovery-ref\" : { \"type\" : \"string\" }, \"service-filter-ref\" : { \"type\" : \"string\" }, \"static-service-discovery\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.cloud.StaticServiceCallServiceDiscoveryConfiguration\" }, \"uri\" : { \"type\" : \"string\" }, \"zookeeper-service-discovery\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.cloud.ZooKeeperServiceCallServiceDiscoveryConfiguration\" } } } ], \"required\" : [ \"name\" ] }, \"org.apache.camel.model.cloud.ServiceCallExpressionConfiguration\" : { \"type\" : \"object\", \"properties\" : { \"expression-type\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.ExpressionDefinition\" }, \"host-header\" : { \"type\" : \"string\" }, \"id\" : { \"type\" : \"string\" }, \"port-header\" : { \"type\" : \"string\" }, \"properties\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.PropertyDefinition\" } } } }, \"org.apache.camel.model.cloud.ServiceCallServiceChooserConfiguration\" : { \"type\" : \"object\", \"properties\" : { \"id\" : { \"type\" : \"string\" }, \"properties\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.PropertyDefinition\" } } } }, \"org.apache.camel.model.cloud.ServiceCallServiceDiscoveryConfiguration\" : { \"type\" : \"object\", \"properties\" : { \"id\" : { \"type\" : \"string\" }, \"properties\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.PropertyDefinition\" } } } }, \"org.apache.camel.model.cloud.ServiceCallServiceFilterConfiguration\" : { \"type\" : \"object\", \"properties\" : { \"id\" : { \"type\" : \"string\" }, \"properties\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.PropertyDefinition\" } } } }, \"org.apache.camel.model.cloud.ServiceCallServiceLoadBalancerConfiguration\" : { \"type\" : \"object\", \"properties\" : { \"id\" : { \"type\" : \"string\" }, \"properties\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.PropertyDefinition\" } } } }, \"org.apache.camel.model.cloud.StaticServiceCallServiceDiscoveryConfiguration\" : { \"type\" : \"object\", \"properties\" : { \"id\" : { \"type\" : \"string\" }, \"properties\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.PropertyDefinition\" } }, \"servers\" : { \"type\" : \"array\", \"items\" : { \"type\" : \"string\" } } } }, \"org.apache.camel.model.cloud.ZooKeeperServiceCallServiceDiscoveryConfiguration\" : { \"type\" : \"object\", \"properties\" : { \"base-path\" : { \"type\" : \"string\" }, \"connection-timeout\" : { \"type\" : \"string\" }, \"id\" : { \"type\" : \"string\" }, \"namespace\" : { \"type\" : \"string\" }, \"nodes\" : { \"type\" : \"string\" }, \"properties\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.PropertyDefinition\" } }, \"reconnect-base-sleep-time\" : { \"type\" : \"string\" }, \"reconnect-max-retries\" : { \"type\" : \"string\" }, \"reconnect-max-sleep-time\" : { \"type\" : \"string\" }, \"session-timeout\" : { \"type\" : \"string\" } }, \"required\" : [ \"base-path\", \"nodes\" ] }, \"org.apache.camel.model.config.BatchResequencerConfig\" : { \"type\" : \"object\", \"properties\" : { \"allow-duplicates\" : { \"type\" : \"boolean\" }, \"batch-size\" : { \"type\" : \"number\" }, \"batch-timeout\" : { \"type\" : \"string\" }, \"ignore-invalid-exchanges\" : { \"type\" : \"boolean\" }, \"reverse\" : { \"type\" : \"boolean\" } } }, \"org.apache.camel.model.config.StreamResequencerConfig\" : { \"type\" : \"object\", \"properties\" : { \"capacity\" : { \"type\" : \"number\" }, \"comparator\" : { \"type\" : \"string\" }, \"delivery-attempt-interval\" : { \"type\" : \"string\" }, \"ignore-invalid-exchanges\" : { \"type\" : \"boolean\" }, \"reject-old\" : { \"type\" : \"boolean\" }, \"timeout\" : { \"type\" : \"string\" } } }, \"org.apache.camel.model.dataformat.ASN1DataFormat\" : { \"oneOf\" : [ { \"type\" : \"string\" }, { \"type\" : \"object\", \"properties\" : { \"id\" : { \"type\" : \"string\" }, \"unmarshal-type\" : { \"type\" : \"string\" }, \"using-iterator\" : { \"type\" : \"boolean\" } } } ] }, \"org.apache.camel.model.dataformat.Any23DataFormat\" : { \"oneOf\" : [ { \"type\" : \"string\" }, { \"type\" : \"object\", \"properties\" : { \"base-uri\" : { \"type\" : \"string\" }, \"configuration\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.PropertyDefinition\" } }, \"extractors\" : { \"type\" : \"array\", \"items\" : { \"type\" : \"string\" } }, \"id\" : { \"type\" : \"string\" }, \"output-format\" : { \"type\" : \"string\", \"enum\" : [ \"NTRIPLES\", \"TURTLE\", \"NQUADS\", \"RDFXML\", \"JSONLD\", \"RDFJSON\", \"RDF4JMODEL\" ] } } } ] }, \"org.apache.camel.model.dataformat.AvroDataFormat\" : { \"oneOf\" : [ { \"type\" : \"string\" }, { \"type\" : \"object\", \"properties\" : { \"allow-jms-type\" : { \"type\" : \"boolean\" }, \"allow-unmarshall-type\" : { \"type\" : \"boolean\" }, \"auto-discover-object-mapper\" : { \"type\" : \"boolean\" }, \"auto-discover-schema-resolver\" : { \"type\" : \"boolean\" }, \"collection-type\" : { \"type\" : \"string\" }, \"content-type-header\" : { \"type\" : \"boolean\" }, \"disable-features\" : { \"type\" : \"string\" }, \"enable-features\" : { \"type\" : \"string\" }, \"id\" : { \"type\" : \"string\" }, \"include\" : { \"type\" : \"string\" }, \"instance-class-name\" : { \"type\" : \"string\" }, \"json-view\" : { \"type\" : \"string\" }, \"library\" : { \"type\" : \"string\", \"enum\" : [ \"ApacheAvro\", \"Jackson\" ] }, \"module-class-names\" : { \"type\" : \"string\" }, \"module-refs\" : { \"type\" : \"string\" }, \"object-mapper\" : { \"type\" : \"string\" }, \"schema-resolver\" : { \"type\" : \"string\" }, \"timezone\" : { \"type\" : \"string\" }, \"unmarshal-type\" : { \"type\" : \"string\" }, \"use-default-object-mapper\" : { \"type\" : \"boolean\" }, \"use-list\" : { \"type\" : \"boolean\" } } } ] }, \"org.apache.camel.model.dataformat.BarcodeDataFormat\" : { \"type\" : \"object\", \"properties\" : { \"barcode-format\" : { \"type\" : \"string\" }, \"height\" : { \"type\" : \"number\" }, \"id\" : { \"type\" : \"string\" }, \"image-type\" : { \"type\" : \"string\" }, \"width\" : { \"type\" : \"number\" } } }, \"org.apache.camel.model.dataformat.Base64DataFormat\" : { \"type\" : \"object\", \"properties\" : { \"id\" : { \"type\" : \"string\" }, \"line-length\" : { \"type\" : \"number\" }, \"line-separator\" : { \"type\" : \"string\" }, \"url-safe\" : { \"type\" : \"boolean\" } } }, \"org.apache.camel.model.dataformat.BindyDataFormat\" : { \"type\" : \"object\", \"properties\" : { \"allow-empty-stream\" : { \"type\" : \"boolean\" }, \"class-type\" : { \"type\" : \"string\" }, \"id\" : { \"type\" : \"string\" }, \"locale\" : { \"type\" : \"string\" }, \"type\" : { \"type\" : \"string\", \"enum\" : [ \"Csv\", \"Fixed\", \"KeyValue\" ] }, \"unwrap-single-instance\" : { \"type\" : \"boolean\" } }, \"required\" : [ \"type\" ] }, \"org.apache.camel.model.dataformat.CBORDataFormat\" : { \"type\" : \"object\", \"properties\" : { \"allow-jms-type\" : { \"type\" : \"boolean\" }, \"allow-unmarshall-type\" : { \"type\" : \"boolean\" }, \"collection-type\" : { \"type\" : \"string\" }, \"disable-features\" : { \"type\" : \"string\" }, \"enable-features\" : { \"type\" : \"string\" }, \"id\" : { \"type\" : \"string\" }, \"object-mapper\" : { \"type\" : \"string\" }, \"pretty-print\" : { \"type\" : \"boolean\" }, \"unmarshal-type\" : { \"type\" : \"string\" }, \"use-default-object-mapper\" : { \"type\" : \"boolean\" }, \"use-list\" : { \"type\" : \"boolean\" } } }, \"org.apache.camel.model.dataformat.CryptoDataFormat\" : { \"type\" : \"object\", \"properties\" : { \"algorithm\" : { \"type\" : \"string\" }, \"algorithm-parameter-ref\" : { \"type\" : \"string\" }, \"buffer-size\" : { \"type\" : \"number\" }, \"crypto-provider\" : { \"type\" : \"string\" }, \"id\" : { \"type\" : \"string\" }, \"init-vector-ref\" : { \"type\" : \"string\" }, \"inline\" : { \"type\" : \"boolean\" }, \"key-ref\" : { \"type\" : \"string\" }, \"mac-algorithm\" : { \"type\" : \"string\" }, \"should-append-hmac\" : { \"type\" : \"boolean\" } } }, \"org.apache.camel.model.dataformat.CsvDataFormat\" : { \"oneOf\" : [ { \"type\" : \"string\" }, { \"type\" : \"object\", \"properties\" : { \"allow-missing-column-names\" : { \"type\" : \"boolean\" }, \"capture-header-record\" : { \"type\" : \"boolean\" }, \"comment-marker\" : { \"type\" : \"string\" }, \"comment-marker-disabled\" : { \"type\" : \"boolean\" }, \"delimiter\" : { \"type\" : \"string\" }, \"escape\" : { \"type\" : \"string\" }, \"escape-disabled\" : { \"type\" : \"boolean\" }, \"format-name\" : { \"type\" : \"string\", \"enum\" : [ \"DEFAULT\", \"EXCEL\", \"INFORMIX_UNLOAD\", \"INFORMIX_UNLOAD_CSV\", \"MYSQL\", \"RFC4180\" ] }, \"format-ref\" : { \"type\" : \"string\" }, \"header\" : { \"type\" : \"array\", \"items\" : { \"type\" : \"string\" } }, \"header-disabled\" : { \"type\" : \"boolean\" }, \"id\" : { \"type\" : \"string\" }, \"ignore-empty-lines\" : { \"type\" : \"boolean\" }, \"ignore-header-case\" : { \"type\" : \"boolean\" }, \"ignore-surrounding-spaces\" : { \"type\" : \"boolean\" }, \"lazy-load\" : { \"type\" : \"boolean\" }, \"marshaller-factory-ref\" : { \"type\" : \"string\" }, \"null-string\" : { \"type\" : \"string\" }, \"null-string-disabled\" : { \"type\" : \"boolean\" }, \"quote\" : { \"type\" : \"string\" }, \"quote-disabled\" : { \"type\" : \"boolean\" }, \"quote-mode\" : { \"type\" : \"string\", \"enum\" : [ \"ALL\", \"ALL_NON_NULL\", \"MINIMAL\", \"NON_NUMERIC\", \"NONE\" ] }, \"record-converter-ref\" : { \"type\" : \"string\" }, \"record-separator\" : { \"type\" : \"string\" }, \"record-separator-disabled\" : { \"type\" : \"string\" }, \"skip-header-record\" : { \"type\" : \"boolean\" }, \"trailing-delimiter\" : { \"type\" : \"boolean\" }, \"trim\" : { \"type\" : \"boolean\" }, \"use-maps\" : { \"type\" : \"boolean\" }, \"use-ordered-maps\" : { \"type\" : \"boolean\" } } } ] }, \"org.apache.camel.model.dataformat.CustomDataFormat\" : { \"oneOf\" : [ { \"type\" : \"string\" }, { \"type\" : \"object\", \"properties\" : { \"id\" : { \"type\" : \"string\" }, \"ref\" : { \"type\" : \"string\" } } } ], \"required\" : [ \"ref\" ] }, \"org.apache.camel.model.dataformat.DataFormatsDefinition\" : { \"type\" : \"object\", \"properties\" : { \"any23\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.Any23DataFormat\" }, \"asn1\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.ASN1DataFormat\" }, \"avro\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.AvroDataFormat\" }, \"barcode\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.BarcodeDataFormat\" }, \"base64\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.Base64DataFormat\" }, \"bindy\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.BindyDataFormat\" }, \"cbor\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.CBORDataFormat\" }, \"crypto\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.CryptoDataFormat\" }, \"csv\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.CsvDataFormat\" }, \"custom\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.CustomDataFormat\" }, \"fhir-json\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.FhirJsonDataFormat\" }, \"fhir-xml\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.FhirXmlDataFormat\" }, \"flatpack\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.FlatpackDataFormat\" }, \"grok\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.GrokDataFormat\" }, \"gzip-deflater\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.GzipDeflaterDataFormat\" }, \"hl7\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.HL7DataFormat\" }, \"ical\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.IcalDataFormat\" }, \"jackson-xml\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.JacksonXMLDataFormat\" }, \"jaxb\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.JaxbDataFormat\" }, \"json\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.JsonDataFormat\" }, \"json-api\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.JsonApiDataFormat\" }, \"lzf\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.LZFDataFormat\" }, \"mime-multipart\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.MimeMultipartDataFormat\" }, \"pgp\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.PGPDataFormat\" }, \"protobuf\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.ProtobufDataFormat\" }, \"rss\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.RssDataFormat\" }, \"soap\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.SoapDataFormat\" }, \"swift-mt\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.SwiftMtDataFormat\" }, \"swift-mx\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.SwiftMxDataFormat\" }, \"syslog\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.SyslogDataFormat\" }, \"tar-file\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.TarFileDataFormat\" }, \"thrift\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.ThriftDataFormat\" }, \"tidy-markup\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.TidyMarkupDataFormat\" }, \"univocity-csv\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.UniVocityCsvDataFormat\" }, \"univocity-fixed\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.UniVocityFixedDataFormat\" }, \"univocity-tsv\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.UniVocityTsvDataFormat\" }, \"xml-security\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.XMLSecurityDataFormat\" }, \"xstream\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.XStreamDataFormat\" }, \"yaml\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.YAMLDataFormat\" }, \"zip-deflater\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.ZipDeflaterDataFormat\" }, \"zip-file\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.ZipFileDataFormat\" } } }, \"org.apache.camel.model.dataformat.FhirJsonDataFormat\" : { \"type\" : \"object\", \"properties\" : { \"content-type-header\" : { \"type\" : \"boolean\" }, \"dont-encode-elements\" : { \"type\" : \"string\" }, \"dont-strip-versions-from-references-at-paths\" : { \"type\" : \"string\" }, \"encode-elements\" : { \"type\" : \"string\" }, \"encode-elements-applies-to-child-resources-only\" : { \"type\" : \"boolean\" }, \"fhir-context\" : { \"type\" : \"string\" }, \"fhir-version\" : { \"type\" : \"string\", \"enum\" : [ \"DSTU2\", \"DSTU2_HL7ORG\", \"DSTU2_1\", \"DSTU3\", \"R4\", \"R5\" ] }, \"force-resource-id\" : { \"type\" : \"string\" }, \"id\" : { \"type\" : \"string\" }, \"omit-resource-id\" : { \"type\" : \"boolean\" }, \"override-resource-id-with-bundle-entry-full-url\" : { \"type\" : \"boolean\" }, \"parser-error-handler\" : { \"type\" : \"string\" }, \"parser-options\" : { \"type\" : \"string\" }, \"prefer-types\" : { \"type\" : \"string\" }, \"pretty-print\" : { \"type\" : \"boolean\" }, \"server-base-url\" : { \"type\" : \"string\" }, \"strip-versions-from-references\" : { \"type\" : \"boolean\" }, \"summary-mode\" : { \"type\" : \"boolean\" }, \"suppress-narratives\" : { \"type\" : \"boolean\" } } }, \"org.apache.camel.model.dataformat.FhirXmlDataFormat\" : { \"type\" : \"object\", \"properties\" : { \"content-type-header\" : { \"type\" : \"boolean\" }, \"dont-encode-elements\" : { \"type\" : \"string\" }, \"dont-strip-versions-from-references-at-paths\" : { \"type\" : \"string\" }, \"encode-elements\" : { \"type\" : \"string\" }, \"encode-elements-applies-to-child-resources-only\" : { \"type\" : \"boolean\" }, \"fhir-context\" : { \"type\" : \"string\" }, \"fhir-version\" : { \"type\" : \"string\", \"enum\" : [ \"DSTU2\", \"DSTU2_HL7ORG\", \"DSTU2_1\", \"DSTU3\", \"R4\", \"R5\" ] }, \"force-resource-id\" : { \"type\" : \"string\" }, \"id\" : { \"type\" : \"string\" }, \"omit-resource-id\" : { \"type\" : \"boolean\" }, \"override-resource-id-with-bundle-entry-full-url\" : { \"type\" : \"boolean\" }, \"parser-error-handler\" : { \"type\" : \"string\" }, \"parser-options\" : { \"type\" : \"string\" }, \"prefer-types\" : { \"type\" : \"string\" }, \"pretty-print\" : { \"type\" : \"boolean\" }, \"server-base-url\" : { \"type\" : \"string\" }, \"strip-versions-from-references\" : { \"type\" : \"boolean\" }, \"summary-mode\" : { \"type\" : \"boolean\" }, \"suppress-narratives\" : { \"type\" : \"boolean\" } } }, \"org.apache.camel.model.dataformat.FlatpackDataFormat\" : { \"type\" : \"object\", \"properties\" : { \"allow-short-lines\" : { \"type\" : \"boolean\" }, \"definition\" : { \"type\" : \"string\" }, \"delimiter\" : { \"type\" : \"string\" }, \"fixed\" : { \"type\" : \"boolean\" }, \"id\" : { \"type\" : \"string\" }, \"ignore-extra-columns\" : { \"type\" : \"boolean\" }, \"ignore-first-record\" : { \"type\" : \"boolean\" }, \"parser-factory-ref\" : { \"type\" : \"string\" }, \"text-qualifier\" : { \"type\" : \"string\" } } }, \"org.apache.camel.model.dataformat.GrokDataFormat\" : { \"type\" : \"object\", \"properties\" : { \"allow-multiple-matches-per-line\" : { \"type\" : \"boolean\" }, \"flattened\" : { \"type\" : \"boolean\" }, \"id\" : { \"type\" : \"string\" }, \"named-only\" : { \"type\" : \"boolean\" }, \"pattern\" : { \"type\" : \"string\" } }, \"required\" : [ \"pattern\" ] }, \"org.apache.camel.model.dataformat.GzipDeflaterDataFormat\" : { \"type\" : \"object\", \"properties\" : { \"id\" : { \"type\" : \"string\" } } }, \"org.apache.camel.model.dataformat.HL7DataFormat\" : { \"type\" : \"object\", \"properties\" : { \"id\" : { \"type\" : \"string\" }, \"validate\" : { \"type\" : \"boolean\" } } }, \"org.apache.camel.model.dataformat.IcalDataFormat\" : { \"type\" : \"object\", \"properties\" : { \"id\" : { \"type\" : \"string\" }, \"validating\" : { \"type\" : \"boolean\" } } }, \"org.apache.camel.model.dataformat.JacksonXMLDataFormat\" : { \"type\" : \"object\", \"properties\" : { \"allow-jms-type\" : { \"type\" : \"boolean\" }, \"allow-unmarshall-type\" : { \"type\" : \"boolean\" }, \"collection-type\" : { \"type\" : \"string\" }, \"content-type-header\" : { \"type\" : \"boolean\" }, \"disable-features\" : { \"type\" : \"string\" }, \"enable-features\" : { \"type\" : \"string\" }, \"enable-jaxb-annotation-module\" : { \"type\" : \"boolean\" }, \"id\" : { \"type\" : \"string\" }, \"include\" : { \"type\" : \"string\" }, \"json-view\" : { \"type\" : \"string\" }, \"module-class-names\" : { \"type\" : \"string\" }, \"module-refs\" : { \"type\" : \"string\" }, \"pretty-print\" : { \"type\" : \"boolean\" }, \"timezone\" : { \"type\" : \"string\" }, \"unmarshal-type\" : { \"type\" : \"string\" }, \"use-list\" : { \"type\" : \"boolean\" }, \"xml-mapper\" : { \"type\" : \"string\" } } }, \"org.apache.camel.model.dataformat.JaxbDataFormat\" : { \"type\" : \"object\", \"properties\" : { \"content-type-header\" : { \"type\" : \"boolean\" }, \"context-path\" : { \"type\" : \"string\" }, \"context-path-is-class-name\" : { \"type\" : \"boolean\" }, \"encoding\" : { \"type\" : \"string\" }, \"filter-non-xml-chars\" : { \"type\" : \"boolean\" }, \"fragment\" : { \"type\" : \"boolean\" }, \"id\" : { \"type\" : \"string\" }, \"ignore-jaxb-element\" : { \"type\" : \"boolean\" }, \"jaxb-provider-properties\" : { \"type\" : \"string\" }, \"must-be-jaxb-element\" : { \"type\" : \"boolean\" }, \"namespace-prefix-ref\" : { \"type\" : \"string\" }, \"no-namespace-schema-location\" : { \"type\" : \"string\" }, \"object-factory\" : { \"type\" : \"boolean\" }, \"part-class\" : { \"type\" : \"string\" }, \"part-namespace\" : { \"type\" : \"string\" }, \"pretty-print\" : { \"type\" : \"boolean\" }, \"schema\" : { \"type\" : \"string\" }, \"schema-location\" : { \"type\" : \"string\" }, \"schema-severity-level\" : { \"type\" : \"string\", \"enum\" : [ \"0\", \"1\", \"2\" ] }, \"xml-stream-writer-wrapper\" : { \"type\" : \"string\" } }, \"required\" : [ \"context-path\" ] }, \"org.apache.camel.model.dataformat.JsonApiDataFormat\" : { \"type\" : \"object\", \"properties\" : { \"data-format-types\" : { \"type\" : \"string\" }, \"id\" : { \"type\" : \"string\" }, \"main-format-type\" : { \"type\" : \"string\" } } }, \"org.apache.camel.model.dataformat.JsonDataFormat\" : { \"type\" : \"object\", \"properties\" : { \"allow-jms-type\" : { \"type\" : \"boolean\" }, \"allow-unmarshall-type\" : { \"type\" : \"boolean\" }, \"auto-discover-object-mapper\" : { \"type\" : \"boolean\" }, \"auto-discover-schema-resolver\" : { \"type\" : \"boolean\" }, \"collection-type\" : { \"type\" : \"string\" }, \"content-type-header\" : { \"type\" : \"boolean\" }, \"disable-features\" : { \"type\" : \"string\" }, \"drop-root-node\" : { \"type\" : \"boolean\" }, \"enable-features\" : { \"type\" : \"string\" }, \"id\" : { \"type\" : \"string\" }, \"include\" : { \"type\" : \"string\" }, \"json-view\" : { \"type\" : \"string\" }, \"library\" : { \"type\" : \"string\", \"enum\" : [ \"Fastjson\", \"Gson\", \"Jackson\", \"Johnzon\", \"Jsonb\", \"XStream\" ] }, \"module-class-names\" : { \"type\" : \"string\" }, \"module-refs\" : { \"type\" : \"string\" }, \"naming-strategy\" : { \"type\" : \"string\" }, \"object-mapper\" : { \"type\" : \"string\" }, \"permissions\" : { \"type\" : \"string\" }, \"pretty-print\" : { \"type\" : \"boolean\" }, \"schema-resolver\" : { \"type\" : \"string\" }, \"timezone\" : { \"type\" : \"string\" }, \"unmarshal-type\" : { \"type\" : \"string\" }, \"use-default-object-mapper\" : { \"type\" : \"boolean\" }, \"use-list\" : { \"type\" : \"boolean\" } } }, \"org.apache.camel.model.dataformat.LZFDataFormat\" : { \"type\" : \"object\", \"properties\" : { \"id\" : { \"type\" : \"string\" }, \"using-parallel-compression\" : { \"type\" : \"boolean\" } } }, \"org.apache.camel.model.dataformat.MimeMultipartDataFormat\" : { \"type\" : \"object\", \"properties\" : { \"binary-content\" : { \"type\" : \"boolean\" }, \"headers-inline\" : { \"type\" : \"boolean\" }, \"id\" : { \"type\" : \"string\" }, \"include-headers\" : { \"type\" : \"string\" }, \"multipart-sub-type\" : { \"type\" : \"string\" }, \"multipart-without-attachment\" : { \"type\" : \"boolean\" } } }, \"org.apache.camel.model.dataformat.PGPDataFormat\" : { \"type\" : \"object\", \"properties\" : { \"algorithm\" : { \"type\" : \"number\" }, \"armored\" : { \"type\" : \"boolean\" }, \"compression-algorithm\" : { \"type\" : \"number\" }, \"hash-algorithm\" : { \"type\" : \"number\" }, \"id\" : { \"type\" : \"string\" }, \"integrity\" : { \"type\" : \"boolean\" }, \"key-file-name\" : { \"type\" : \"string\" }, \"key-userid\" : { \"type\" : \"string\" }, \"password\" : { \"type\" : \"string\" }, \"provider\" : { \"type\" : \"string\" }, \"signature-key-file-name\" : { \"type\" : \"string\" }, \"signature-key-ring\" : { \"type\" : \"string\" }, \"signature-key-userid\" : { \"type\" : \"string\" }, \"signature-password\" : { \"type\" : \"string\" }, \"signature-verification-option\" : { \"type\" : \"string\" } } }, \"org.apache.camel.model.dataformat.ProtobufDataFormat\" : { \"oneOf\" : [ { \"type\" : \"string\" }, { \"type\" : \"object\", \"properties\" : { \"allow-jms-type\" : { \"type\" : \"boolean\" }, \"allow-unmarshall-type\" : { \"type\" : \"boolean\" }, \"auto-discover-object-mapper\" : { \"type\" : \"boolean\" }, \"auto-discover-schema-resolver\" : { \"type\" : \"boolean\" }, \"collection-type\" : { \"type\" : \"string\" }, \"content-type-format\" : { \"type\" : \"string\", \"enum\" : [ \"native\", \"json\" ] }, \"content-type-header\" : { \"type\" : \"boolean\" }, \"disable-features\" : { \"type\" : \"string\" }, \"enable-features\" : { \"type\" : \"string\" }, \"id\" : { \"type\" : \"string\" }, \"include\" : { \"type\" : \"string\" }, \"instance-class\" : { \"type\" : \"string\" }, \"json-view\" : { \"type\" : \"string\" }, \"library\" : { \"type\" : \"string\", \"enum\" : [ \"GoogleProtobuf\", \"Jackson\" ] }, \"module-class-names\" : { \"type\" : \"string\" }, \"module-refs\" : { \"type\" : \"string\" }, \"object-mapper\" : { \"type\" : \"string\" }, \"schema-resolver\" : { \"type\" : \"string\" }, \"timezone\" : { \"type\" : \"string\" }, \"unmarshal-type\" : { \"type\" : \"string\" }, \"use-default-object-mapper\" : { \"type\" : \"boolean\" }, \"use-list\" : { \"type\" : \"boolean\" } } } ] }, \"org.apache.camel.model.dataformat.RssDataFormat\" : { \"type\" : \"object\", \"properties\" : { \"id\" : { \"type\" : \"string\" } } }, \"org.apache.camel.model.dataformat.SoapDataFormat\" : { \"oneOf\" : [ { \"type\" : \"string\" }, { \"type\" : \"object\", \"properties\" : { \"context-path\" : { \"type\" : \"string\" }, \"element-name-strategy-ref\" : { \"type\" : \"string\" }, \"encoding\" : { \"type\" : \"string\" }, \"id\" : { \"type\" : \"string\" }, \"namespace-prefix-ref\" : { \"type\" : \"string\" }, \"schema\" : { \"type\" : \"string\" }, \"version\" : { \"type\" : \"string\", \"enum\" : [ \"1.1\", \"1.2\" ] } } } ], \"required\" : [ \"context-path\" ] }, \"org.apache.camel.model.dataformat.SwiftMtDataFormat\" : { \"oneOf\" : [ { \"type\" : \"string\" }, { \"type\" : \"object\", \"properties\" : { \"id\" : { \"type\" : \"string\" }, \"write-in-json\" : { \"type\" : \"boolean\" } } } ] }, \"org.apache.camel.model.dataformat.SwiftMxDataFormat\" : { \"type\" : \"object\", \"properties\" : { \"id\" : { \"type\" : \"string\" }, \"read-config-ref\" : { \"type\" : \"string\" }, \"read-message-id\" : { \"type\" : \"string\" }, \"write-config-ref\" : { \"type\" : \"string\" }, \"write-in-json\" : { \"type\" : \"boolean\" } } }, \"org.apache.camel.model.dataformat.SyslogDataFormat\" : { \"type\" : \"object\", \"properties\" : { \"id\" : { \"type\" : \"string\" } } }, \"org.apache.camel.model.dataformat.TarFileDataFormat\" : { \"type\" : \"object\", \"properties\" : { \"allow-empty-directory\" : { \"type\" : \"boolean\" }, \"id\" : { \"type\" : \"string\" }, \"max-decompressed-size\" : { \"type\" : \"number\" }, \"preserve-path-elements\" : { \"type\" : \"boolean\" }, \"using-iterator\" : { \"type\" : \"boolean\" } } }, \"org.apache.camel.model.dataformat.ThriftDataFormat\" : { \"oneOf\" : [ { \"type\" : \"string\" }, { \"type\" : \"object\", \"properties\" : { \"content-type-format\" : { \"type\" : \"string\", \"enum\" : [ \"binary\", \"json\", \"sjson\" ] }, \"content-type-header\" : { \"type\" : \"boolean\" }, \"id\" : { \"type\" : \"string\" }, \"instance-class\" : { \"type\" : \"string\" } } } ] }, \"org.apache.camel.model.dataformat.TidyMarkupDataFormat\" : { \"type\" : \"object\", \"properties\" : { \"data-object-type\" : { \"type\" : \"string\", \"enum\" : [ \"org.w3c.dom.Node\", \"java.lang.String\" ] }, \"id\" : { \"type\" : \"string\" }, \"omit-xml-declaration\" : { \"type\" : \"boolean\" } } }, \"org.apache.camel.model.dataformat.UniVocityCsvDataFormat\" : { \"type\" : \"object\", \"properties\" : { \"as-map\" : { \"type\" : \"boolean\" }, \"comment\" : { \"type\" : \"string\" }, \"delimiter\" : { \"type\" : \"string\" }, \"empty-value\" : { \"type\" : \"string\" }, \"header-extraction-enabled\" : { \"type\" : \"boolean\" }, \"headers-disabled\" : { \"type\" : \"boolean\" }, \"id\" : { \"type\" : \"string\" }, \"ignore-leading-whitespaces\" : { \"type\" : \"boolean\" }, \"ignore-trailing-whitespaces\" : { \"type\" : \"boolean\" }, \"lazy-load\" : { \"type\" : \"boolean\" }, \"line-separator\" : { \"type\" : \"string\" }, \"normalized-line-separator\" : { \"type\" : \"string\" }, \"null-value\" : { \"type\" : \"string\" }, \"number-of-records-to-read\" : { \"type\" : \"number\" }, \"quote\" : { \"type\" : \"string\" }, \"quote-all-fields\" : { \"type\" : \"boolean\" }, \"quote-escape\" : { \"type\" : \"string\" }, \"skip-empty-lines\" : { \"type\" : \"boolean\" }, \"univocity-header\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.UniVocityHeader\" } } } }, \"org.apache.camel.model.dataformat.UniVocityFixedDataFormat\" : { \"type\" : \"object\", \"properties\" : { \"as-map\" : { \"type\" : \"boolean\" }, \"comment\" : { \"type\" : \"string\" }, \"empty-value\" : { \"type\" : \"string\" }, \"header-extraction-enabled\" : { \"type\" : \"boolean\" }, \"headers-disabled\" : { \"type\" : \"boolean\" }, \"id\" : { \"type\" : \"string\" }, \"ignore-leading-whitespaces\" : { \"type\" : \"boolean\" }, \"ignore-trailing-whitespaces\" : { \"type\" : \"boolean\" }, \"lazy-load\" : { \"type\" : \"boolean\" }, \"line-separator\" : { \"type\" : \"string\" }, \"normalized-line-separator\" : { \"type\" : \"string\" }, \"null-value\" : { \"type\" : \"string\" }, \"number-of-records-to-read\" : { \"type\" : \"number\" }, \"padding\" : { \"type\" : \"string\" }, \"record-ends-on-newline\" : { \"type\" : \"boolean\" }, \"skip-empty-lines\" : { \"type\" : \"boolean\" }, \"skip-trailing-chars-until-newline\" : { \"type\" : \"boolean\" }, \"univocity-header\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.UniVocityHeader\" } } } }, \"org.apache.camel.model.dataformat.UniVocityHeader\" : { \"type\" : \"object\", \"properties\" : { \"length\" : { \"type\" : \"string\" }, \"name\" : { \"type\" : \"string\" } } }, \"org.apache.camel.model.dataformat.UniVocityTsvDataFormat\" : { \"type\" : \"object\", \"properties\" : { \"as-map\" : { \"type\" : \"boolean\" }, \"comment\" : { \"type\" : \"string\" }, \"empty-value\" : { \"type\" : \"string\" }, \"escape-char\" : { \"type\" : \"string\" }, \"header-extraction-enabled\" : { \"type\" : \"boolean\" }, \"headers-disabled\" : { \"type\" : \"boolean\" }, \"id\" : { \"type\" : \"string\" }, \"ignore-leading-whitespaces\" : { \"type\" : \"boolean\" }, \"ignore-trailing-whitespaces\" : { \"type\" : \"boolean\" }, \"lazy-load\" : { \"type\" : \"boolean\" }, \"line-separator\" : { \"type\" : \"string\" }, \"normalized-line-separator\" : { \"type\" : \"string\" }, \"null-value\" : { \"type\" : \"string\" }, \"number-of-records-to-read\" : { \"type\" : \"number\" }, \"skip-empty-lines\" : { \"type\" : \"boolean\" }, \"univocity-header\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.UniVocityHeader\" } } } }, \"org.apache.camel.model.dataformat.XMLSecurityDataFormat\" : { \"type\" : \"object\", \"properties\" : { \"add-key-value-for-encrypted-key\" : { \"type\" : \"boolean\" }, \"digest-algorithm\" : { \"type\" : \"string\", \"enum\" : [ \"SHA1\", \"SHA256\", \"SHA512\" ] }, \"id\" : { \"type\" : \"string\" }, \"key-cipher-algorithm\" : { \"type\" : \"string\", \"enum\" : [ \"RSA_v1dot5\", \"RSA_OAEP\", \"RSA_OAEP_11\" ] }, \"key-or-trust-store-parameters-ref\" : { \"type\" : \"string\" }, \"key-password\" : { \"type\" : \"string\" }, \"mgf-algorithm\" : { \"type\" : \"string\", \"enum\" : [ \"MGF1_SHA1\", \"MGF1_SHA256\", \"MGF1_SHA512\" ] }, \"pass-phrase\" : { \"type\" : \"string\" }, \"pass-phrase-byte\" : { \"type\" : \"string\" }, \"recipient-key-alias\" : { \"type\" : \"string\" }, \"secure-tag\" : { \"type\" : \"string\" }, \"secure-tag-contents\" : { \"type\" : \"boolean\" }, \"xml-cipher-algorithm\" : { \"type\" : \"string\", \"enum\" : [ \"TRIPLEDES\", \"AES_128\", \"AES_128_GCM\", \"AES_192\", \"AES_192_GCM\", \"AES_256\", \"AES_256_GCM\", \"SEED_128\", \"CAMELLIA_128\", \"CAMELLIA_192\", \"CAMELLIA_256\" ] } } }, \"org.apache.camel.model.dataformat.XStreamDataFormat\" : { \"oneOf\" : [ { \"type\" : \"string\" }, { \"type\" : \"object\", \"properties\" : { \"aliases\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.PropertyDefinition\" } }, \"content-type-header\" : { \"type\" : \"boolean\" }, \"converters\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.PropertyDefinition\" } }, \"driver\" : { \"type\" : \"string\" }, \"driver-ref\" : { \"type\" : \"string\" }, \"encoding\" : { \"type\" : \"string\" }, \"id\" : { \"type\" : \"string\" }, \"implicit-collections\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.PropertyDefinition\" } }, \"mode\" : { \"type\" : \"string\", \"enum\" : [ \"NO_REFERENCES\", \"ID_REFERENCES\", \"XPATH_RELATIVE_REFERENCES\", \"XPATH_ABSOLUTE_REFERENCES\", \"SINGLE_NODE_XPATH_RELATIVE_REFERENCES\", \"SINGLE_NODE_XPATH_ABSOLUTE_REFERENCES\" ] }, \"omit-fields\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.PropertyDefinition\" } }, \"permissions\" : { \"type\" : \"string\" } } } ] }, \"org.apache.camel.model.dataformat.YAMLDataFormat\" : { \"type\" : \"object\", \"properties\" : { \"allow-any-type\" : { \"type\" : \"boolean\" }, \"allow-recursive-keys\" : { \"type\" : \"boolean\" }, \"constructor\" : { \"type\" : \"string\" }, \"dumper-options\" : { \"type\" : \"string\" }, \"id\" : { \"type\" : \"string\" }, \"library\" : { \"type\" : \"string\", \"enum\" : [ \"SnakeYAML\" ] }, \"max-aliases-for-collections\" : { \"type\" : \"number\" }, \"pretty-flow\" : { \"type\" : \"boolean\" }, \"representer\" : { \"type\" : \"string\" }, \"resolver\" : { \"type\" : \"string\" }, \"type-filter\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.YAMLTypeFilterDefinition\" } }, \"unmarshal-type\" : { \"type\" : \"string\" }, \"use-application-context-class-loader\" : { \"type\" : \"boolean\" } } }, \"org.apache.camel.model.dataformat.YAMLTypeFilterDefinition\" : { \"type\" : \"object\", \"properties\" : { \"type\" : { \"type\" : \"string\" }, \"value\" : { \"type\" : \"string\" } } }, \"org.apache.camel.model.dataformat.ZipDeflaterDataFormat\" : { \"type\" : \"object\", \"properties\" : { \"compression-level\" : { \"type\" : \"string\", \"enum\" : [ \"-1\", \"0\", \"1\", \"2\", \"3\", \"4\", \"5\", \"6\", \"7\", \"8\", \"9\" ] }, \"id\" : { \"type\" : \"string\" } } }, \"org.apache.camel.model.dataformat.ZipFileDataFormat\" : { \"type\" : \"object\", \"properties\" : { \"allow-empty-directory\" : { \"type\" : \"boolean\" }, \"id\" : { \"type\" : \"string\" }, \"max-decompressed-size\" : { \"type\" : \"number\" }, \"preserve-path-elements\" : { \"type\" : \"boolean\" }, \"using-iterator\" : { \"type\" : \"boolean\" } } }, \"org.apache.camel.model.errorhandler.DeadLetterChannelDefinition\" : { \"type\" : \"object\", \"properties\" : { \"dead-letter-handle-new-exception\" : { \"type\" : \"boolean\" }, \"dead-letter-uri\" : { \"type\" : \"string\" }, \"executor-service-ref\" : { \"type\" : \"string\" }, \"id\" : { \"type\" : \"string\" }, \"level\" : { \"type\" : \"string\", \"enum\" : [ \"TRACE\", \"DEBUG\", \"INFO\", \"WARN\", \"ERROR\", \"OFF\" ] }, \"log-name\" : { \"type\" : \"string\" }, \"logger-ref\" : { \"type\" : \"string\" }, \"on-exception-occurred-ref\" : { \"type\" : \"string\" }, \"on-prepare-failure-ref\" : { \"type\" : \"string\" }, \"on-redelivery-ref\" : { \"type\" : \"string\" }, \"redelivery-policy\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.RedeliveryPolicyDefinition\" }, \"redelivery-policy-ref\" : { \"type\" : \"string\" }, \"retry-while-ref\" : { \"type\" : \"string\" }, \"use-original-body\" : { \"type\" : \"boolean\" }, \"use-original-message\" : { \"type\" : \"boolean\" } }, \"required\" : [ \"dead-letter-uri\" ] }, \"org.apache.camel.model.errorhandler.DefaultErrorHandlerDefinition\" : { \"type\" : \"object\", \"properties\" : { \"executor-service-ref\" : { \"type\" : \"string\" }, \"id\" : { \"type\" : \"string\" }, \"level\" : { \"type\" : \"string\", \"enum\" : [ \"TRACE\", \"DEBUG\", \"INFO\", \"WARN\", \"ERROR\", \"OFF\" ] }, \"log-name\" : { \"type\" : \"string\" }, \"logger-ref\" : { \"type\" : \"string\" }, \"on-exception-occurred-ref\" : { \"type\" : \"string\" }, \"on-prepare-failure-ref\" : { \"type\" : \"string\" }, \"on-redelivery-ref\" : { \"type\" : \"string\" }, \"redelivery-policy\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.RedeliveryPolicyDefinition\" }, \"redelivery-policy-ref\" : { \"type\" : \"string\" }, \"retry-while-ref\" : { \"type\" : \"string\" }, \"use-original-body\" : { \"type\" : \"boolean\" }, \"use-original-message\" : { \"type\" : \"boolean\" } } }, \"org.apache.camel.model.errorhandler.JtaTransactionErrorHandlerDefinition\" : { \"type\" : \"object\", \"properties\" : { \"executor-service-ref\" : { \"type\" : \"string\" }, \"id\" : { \"type\" : \"string\" }, \"level\" : { \"type\" : \"string\", \"enum\" : [ \"TRACE\", \"DEBUG\", \"INFO\", \"WARN\", \"ERROR\", \"OFF\" ] }, \"log-name\" : { \"type\" : \"string\" }, \"logger-ref\" : { \"type\" : \"string\" }, \"on-exception-occurred-ref\" : { \"type\" : \"string\" }, \"on-prepare-failure-ref\" : { \"type\" : \"string\" }, \"on-redelivery-ref\" : { \"type\" : \"string\" }, \"redelivery-policy\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.RedeliveryPolicyDefinition\" }, \"redelivery-policy-ref\" : { \"type\" : \"string\" }, \"retry-while-ref\" : { \"type\" : \"string\" }, \"rollback-logging-level\" : { \"type\" : \"string\", \"enum\" : [ \"TRACE\", \"DEBUG\", \"INFO\", \"WARN\", \"ERROR\", \"OFF\" ] }, \"transacted-policy-ref\" : { \"type\" : \"string\" }, \"use-original-body\" : { \"type\" : \"boolean\" }, \"use-original-message\" : { \"type\" : \"boolean\" } } }, \"org.apache.camel.model.errorhandler.NoErrorHandlerDefinition\" : { \"type\" : \"object\", \"properties\" : { \"id\" : { \"type\" : \"string\" } } }, \"org.apache.camel.model.errorhandler.RefErrorHandlerDefinition\" : { \"oneOf\" : [ { \"type\" : \"string\" }, { \"type\" : \"object\", \"properties\" : { \"id\" : { \"type\" : \"string\" }, \"ref\" : { \"type\" : \"string\" } } } ], \"required\" : [ \"ref\" ] }, \"org.apache.camel.model.errorhandler.SpringTransactionErrorHandlerDefinition\" : { \"type\" : \"object\", \"properties\" : { \"executor-service-ref\" : { \"type\" : \"string\" }, \"id\" : { \"type\" : \"string\" }, \"level\" : { \"type\" : \"string\", \"enum\" : [ \"TRACE\", \"DEBUG\", \"INFO\", \"WARN\", \"ERROR\", \"OFF\" ] }, \"log-name\" : { \"type\" : \"string\" }, \"logger-ref\" : { \"type\" : \"string\" }, \"on-exception-occurred-ref\" : { \"type\" : \"string\" }, \"on-prepare-failure-ref\" : { \"type\" : \"string\" }, \"on-redelivery-ref\" : { \"type\" : \"string\" }, \"redelivery-policy\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.RedeliveryPolicyDefinition\" }, \"redelivery-policy-ref\" : { \"type\" : \"string\" }, \"retry-while-ref\" : { \"type\" : \"string\" }, \"rollback-logging-level\" : { \"type\" : \"string\", \"enum\" : [ \"TRACE\", \"DEBUG\", \"INFO\", \"WARN\", \"ERROR\", \"OFF\" ] }, \"transacted-policy-ref\" : { \"type\" : \"string\" }, \"use-original-body\" : { \"type\" : \"boolean\" }, \"use-original-message\" : { \"type\" : \"boolean\" } } }, \"org.apache.camel.model.language.CSimpleExpression\" : { \"oneOf\" : [ { \"type\" : \"string\" }, { \"type\" : \"object\", \"properties\" : { \"expression\" : { \"type\" : \"string\" }, \"id\" : { \"type\" : \"string\" }, \"result-type\" : { \"type\" : \"string\" }, \"trim\" : { \"type\" : \"boolean\" } } } ], \"required\" : [ \"expression\" ] }, \"org.apache.camel.model.language.ConstantExpression\" : { \"oneOf\" : [ { \"type\" : \"string\" }, { \"type\" : \"object\", \"properties\" : { \"expression\" : { \"type\" : \"string\" }, \"id\" : { \"type\" : \"string\" }, \"result-type\" : { \"type\" : \"string\" }, \"trim\" : { \"type\" : \"boolean\" } } } ], \"required\" : [ \"expression\" ] }, \"org.apache.camel.model.language.DatasonnetExpression\" : { \"oneOf\" : [ { \"type\" : \"string\" }, { \"type\" : \"object\", \"properties\" : { \"body-media-type\" : { \"type\" : \"string\" }, \"expression\" : { \"type\" : \"string\" }, \"id\" : { \"type\" : \"string\" }, \"output-media-type\" : { \"type\" : \"string\" }, \"result-type\" : { \"type\" : \"string\" }, \"trim\" : { \"type\" : \"boolean\" } } } ], \"required\" : [ \"expression\" ] }, \"org.apache.camel.model.language.ExchangePropertyExpression\" : { \"oneOf\" : [ { \"type\" : \"string\" }, { \"type\" : \"object\", \"properties\" : { \"expression\" : { \"type\" : \"string\" }, \"id\" : { \"type\" : \"string\" }, \"trim\" : { \"type\" : \"boolean\" } } } ], \"required\" : [ \"expression\" ] }, \"org.apache.camel.model.language.ExpressionDefinition\" : { \"type\" : \"object\", \"properties\" : { \"constant\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.ConstantExpression\" }, \"csimple\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.CSimpleExpression\" }, \"datasonnet\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.DatasonnetExpression\" }, \"exchange-property\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.ExchangePropertyExpression\" }, \"exchangeProperty\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.ExchangePropertyExpression\" }, \"groovy\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.GroovyExpression\" }, \"header\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.HeaderExpression\" }, \"hl7terser\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.Hl7TerserExpression\" }, \"joor\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.JoorExpression\" }, \"jq\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.JqExpression\" }, \"js\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.JavaScriptExpression\" }, \"jsonpath\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.JsonPathExpression\" }, \"language\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.LanguageExpression\" }, \"method\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.MethodCallExpression\" }, \"mvel\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.MvelExpression\" }, \"ognl\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.OgnlExpression\" }, \"python\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.PythonExpression\" }, \"ref\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.RefExpression\" }, \"simple\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.SimpleExpression\" }, \"spel\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.SpELExpression\" }, \"tokenize\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.TokenizerExpression\" }, \"xpath\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.XPathExpression\" }, \"xquery\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.XQueryExpression\" }, \"xtokenize\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.XMLTokenizerExpression\" } } }, \"org.apache.camel.model.language.GroovyExpression\" : { \"oneOf\" : [ { \"type\" : \"string\" }, { \"type\" : \"object\", \"properties\" : { \"expression\" : { \"type\" : \"string\" }, \"id\" : { \"type\" : \"string\" }, \"result-type\" : { \"type\" : \"string\" }, \"trim\" : { \"type\" : \"boolean\" } } } ], \"required\" : [ \"expression\" ] }, \"org.apache.camel.model.language.HeaderExpression\" : { \"oneOf\" : [ { \"type\" : \"string\" }, { \"type\" : \"object\", \"properties\" : { \"expression\" : { \"type\" : \"string\" }, \"id\" : { \"type\" : \"string\" }, \"trim\" : { \"type\" : \"boolean\" } } } ], \"required\" : [ \"expression\" ] }, \"org.apache.camel.model.language.Hl7TerserExpression\" : { \"oneOf\" : [ { \"type\" : \"string\" }, { \"type\" : \"object\", \"properties\" : { \"expression\" : { \"type\" : \"string\" }, \"header-name\" : { \"type\" : \"string\" }, \"id\" : { \"type\" : \"string\" }, \"property-name\" : { \"type\" : \"string\" }, \"result-type\" : { \"type\" : \"string\" }, \"trim\" : { \"type\" : \"boolean\" } } } ], \"required\" : [ \"expression\" ] }, \"org.apache.camel.model.language.JavaScriptExpression\" : { \"oneOf\" : [ { \"type\" : \"string\" }, { \"type\" : \"object\", \"properties\" : { \"expression\" : { \"type\" : \"string\" }, \"id\" : { \"type\" : \"string\" }, \"result-type\" : { \"type\" : \"string\" }, \"trim\" : { \"type\" : \"boolean\" } } } ], \"required\" : [ \"expression\" ] }, \"org.apache.camel.model.language.JoorExpression\" : { \"oneOf\" : [ { \"type\" : \"string\" }, { \"type\" : \"object\", \"properties\" : { \"expression\" : { \"type\" : \"string\" }, \"id\" : { \"type\" : \"string\" }, \"pre-compile\" : { \"type\" : \"boolean\" }, \"result-type\" : { \"type\" : \"string\" }, \"single-quotes\" : { \"type\" : \"boolean\" }, \"trim\" : { \"type\" : \"boolean\" } } } ], \"required\" : [ \"expression\" ] }, \"org.apache.camel.model.language.JqExpression\" : { \"oneOf\" : [ { \"type\" : \"string\" }, { \"type\" : \"object\", \"properties\" : { \"expression\" : { \"type\" : \"string\" }, \"header-name\" : { \"type\" : \"string\" }, \"id\" : { \"type\" : \"string\" }, \"property-name\" : { \"type\" : \"string\" }, \"result-type\" : { \"type\" : \"string\" }, \"trim\" : { \"type\" : \"boolean\" } } } ], \"required\" : [ \"expression\" ] }, \"org.apache.camel.model.language.JsonPathExpression\" : { \"oneOf\" : [ { \"type\" : \"string\" }, { \"type\" : \"object\", \"properties\" : { \"allow-easy-predicate\" : { \"type\" : \"boolean\" }, \"allow-simple\" : { \"type\" : \"boolean\" }, \"expression\" : { \"type\" : \"string\" }, \"header-name\" : { \"type\" : \"string\" }, \"id\" : { \"type\" : \"string\" }, \"option\" : { \"type\" : \"string\", \"enum\" : [ \"DEFAULT_PATH_LEAF_TO_NULL\", \"ALWAYS_RETURN_LIST\", \"AS_PATH_LIST\", \"SUPPRESS_EXCEPTIONS\", \"REQUIRE_PROPERTIES\" ] }, \"property-name\" : { \"type\" : \"string\" }, \"result-type\" : { \"type\" : \"string\" }, \"suppress-exceptions\" : { \"type\" : \"boolean\" }, \"trim\" : { \"type\" : \"boolean\" }, \"unpack-array\" : { \"type\" : \"boolean\" }, \"write-as-string\" : { \"type\" : \"boolean\" } } } ], \"required\" : [ \"expression\" ] }, \"org.apache.camel.model.language.LanguageExpression\" : { \"type\" : \"object\", \"properties\" : { \"expression\" : { \"type\" : \"string\" }, \"id\" : { \"type\" : \"string\" }, \"language\" : { \"type\" : \"string\" }, \"trim\" : { \"type\" : \"boolean\" } }, \"required\" : [ \"expression\", \"language\" ] }, \"org.apache.camel.model.language.MethodCallExpression\" : { \"oneOf\" : [ { \"type\" : \"string\" }, { \"type\" : \"object\", \"properties\" : { \"bean-type\" : { \"type\" : \"string\" }, \"id\" : { \"type\" : \"string\" }, \"method\" : { \"type\" : \"string\" }, \"ref\" : { \"type\" : \"string\" }, \"result-type\" : { \"type\" : \"string\" }, \"scope\" : { \"type\" : \"string\", \"enum\" : [ \"Singleton\", \"Request\", \"Prototype\" ] }, \"trim\" : { \"type\" : \"boolean\" } } } ] }, \"org.apache.camel.model.language.MvelExpression\" : { \"oneOf\" : [ { \"type\" : \"string\" }, { \"type\" : \"object\", \"properties\" : { \"expression\" : { \"type\" : \"string\" }, \"id\" : { \"type\" : \"string\" }, \"result-type\" : { \"type\" : \"string\" }, \"trim\" : { \"type\" : \"boolean\" } } } ], \"required\" : [ \"expression\" ] }, \"org.apache.camel.model.language.OgnlExpression\" : { \"oneOf\" : [ { \"type\" : \"string\" }, { \"type\" : \"object\", \"properties\" : { \"expression\" : { \"type\" : \"string\" }, \"id\" : { \"type\" : \"string\" }, \"result-type\" : { \"type\" : \"string\" }, \"trim\" : { \"type\" : \"boolean\" } } } ], \"required\" : [ \"expression\" ] }, \"org.apache.camel.model.language.PythonExpression\" : { \"oneOf\" : [ { \"type\" : \"string\" }, { \"type\" : \"object\", \"properties\" : { \"expression\" : { \"type\" : \"string\" }, \"id\" : { \"type\" : \"string\" }, \"result-type\" : { \"type\" : \"string\" }, \"trim\" : { \"type\" : \"boolean\" } } } ], \"required\" : [ \"expression\" ] }, \"org.apache.camel.model.language.RefExpression\" : { \"oneOf\" : [ { \"type\" : \"string\" }, { \"type\" : \"object\", \"properties\" : { \"expression\" : { \"type\" : \"string\" }, \"id\" : { \"type\" : \"string\" }, \"result-type\" : { \"type\" : \"string\" }, \"trim\" : { \"type\" : \"boolean\" } } } ], \"required\" : [ \"expression\" ] }, \"org.apache.camel.model.language.SimpleExpression\" : { \"oneOf\" : [ { \"type\" : \"string\" }, { \"type\" : \"object\", \"properties\" : { \"expression\" : { \"type\" : \"string\" }, \"id\" : { \"type\" : \"string\" }, \"result-type\" : { \"type\" : \"string\" }, \"trim\" : { \"type\" : \"boolean\" } } } ], \"required\" : [ \"expression\" ] }, \"org.apache.camel.model.language.SpELExpression\" : { \"oneOf\" : [ { \"type\" : \"string\" }, { \"type\" : \"object\", \"properties\" : { \"expression\" : { \"type\" : \"string\" }, \"id\" : { \"type\" : \"string\" }, \"result-type\" : { \"type\" : \"string\" }, \"trim\" : { \"type\" : \"boolean\" } } } ], \"required\" : [ \"expression\" ] }, \"org.apache.camel.model.language.TokenizerExpression\" : { \"oneOf\" : [ { \"type\" : \"string\" }, { \"type\" : \"object\", \"properties\" : { \"end-token\" : { \"type\" : \"string\" }, \"group\" : { \"type\" : \"string\" }, \"group-delimiter\" : { \"type\" : \"string\" }, \"header-name\" : { \"type\" : \"string\" }, \"id\" : { \"type\" : \"string\" }, \"include-tokens\" : { \"type\" : \"boolean\" }, \"inherit-namespace-tag-name\" : { \"type\" : \"string\" }, \"property-name\" : { \"type\" : \"string\" }, \"regex\" : { \"type\" : \"boolean\" }, \"skip-first\" : { \"type\" : \"boolean\" }, \"token\" : { \"type\" : \"string\" }, \"trim\" : { \"type\" : \"boolean\" }, \"xml\" : { \"type\" : \"boolean\" } } } ], \"required\" : [ \"token\" ] }, \"org.apache.camel.model.language.XMLTokenizerExpression\" : { \"oneOf\" : [ { \"type\" : \"string\" }, { \"type\" : \"object\", \"properties\" : { \"expression\" : { \"type\" : \"string\" }, \"group\" : { \"type\" : \"number\" }, \"header-name\" : { \"type\" : \"string\" }, \"id\" : { \"type\" : \"string\" }, \"mode\" : { \"type\" : \"string\", \"enum\" : [ \"i\", \"w\", \"u\", \"t\" ] }, \"namespace\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.PropertyDefinition\" } }, \"property-name\" : { \"type\" : \"string\" }, \"trim\" : { \"type\" : \"boolean\" } } } ], \"required\" : [ \"expression\" ] }, \"org.apache.camel.model.language.XPathExpression\" : { \"oneOf\" : [ { \"type\" : \"string\" }, { \"type\" : \"object\", \"properties\" : { \"document-type\" : { \"type\" : \"string\" }, \"expression\" : { \"type\" : \"string\" }, \"factory-ref\" : { \"type\" : \"string\" }, \"header-name\" : { \"type\" : \"string\" }, \"id\" : { \"type\" : \"string\" }, \"log-namespaces\" : { \"type\" : \"boolean\" }, \"namespace\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.PropertyDefinition\" } }, \"object-model\" : { \"type\" : \"string\" }, \"pre-compile\" : { \"type\" : \"boolean\" }, \"property-name\" : { \"type\" : \"string\" }, \"result-type\" : { \"type\" : \"string\", \"enum\" : [ \"NUMBER\", \"STRING\", \"BOOLEAN\", \"NODESET\", \"NODE\" ] }, \"saxon\" : { \"type\" : \"boolean\" }, \"thread-safety\" : { \"type\" : \"boolean\" }, \"trim\" : { \"type\" : \"boolean\" } } } ], \"required\" : [ \"expression\" ] }, \"org.apache.camel.model.language.XQueryExpression\" : { \"oneOf\" : [ { \"type\" : \"string\" }, { \"type\" : \"object\", \"properties\" : { \"configuration-ref\" : { \"type\" : \"string\" }, \"expression\" : { \"type\" : \"string\" }, \"header-name\" : { \"type\" : \"string\" }, \"id\" : { \"type\" : \"string\" }, \"namespace\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.PropertyDefinition\" } }, \"property-name\" : { \"type\" : \"string\" }, \"result-type\" : { \"type\" : \"string\" }, \"trim\" : { \"type\" : \"boolean\" }, \"type\" : { \"type\" : \"string\" } } } ], \"required\" : [ \"expression\" ] }, \"org.apache.camel.model.loadbalancer.CustomLoadBalancerDefinition\" : { \"oneOf\" : [ { \"type\" : \"string\" }, { \"type\" : \"object\", \"properties\" : { \"id\" : { \"type\" : \"string\" }, \"ref\" : { \"type\" : \"string\" } } } ], \"required\" : [ \"ref\" ] }, \"org.apache.camel.model.loadbalancer.FailoverLoadBalancerDefinition\" : { \"type\" : \"object\", \"properties\" : { \"exception\" : { \"type\" : \"array\", \"items\" : { \"type\" : \"string\" } }, \"id\" : { \"type\" : \"string\" }, \"maximum-failover-attempts\" : { \"type\" : \"string\" }, \"round-robin\" : { \"type\" : \"string\" }, \"sticky\" : { \"type\" : \"string\" } } }, \"org.apache.camel.model.loadbalancer.RandomLoadBalancerDefinition\" : { \"type\" : \"object\", \"properties\" : { \"id\" : { \"type\" : \"string\" } } }, \"org.apache.camel.model.loadbalancer.RoundRobinLoadBalancerDefinition\" : { \"type\" : \"object\", \"properties\" : { \"id\" : { \"type\" : \"string\" } } }, \"org.apache.camel.model.loadbalancer.StickyLoadBalancerDefinition\" : { \"type\" : \"object\", \"properties\" : { \"correlation-expression\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.ExpressionSubElementDefinition\" }, \"id\" : { \"type\" : \"string\" } } }, \"org.apache.camel.model.loadbalancer.TopicLoadBalancerDefinition\" : { \"type\" : \"object\", \"properties\" : { \"id\" : { \"type\" : \"string\" } } }, \"org.apache.camel.model.loadbalancer.WeightedLoadBalancerDefinition\" : { \"type\" : \"object\", \"properties\" : { \"distribution-ratio\" : { \"type\" : \"string\" }, \"distribution-ratio-delimiter\" : { \"type\" : \"string\" }, \"id\" : { \"type\" : \"string\" }, \"round-robin\" : { \"type\" : \"boolean\" } }, \"required\" : [ \"distribution-ratio\" ] }, \"org.apache.camel.model.rest.ApiKeyDefinition\" : { \"type\" : \"object\", \"properties\" : { \"description\" : { \"type\" : \"string\" }, \"in-cookie\" : { \"type\" : \"boolean\" }, \"in-header\" : { \"type\" : \"boolean\" }, \"in-query\" : { \"type\" : \"boolean\" }, \"key\" : { \"type\" : \"string\" }, \"name\" : { \"type\" : \"string\" } }, \"required\" : [ \"key\", \"name\" ] }, \"org.apache.camel.model.rest.BasicAuthDefinition\" : { \"type\" : \"object\", \"properties\" : { \"description\" : { \"type\" : \"string\" }, \"key\" : { \"type\" : \"string\" } }, \"required\" : [ \"key\" ] }, \"org.apache.camel.model.rest.BearerTokenDefinition\" : { \"type\" : \"object\", \"properties\" : { \"description\" : { \"type\" : \"string\" }, \"format\" : { \"type\" : \"string\" }, \"key\" : { \"type\" : \"string\" } }, \"required\" : [ \"key\" ] }, \"org.apache.camel.model.rest.DeleteDefinition\" : { \"type\" : \"object\", \"properties\" : { \"api-docs\" : { \"type\" : \"boolean\" }, \"binding-mode\" : { \"type\" : \"string\", \"enum\" : [ \"off\", \"auto\", \"json\", \"xml\", \"json_xml\" ] }, \"client-request-validation\" : { \"type\" : \"boolean\" }, \"consumes\" : { \"type\" : \"string\" }, \"deprecated\" : { \"type\" : \"boolean\" }, \"description\" : { \"type\" : \"string\" }, \"disabled\" : { \"type\" : \"boolean\" }, \"enable-cors\" : { \"type\" : \"boolean\" }, \"id\" : { \"type\" : \"string\" }, \"out-type\" : { \"type\" : \"string\" }, \"param\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.rest.ParamDefinition\" } }, \"path\" : { \"type\" : \"string\" }, \"produces\" : { \"type\" : \"string\" }, \"response-message\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.rest.ResponseMessageDefinition\" } }, \"route-id\" : { \"type\" : \"string\" }, \"security\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.rest.SecurityDefinition\" } }, \"skip-binding-on-error-code\" : { \"type\" : \"boolean\" }, \"to\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.ToDefinition\" }, \"type\" : { \"type\" : \"string\" } } }, \"org.apache.camel.model.rest.GetDefinition\" : { \"type\" : \"object\", \"properties\" : { \"api-docs\" : { \"type\" : \"boolean\" }, \"binding-mode\" : { \"type\" : \"string\", \"enum\" : [ \"off\", \"auto\", \"json\", \"xml\", \"json_xml\" ] }, \"client-request-validation\" : { \"type\" : \"boolean\" }, \"consumes\" : { \"type\" : \"string\" }, \"deprecated\" : { \"type\" : \"boolean\" }, \"description\" : { \"type\" : \"string\" }, \"disabled\" : { \"type\" : \"boolean\" }, \"enable-cors\" : { \"type\" : \"boolean\" }, \"id\" : { \"type\" : \"string\" }, \"out-type\" : { \"type\" : \"string\" }, \"param\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.rest.ParamDefinition\" } }, \"path\" : { \"type\" : \"string\" }, \"produces\" : { \"type\" : \"string\" }, \"response-message\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.rest.ResponseMessageDefinition\" } }, \"route-id\" : { \"type\" : \"string\" }, \"security\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.rest.SecurityDefinition\" } }, \"skip-binding-on-error-code\" : { \"type\" : \"boolean\" }, \"to\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.ToDefinition\" }, \"type\" : { \"type\" : \"string\" } } }, \"org.apache.camel.model.rest.HeadDefinition\" : { \"type\" : \"object\", \"properties\" : { \"api-docs\" : { \"type\" : \"boolean\" }, \"binding-mode\" : { \"type\" : \"string\", \"enum\" : [ \"off\", \"auto\", \"json\", \"xml\", \"json_xml\" ] }, \"client-request-validation\" : { \"type\" : \"boolean\" }, \"consumes\" : { \"type\" : \"string\" }, \"deprecated\" : { \"type\" : \"boolean\" }, \"description\" : { \"type\" : \"string\" }, \"disabled\" : { \"type\" : \"boolean\" }, \"enable-cors\" : { \"type\" : \"boolean\" }, \"id\" : { \"type\" : \"string\" }, \"out-type\" : { \"type\" : \"string\" }, \"param\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.rest.ParamDefinition\" } }, \"path\" : { \"type\" : \"string\" }, \"produces\" : { \"type\" : \"string\" }, \"response-message\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.rest.ResponseMessageDefinition\" } }, \"route-id\" : { \"type\" : \"string\" }, \"security\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.rest.SecurityDefinition\" } }, \"skip-binding-on-error-code\" : { \"type\" : \"boolean\" }, \"to\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.ToDefinition\" }, \"type\" : { \"type\" : \"string\" } } }, \"org.apache.camel.model.rest.MutualTLSDefinition\" : { \"type\" : \"object\", \"properties\" : { \"description\" : { \"type\" : \"string\" }, \"key\" : { \"type\" : \"string\" } }, \"required\" : [ \"key\" ] }, \"org.apache.camel.model.rest.OAuth2Definition\" : { \"type\" : \"object\", \"properties\" : { \"authorization-url\" : { \"type\" : \"string\" }, \"description\" : { \"type\" : \"string\" }, \"flow\" : { \"type\" : \"string\", \"enum\" : [ \"implicit\", \"password\", \"application\", \"clientCredentials\", \"accessCode\", \"authorizationCode\" ] }, \"key\" : { \"type\" : \"string\" }, \"refresh-url\" : { \"type\" : \"string\" }, \"scopes\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.rest.RestPropertyDefinition\" } }, \"token-url\" : { \"type\" : \"string\" } }, \"required\" : [ \"key\" ] }, \"org.apache.camel.model.rest.OpenIdConnectDefinition\" : { \"type\" : \"object\", \"properties\" : { \"description\" : { \"type\" : \"string\" }, \"key\" : { \"type\" : \"string\" }, \"url\" : { \"type\" : \"string\" } }, \"required\" : [ \"key\", \"url\" ] }, \"org.apache.camel.model.rest.ParamDefinition\" : { \"type\" : \"object\", \"properties\" : { \"allowable-values\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.ValueDefinition\" } }, \"array-type\" : { \"type\" : \"string\" }, \"collection-format\" : { \"type\" : \"string\", \"enum\" : [ \"csv\", \"multi\", \"pipes\", \"ssv\", \"tsv\" ] }, \"data-format\" : { \"type\" : \"string\" }, \"data-type\" : { \"type\" : \"string\" }, \"default-value\" : { \"type\" : \"string\" }, \"description\" : { \"type\" : \"string\" }, \"examples\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.rest.RestPropertyDefinition\" } }, \"name\" : { \"type\" : \"string\" }, \"required\" : { \"type\" : \"boolean\" }, \"type\" : { \"type\" : \"string\", \"enum\" : [ \"body\", \"formData\", \"header\", \"path\", \"query\" ] } }, \"required\" : [ \"name\", \"type\" ] }, \"org.apache.camel.model.rest.PatchDefinition\" : { \"type\" : \"object\", \"properties\" : { \"api-docs\" : { \"type\" : \"boolean\" }, \"binding-mode\" : { \"type\" : \"string\", \"enum\" : [ \"off\", \"auto\", \"json\", \"xml\", \"json_xml\" ] }, \"client-request-validation\" : { \"type\" : \"boolean\" }, \"consumes\" : { \"type\" : \"string\" }, \"deprecated\" : { \"type\" : \"boolean\" }, \"description\" : { \"type\" : \"string\" }, \"disabled\" : { \"type\" : \"boolean\" }, \"enable-cors\" : { \"type\" : \"boolean\" }, \"id\" : { \"type\" : \"string\" }, \"out-type\" : { \"type\" : \"string\" }, \"param\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.rest.ParamDefinition\" } }, \"path\" : { \"type\" : \"string\" }, \"produces\" : { \"type\" : \"string\" }, \"response-message\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.rest.ResponseMessageDefinition\" } }, \"route-id\" : { \"type\" : \"string\" }, \"security\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.rest.SecurityDefinition\" } }, \"skip-binding-on-error-code\" : { \"type\" : \"boolean\" }, \"to\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.ToDefinition\" }, \"type\" : { \"type\" : \"string\" } } }, \"org.apache.camel.model.rest.PostDefinition\" : { \"type\" : \"object\", \"properties\" : { \"api-docs\" : { \"type\" : \"boolean\" }, \"binding-mode\" : { \"type\" : \"string\", \"enum\" : [ \"off\", \"auto\", \"json\", \"xml\", \"json_xml\" ] }, \"client-request-validation\" : { \"type\" : \"boolean\" }, \"consumes\" : { \"type\" : \"string\" }, \"deprecated\" : { \"type\" : \"boolean\" }, \"description\" : { \"type\" : \"string\" }, \"disabled\" : { \"type\" : \"boolean\" }, \"enable-cors\" : { \"type\" : \"boolean\" }, \"id\" : { \"type\" : \"string\" }, \"out-type\" : { \"type\" : \"string\" }, \"param\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.rest.ParamDefinition\" } }, \"path\" : { \"type\" : \"string\" }, \"produces\" : { \"type\" : \"string\" }, \"response-message\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.rest.ResponseMessageDefinition\" } }, \"route-id\" : { \"type\" : \"string\" }, \"security\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.rest.SecurityDefinition\" } }, \"skip-binding-on-error-code\" : { \"type\" : \"boolean\" }, \"to\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.ToDefinition\" }, \"type\" : { \"type\" : \"string\" } } }, \"org.apache.camel.model.rest.PutDefinition\" : { \"type\" : \"object\", \"properties\" : { \"api-docs\" : { \"type\" : \"boolean\" }, \"binding-mode\" : { \"type\" : \"string\", \"enum\" : [ \"off\", \"auto\", \"json\", \"xml\", \"json_xml\" ] }, \"client-request-validation\" : { \"type\" : \"boolean\" }, \"consumes\" : { \"type\" : \"string\" }, \"deprecated\" : { \"type\" : \"boolean\" }, \"description\" : { \"type\" : \"string\" }, \"disabled\" : { \"type\" : \"boolean\" }, \"enable-cors\" : { \"type\" : \"boolean\" }, \"id\" : { \"type\" : \"string\" }, \"out-type\" : { \"type\" : \"string\" }, \"param\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.rest.ParamDefinition\" } }, \"path\" : { \"type\" : \"string\" }, \"produces\" : { \"type\" : \"string\" }, \"response-message\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.rest.ResponseMessageDefinition\" } }, \"route-id\" : { \"type\" : \"string\" }, \"security\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.rest.SecurityDefinition\" } }, \"skip-binding-on-error-code\" : { \"type\" : \"boolean\" }, \"to\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.ToDefinition\" }, \"type\" : { \"type\" : \"string\" } } }, \"org.apache.camel.model.rest.ResponseHeaderDefinition\" : { \"type\" : \"object\", \"properties\" : { \"allowable-values\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.ValueDefinition\" } }, \"array-type\" : { \"type\" : \"string\" }, \"collection-format\" : { \"type\" : \"string\", \"enum\" : [ \"csv\", \"multi\", \"pipes\", \"ssv\", \"tsv\" ] }, \"data-format\" : { \"type\" : \"string\" }, \"data-type\" : { \"type\" : \"string\" }, \"description\" : { \"type\" : \"string\" }, \"example\" : { \"type\" : \"string\" }, \"name\" : { \"type\" : \"string\" } }, \"required\" : [ \"name\" ] }, \"org.apache.camel.model.rest.ResponseMessageDefinition\" : { \"type\" : \"object\", \"properties\" : { \"code\" : { \"type\" : \"string\" }, \"examples\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.rest.RestPropertyDefinition\" } }, \"header\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.rest.ResponseHeaderDefinition\" } }, \"message\" : { \"type\" : \"string\" }, \"response-model\" : { \"type\" : \"string\" } }, \"required\" : [ \"message\" ] }, \"org.apache.camel.model.rest.RestBindingDefinition\" : { \"type\" : \"object\", \"properties\" : { \"binding-mode\" : { \"type\" : \"string\", \"enum\" : [ \"off\", \"auto\", \"json\", \"xml\", \"json_xml\" ] }, \"client-request-validation\" : { \"type\" : \"boolean\" }, \"component\" : { \"type\" : \"string\" }, \"consumes\" : { \"type\" : \"string\" }, \"description\" : { \"type\" : \"string\" }, \"enable-cors\" : { \"type\" : \"boolean\" }, \"id\" : { \"type\" : \"string\" }, \"out-type\" : { \"type\" : \"string\" }, \"produces\" : { \"type\" : \"string\" }, \"skip-binding-on-error-code\" : { \"type\" : \"boolean\" }, \"type\" : { \"type\" : \"string\" } } }, \"org.apache.camel.model.rest.RestConfigurationDefinition\" : { \"type\" : \"object\", \"properties\" : { \"api-component\" : { \"type\" : \"string\", \"enum\" : [ \"openapi\", \"swagger\" ] }, \"api-context-path\" : { \"type\" : \"string\" }, \"api-context-route-id\" : { \"type\" : \"string\" }, \"api-host\" : { \"type\" : \"string\" }, \"api-property\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.rest.RestPropertyDefinition\" } }, \"api-vendor-extension\" : { \"type\" : \"boolean\" }, \"binding-mode\" : { \"type\" : \"string\", \"enum\" : [ \"auto\", \"json\", \"json_xml\", \"off\", \"xml\" ] }, \"client-request-validation\" : { \"type\" : \"boolean\" }, \"component\" : { \"type\" : \"string\", \"enum\" : [ \"platform-http\", \"servlet\", \"jetty\", \"undertow\", \"netty-http\", \"coap\" ] }, \"component-property\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.rest.RestPropertyDefinition\" } }, \"consumer-property\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.rest.RestPropertyDefinition\" } }, \"context-path\" : { \"type\" : \"string\" }, \"cors-headers\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.rest.RestPropertyDefinition\" } }, \"data-format-property\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.rest.RestPropertyDefinition\" } }, \"enable-cors\" : { \"type\" : \"boolean\" }, \"endpoint-property\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.rest.RestPropertyDefinition\" } }, \"host\" : { \"type\" : \"string\" }, \"host-name-resolver\" : { \"type\" : \"string\", \"enum\" : [ \"allLocalIp\", \"localHostName\", \"localIp\" ] }, \"inline-routes\" : { \"type\" : \"boolean\" }, \"json-data-format\" : { \"type\" : \"string\" }, \"port\" : { \"type\" : \"string\" }, \"producer-api-doc\" : { \"type\" : \"string\" }, \"producer-component\" : { \"type\" : \"string\", \"enum\" : [ \"vertx-http\", \"http\", \"undertow\", \"netty-http\" ] }, \"scheme\" : { \"type\" : \"string\" }, \"skip-binding-on-error-code\" : { \"type\" : \"boolean\" }, \"use-x-forward-headers\" : { \"type\" : \"boolean\" }, \"xml-data-format\" : { \"type\" : \"string\" } } }, \"org.apache.camel.model.rest.RestDefinition\" : { \"type\" : \"object\", \"properties\" : { \"api-docs\" : { \"type\" : \"boolean\" }, \"binding-mode\" : { \"type\" : \"string\", \"enum\" : [ \"off\", \"auto\", \"json\", \"xml\", \"json_xml\" ] }, \"client-request-validation\" : { \"type\" : \"boolean\" }, \"consumes\" : { \"type\" : \"string\" }, \"delete\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.rest.DeleteDefinition\" } }, \"description\" : { \"type\" : \"string\" }, \"disabled\" : { \"type\" : \"boolean\" }, \"enable-cors\" : { \"type\" : \"boolean\" }, \"get\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.rest.GetDefinition\" } }, \"head\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.rest.HeadDefinition\" } }, \"id\" : { \"type\" : \"string\" }, \"patch\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.rest.PatchDefinition\" } }, \"path\" : { \"type\" : \"string\" }, \"post\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.rest.PostDefinition\" } }, \"produces\" : { \"type\" : \"string\" }, \"put\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.rest.PutDefinition\" } }, \"security-definitions\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.rest.RestSecuritiesDefinition\" }, \"security-requirements\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.rest.SecurityDefinition\" } }, \"skip-binding-on-error-code\" : { \"type\" : \"boolean\" }, \"tag\" : { \"type\" : \"string\" } } }, \"org.apache.camel.model.rest.RestPropertyDefinition\" : { \"type\" : \"object\", \"properties\" : { \"key\" : { \"type\" : \"string\" }, \"value\" : { \"type\" : \"string\" } }, \"required\" : [ \"key\", \"value\" ] }, \"org.apache.camel.model.rest.RestSecuritiesDefinition\" : { \"type\" : \"object\", \"properties\" : { \"api-key\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.rest.ApiKeyDefinition\" }, \"basic-auth\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.rest.BasicAuthDefinition\" }, \"bearer\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.rest.BearerTokenDefinition\" }, \"mutual-tls\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.rest.MutualTLSDefinition\" }, \"oauth2\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.rest.OAuth2Definition\" }, \"open-id-connect\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.rest.OpenIdConnectDefinition\" } } }, \"org.apache.camel.model.rest.RestsDefinition\" : { \"type\" : \"object\", \"properties\" : { \"description\" : { \"type\" : \"string\" }, \"id\" : { \"type\" : \"string\" }, \"rest\" : { \"type\" : \"array\", \"items\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.rest.RestDefinition\" } } } }, \"org.apache.camel.model.rest.SecurityDefinition\" : { \"type\" : \"object\", \"properties\" : { \"key\" : { \"type\" : \"string\" }, \"scopes\" : { \"type\" : \"string\" } }, \"required\" : [ \"key\" ] }, \"org.apache.camel.model.transformer.CustomTransformerDefinition\" : { \"type\" : \"object\", \"properties\" : { \"class-name\" : { \"type\" : \"string\" }, \"from-type\" : { \"type\" : \"string\" }, \"ref\" : { \"type\" : \"string\" }, \"scheme\" : { \"type\" : \"string\" }, \"to-type\" : { \"type\" : \"string\" } } }, \"org.apache.camel.model.transformer.DataFormatTransformerDefinition\" : { \"type\" : \"object\", \"properties\" : { \"any23\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.Any23DataFormat\" }, \"asn1\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.ASN1DataFormat\" }, \"avro\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.AvroDataFormat\" }, \"barcode\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.BarcodeDataFormat\" }, \"base64\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.Base64DataFormat\" }, \"bindy\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.BindyDataFormat\" }, \"cbor\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.CBORDataFormat\" }, \"crypto\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.CryptoDataFormat\" }, \"csv\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.CsvDataFormat\" }, \"custom\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.CustomDataFormat\" }, \"fhir-json\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.FhirJsonDataFormat\" }, \"fhir-xml\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.FhirXmlDataFormat\" }, \"flatpack\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.FlatpackDataFormat\" }, \"from-type\" : { \"type\" : \"string\" }, \"grok\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.GrokDataFormat\" }, \"gzip-deflater\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.GzipDeflaterDataFormat\" }, \"hl7\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.HL7DataFormat\" }, \"ical\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.IcalDataFormat\" }, \"jackson-xml\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.JacksonXMLDataFormat\" }, \"jaxb\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.JaxbDataFormat\" }, \"json\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.JsonDataFormat\" }, \"json-api\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.JsonApiDataFormat\" }, \"lzf\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.LZFDataFormat\" }, \"mime-multipart\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.MimeMultipartDataFormat\" }, \"pgp\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.PGPDataFormat\" }, \"protobuf\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.ProtobufDataFormat\" }, \"rss\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.RssDataFormat\" }, \"scheme\" : { \"type\" : \"string\" }, \"soap\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.SoapDataFormat\" }, \"swift-mt\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.SwiftMtDataFormat\" }, \"swift-mx\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.SwiftMxDataFormat\" }, \"syslog\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.SyslogDataFormat\" }, \"tar-file\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.TarFileDataFormat\" }, \"thrift\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.ThriftDataFormat\" }, \"tidy-markup\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.TidyMarkupDataFormat\" }, \"to-type\" : { \"type\" : \"string\" }, \"univocity-csv\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.UniVocityCsvDataFormat\" }, \"univocity-fixed\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.UniVocityFixedDataFormat\" }, \"univocity-tsv\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.UniVocityTsvDataFormat\" }, \"xml-security\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.XMLSecurityDataFormat\" }, \"xstream\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.XStreamDataFormat\" }, \"yaml\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.YAMLDataFormat\" }, \"zip-deflater\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.ZipDeflaterDataFormat\" }, \"zip-file\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.dataformat.ZipFileDataFormat\" } } }, \"org.apache.camel.model.transformer.EndpointTransformerDefinition\" : { \"type\" : \"object\", \"properties\" : { \"from-type\" : { \"type\" : \"string\" }, \"ref\" : { \"type\" : \"string\" }, \"scheme\" : { \"type\" : \"string\" }, \"to-type\" : { \"type\" : \"string\" }, \"uri\" : { \"type\" : \"string\" } } }, \"org.apache.camel.model.transformer.TransformersDefinition\" : { \"type\" : \"object\", \"properties\" : { \"custom-transformer\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.transformer.CustomTransformerDefinition\" }, \"data-format-transformer\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.transformer.DataFormatTransformerDefinition\" }, \"endpoint-transformer\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.transformer.EndpointTransformerDefinition\" } } }, \"org.apache.camel.model.validator.CustomValidatorDefinition\" : { \"type\" : \"object\", \"properties\" : { \"class-name\" : { \"type\" : \"string\" }, \"ref\" : { \"type\" : \"string\" }, \"type\" : { \"type\" : \"string\" } } }, \"org.apache.camel.model.validator.EndpointValidatorDefinition\" : { \"type\" : \"object\", \"properties\" : { \"ref\" : { \"type\" : \"string\" }, \"type\" : { \"type\" : \"string\" }, \"uri\" : { \"type\" : \"string\" } } }, \"org.apache.camel.model.validator.PredicateValidatorDefinition\" : { \"type\" : \"object\", \"properties\" : { \"expression\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.language.ExpressionDefinition\" }, \"type\" : { \"type\" : \"string\" } } }, \"org.apache.camel.model.validator.ValidatorsDefinition\" : { \"type\" : \"object\", \"properties\" : { \"custom-validator\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.validator.CustomValidatorDefinition\" }, \"endpoint-validator\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.validator.EndpointValidatorDefinition\" }, \"predicate-validator\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.validator.PredicateValidatorDefinition\" } } } }, \"properties\" : { \"beans\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.dsl.yaml.deserializers.BeansDeserializer\" }, \"error-handler\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.dsl.yaml.deserializers.ErrorHandlerBuilderDeserializer\" }, \"errorHandler\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.dsl.yaml.deserializers.ErrorHandlerBuilderDeserializer\" }, \"from\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.dsl.yaml.deserializers.RouteFromDefinitionDeserializer\" }, \"on-exception\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.OnExceptionDefinition\" }, \"onException\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.OnExceptionDefinition\" }, \"route-configuration\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.RouteConfigurationDefinition\" }, \"routeConfiguration\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.RouteConfigurationDefinition\" }, \"route\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.RouteDefinition\" }, \"route-template\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.RouteTemplateDefinition\" }, \"routeTemplate\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.RouteTemplateDefinition\" }, \"templated-route\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.TemplatedRouteDefinition\" }, \"templatedRoute\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.TemplatedRouteDefinition\" }, \"rest\" : { \"$ref\" : \"#/items/definitions/org.apache.camel.model.rest.RestDefinition\" } } } }" diff --git a/vendor/github.com/kiegroup/kogito-serverless-operator/workflowproj/io.go b/vendor/github.com/kiegroup/kogito-serverless-operator/workflowproj/io.go new file mode 100644 index 0000000000..9fa84f47b5 --- /dev/null +++ b/vendor/github.com/kiegroup/kogito-serverless-operator/workflowproj/io.go @@ -0,0 +1,59 @@ +// Copyright 2023 Red Hat, Inc. and/or its affiliates +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package workflowproj + +import ( + "fmt" + "os" + "path/filepath" + "reflect" + "strings" + + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/yaml" +) + +const ( + yamlFileExt = ".yaml" +) + +func ensurePath(path string) error { + err := os.MkdirAll(path, os.ModePerm) + if err != nil { + return err + } + return nil +} + +func saveAsKubernetesManifest(object client.Object, savePath, prefix string) error { + if reflect.ValueOf(object).IsNil() { + return nil + } + filename := strings.ToLower(fmt.Sprintf("%s%s_%s%s", + prefix, + object.GetObjectKind().GroupVersionKind().Kind, + object.GetName(), + yamlFileExt)) + finalPath := filepath.Join(savePath, filename) + contents, err := yaml.Marshal(object) + if err != nil { + return err + } + err = os.WriteFile(finalPath, contents, os.ModePerm) + if err != nil { + return err + } + return nil +} diff --git a/vendor/github.com/kiegroup/kogito-serverless-operator/workflowproj/operator.go b/vendor/github.com/kiegroup/kogito-serverless-operator/workflowproj/operator.go new file mode 100644 index 0000000000..3c620ac59d --- /dev/null +++ b/vendor/github.com/kiegroup/kogito-serverless-operator/workflowproj/operator.go @@ -0,0 +1,91 @@ +// Copyright 2023 Red Hat, Inc. and/or its affiliates +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package workflowproj + +import ( + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + + "github.com/kiegroup/kogito-serverless-operator/api/metadata" + operatorapi "github.com/kiegroup/kogito-serverless-operator/api/v1alpha08" +) + +const ( + workflowConfigMapNameSuffix = "-props" + // ApplicationPropertiesFileName is the default application properties file name + ApplicationPropertiesFileName = "application.properties" + // LabelApp key to use among object selectors + LabelApp = "app" +) + +// SetTypeToObject sets the Kind and ApiVersion to a given object since the default constructor won't do it. +// See: https://github.com/kubernetes/client-go/issues/308#issuecomment-700099260 +func SetTypeToObject(obj runtime.Object, s *runtime.Scheme) error { + gvks, _, err := s.ObjectKinds(obj) + if err != nil { + return err + } + for _, gvk := range gvks { + if len(gvk.Kind) == 0 { + continue + } + if len(gvk.Version) == 0 || gvk.Version == runtime.APIVersionInternal { + continue + } + obj.GetObjectKind().SetGroupVersionKind(gvk) + break + } + return nil +} + +// GetWorkflowPropertiesConfigMapName gets the default ConfigMap name that holds the application property for the given workflow +func GetWorkflowPropertiesConfigMapName(workflow *operatorapi.SonataFlow) string { + return workflow.Name + workflowConfigMapNameSuffix +} + +// SetDefaultLabels adds the default workflow application labels to the given object. +// Overrides the defined labels. +func SetDefaultLabels(workflow *operatorapi.SonataFlow, object metav1.Object) { + object.SetLabels(GetDefaultLabels(workflow)) +} + +// GetDefaultLabels gets the default labels based on the given workflow. +// You can use SetDefaultLabels that essentially does the same thing, if you don't need the labels explicitly. +func GetDefaultLabels(workflow *operatorapi.SonataFlow) map[string]string { + return map[string]string{ + LabelApp: workflow.Name, + } +} + +// CreateNewAppPropsConfigMap creates a new ConfigMap object to hold the workflow application properties. +func CreateNewAppPropsConfigMap(workflow *operatorapi.SonataFlow, properties string) *corev1.ConfigMap { + return &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: GetWorkflowPropertiesConfigMapName(workflow), + Namespace: workflow.Namespace, + Labels: GetDefaultLabels(workflow), + }, + Data: map[string]string{ApplicationPropertiesFileName: properties}, + } +} + +// SetWorkflowProfile adds the profile annotation to the workflow +func SetWorkflowProfile(workflow *operatorapi.SonataFlow, profile metadata.ProfileType) { + if workflow.Annotations == nil { + workflow.Annotations = map[string]string{} + } + workflow.Annotations[metadata.Profile] = string(profile) +} diff --git a/vendor/github.com/kiegroup/kogito-serverless-operator/workflowproj/resources.go b/vendor/github.com/kiegroup/kogito-serverless-operator/workflowproj/resources.go new file mode 100644 index 0000000000..7d5e436b20 --- /dev/null +++ b/vendor/github.com/kiegroup/kogito-serverless-operator/workflowproj/resources.go @@ -0,0 +1,68 @@ +// Copyright 2023 Red Hat, Inc. and/or its affiliates +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package workflowproj + +import ( + "strings" + + "github.com/pb33f/libopenapi" + libopenapiutils "github.com/pb33f/libopenapi/utils" + "github.com/santhosh-tekuri/jsonschema/v5" + "k8s.io/apimachinery/pkg/util/yaml" +) + +type ResourceKind int + +const ( + OpenApiResource ResourceKind = iota + AsyncApiResource + CamelRouteResource + GenericResource +) + +// ParseResourceKind tries to parse the contents of the given resource and find the correct type. +// Async and OpenAPI files are pretty fast to parse (0.00s). +// Camel and generic files can take a fair price from the CPU (0.03s on the i5) since it takes more processing power. +func ParseResourceKind(contents []byte) ResourceKind { + if len(contents) == 0 { + return GenericResource + } + doc, err := libopenapi.NewDocument(contents) + if err == nil { + switch doc.GetSpecInfo().SpecType { + case libopenapiutils.AsyncApi: + return AsyncApiResource + default: + return OpenApiResource + } + } + if err = validateCamelRoute(contents); err == nil { + return CamelRouteResource + } + return GenericResource +} + +func validateCamelRoute(contents []byte) error { + schema, err := jsonschema.CompileString("camel.json", camelSchema) + if err != nil { + return err + } + decoder := yaml.NewYAMLOrJSONDecoder(strings.NewReader(string(contents)), 512) + var v []interface{} + if err = decoder.Decode(&v); err != nil { + return err + } + return schema.Validate(v) +} diff --git a/vendor/github.com/kiegroup/kogito-serverless-operator/workflowproj/workflowproj.go b/vendor/github.com/kiegroup/kogito-serverless-operator/workflowproj/workflowproj.go new file mode 100644 index 0000000000..2a64b0b005 --- /dev/null +++ b/vendor/github.com/kiegroup/kogito-serverless-operator/workflowproj/workflowproj.go @@ -0,0 +1,286 @@ +// Copyright 2023 Red Hat, Inc. and/or its affiliates +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package workflowproj + +import ( + "context" + "fmt" + "io" + "strings" + + "github.com/pkg/errors" + "github.com/serverlessworkflow/sdk-go/v2/model" + "github.com/serverlessworkflow/sdk-go/v2/parser" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + "k8s.io/client-go/kubernetes/scheme" + + "github.com/kiegroup/kogito-serverless-operator/api/metadata" + operatorapi "github.com/kiegroup/kogito-serverless-operator/api/v1alpha08" +) + +var _ WorkflowProjectHandler = &workflowProjectHandler{} + +// defaultResourcePath is the default resource path to add to the generated ConfigMaps +const defaultResourcePath = "specs" + +// WorkflowProjectHandler is the description of the handler interface. +// A handler can generate Kubernetes manifests to deploy a new SonataFlow project in the cluster +type WorkflowProjectHandler interface { + // Named overwrites the workflow ID. The handler will use this name instead to generate the manifests name. + // Remember that together with the Namespace, the Name is the unique key of a Kubernetes object. + Named(name string) WorkflowProjectHandler + // WithWorkflow reader for a file or the content stream of a workflow definition. + WithWorkflow(reader io.Reader) WorkflowProjectHandler + // WithAppProperties reader for a file or the content stream of a workflow application properties. + WithAppProperties(reader io.Reader) WorkflowProjectHandler + // AddResource reader for a file or the content stream of any resource needed by the workflow. E.g. an OpenAPI specification file. + // Name is required, should match the workflow function definition. + AddResource(name string, reader io.Reader) WorkflowProjectHandler + // AddResourceAt same as AddResource, but defines the path instead of using the default. + AddResourceAt(name, path string, reader io.Reader) WorkflowProjectHandler + // SaveAsKubernetesManifests saves the project in the given file system path in YAML format. + SaveAsKubernetesManifests(path string) error + // AsObjects returns a reference to the WorkflowProject holding the Kubernetes Manifests based on your files. + AsObjects() (*WorkflowProject, error) +} + +// WorkflowProject is a structure to hold every Kubernetes object generated by the given WorkflowProjectHandler handler. +type WorkflowProject struct { + // Workflow the workflow definition + Workflow *operatorapi.SonataFlow + // Properties the application properties for the workflow + Properties *corev1.ConfigMap + // Resources any resource that this workflow requires, like an OpenAPI specification file. + Resources []*corev1.ConfigMap +} + +type resource struct { + name string + contents io.Reader +} + +// New is the entry point for this package. +// You can create a new handler with the given namespace, meaning that every manifest generated will use this namespace. +// namespace is a required parameter. +func New(namespace string) WorkflowProjectHandler { + s := scheme.Scheme + utilruntime.Must(operatorapi.AddToScheme(s)) + utilruntime.Must(corev1.AddToScheme(s)) + return &workflowProjectHandler{ + scheme: s, + namespace: namespace, + rawResources: map[string][]*resource{}, + } +} + +type workflowProjectHandler struct { + name string + namespace string + scheme *runtime.Scheme + project WorkflowProject + rawWorkflow io.Reader + rawAppProperties io.Reader + rawResources map[string][]*resource + parsed bool +} + +func (w *workflowProjectHandler) Named(name string) WorkflowProjectHandler { + w.name = strings.ToLower(name) + w.parsed = false + return w +} + +func (w *workflowProjectHandler) WithWorkflow(reader io.Reader) WorkflowProjectHandler { + w.rawWorkflow = reader + w.parsed = false + return w +} + +func (w *workflowProjectHandler) WithAppProperties(reader io.Reader) WorkflowProjectHandler { + w.rawAppProperties = reader + w.parsed = false + return w +} + +func (w *workflowProjectHandler) AddResource(name string, reader io.Reader) WorkflowProjectHandler { + return w.AddResourceAt(name, defaultResourcePath, reader) +} + +func (w *workflowProjectHandler) AddResourceAt(name, path string, reader io.Reader) WorkflowProjectHandler { + for _, r := range w.rawResources[path] { + if r.name == name { + r.contents = reader + return w + } + } + w.rawResources[path] = append(w.rawResources[path], &resource{name: name, contents: reader}) + w.parsed = false + return w +} + +func (w *workflowProjectHandler) SaveAsKubernetesManifests(path string) error { + if err := ensurePath(path); err != nil { + return err + } + if err := w.parseRawProject(); err != nil { + return err + } + fileCount := 1 + if err := saveAsKubernetesManifest(w.project.Workflow, path, fmt.Sprintf("%02d-", 1)); err != nil { + return err + } + for i, r := range w.project.Resources { + fileCount = i + 1 + if err := saveAsKubernetesManifest(r, path, fmt.Sprintf("%02d-", fileCount)); err != nil { + return err + } + } + fileCount++ + if err := saveAsKubernetesManifest(w.project.Properties, path, fmt.Sprintf("%02d-", fileCount)); err != nil { + return err + } + return nil +} + +func (w *workflowProjectHandler) AsObjects() (*WorkflowProject, error) { + if err := w.parseRawProject(); err != nil { + return nil, err + } + return &w.project, nil +} + +func (w *workflowProjectHandler) parseRawProject() error { + if w.parsed { + return nil + } + if err := w.sanityCheck(); err != nil { + return err + } + if err := w.parseRawWorkflow(); err != nil { + return err + } + if err := w.parseRawAppProperties(); err != nil { + return err + } + if err := w.parseRawResources(); err != nil { + return err + } + w.parsed = true + return nil +} + +func (w *workflowProjectHandler) sanityCheck() error { + if len(w.namespace) == 0 { + return errors.New("Namespace is required when building Workflow projects") + } + if w.rawWorkflow == nil { + return errors.New("A workflow reader pointer is required when building Workflow projects") + } + return nil +} + +func (w *workflowProjectHandler) parseRawWorkflow() error { + workflowContents, err := io.ReadAll(w.rawWorkflow) + if err != nil { + return err + } + var workflowDef *model.Workflow + // TODO: add this to the SDK, also an input from io.Reader + workflowDef, err = parser.FromJSONSource(workflowContents) + if err != nil { + workflowDef, err = parser.FromYAMLSource(workflowContents) + if err != nil { + return errors.Errorf("Failed to parse the workflow either as a JSON or as a YAML file: %+v", err) + } + } + + if len(w.name) == 0 { + w.name = strings.ToLower(workflowDef.ID) + } + + w.project.Workflow, err = operatorapi.FromCNCFWorkflow(workflowDef, context.TODO()) + w.project.Workflow.Name = w.name + w.project.Workflow.Namespace = w.namespace + + SetWorkflowProfile(w.project.Workflow, metadata.DevProfile) + SetDefaultLabels(w.project.Workflow, w.project.Workflow) + if err = SetTypeToObject(w.project.Workflow, w.scheme); err != nil { + return err + } + + return nil +} + +func (w *workflowProjectHandler) parseRawAppProperties() error { + if w.rawAppProperties == nil { + return nil + } + appPropsContent, err := io.ReadAll(w.rawAppProperties) + if err != nil { + return err + } + w.project.Properties = CreateNewAppPropsConfigMap(w.project.Workflow, string(appPropsContent)) + if err = SetTypeToObject(w.project.Properties, w.scheme); err != nil { + return err + } + return nil +} + +func (w *workflowProjectHandler) parseRawResources() error { + if len(w.rawResources) == 0 { + return nil + } + + resourceCount := 1 + for path, resources := range w.rawResources { + cm := &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{Namespace: w.namespace, Name: fmt.Sprintf("%02d-%s-resources", resourceCount, w.name)}, + Data: map[string]string{}, + } + + for _, r := range resources { + contents, err := io.ReadAll(r.contents) + if err != nil { + return err + } + if len(contents) == 0 { + return errors.Errorf("Content for the resource %s is empty. Can't add an empty resource to the workflow project", r.name) + } + cm.Data[r.name] = string(contents) + } + + if err := w.addResourceConfigMapToProject(cm, path); err != nil { + return err + } + resourceCount++ + } + + return nil +} + +func (w *workflowProjectHandler) addResourceConfigMapToProject(cm *corev1.ConfigMap, path string) error { + if cm.Data != nil { + if err := SetTypeToObject(cm, w.scheme); err != nil { + return err + } + w.project.Workflow.Spec.Resources.ConfigMaps = append(w.project.Workflow.Spec.Resources.ConfigMaps, + operatorapi.ConfigMapWorkflowResource{ConfigMap: corev1.LocalObjectReference{Name: cm.Name}, WorkflowPath: path}) + w.project.Resources = append(w.project.Resources, cm) + } + return nil +} diff --git a/vendor/github.com/leodido/go-urn/.gitignore b/vendor/github.com/leodido/go-urn/.gitignore new file mode 100644 index 0000000000..5bcf4bade0 --- /dev/null +++ b/vendor/github.com/leodido/go-urn/.gitignore @@ -0,0 +1,11 @@ +*.exe +*.dll +*.so +*.dylib + +*.test + +*.out +*.txt + +vendor/ \ No newline at end of file diff --git a/vendor/github.com/leodido/go-urn/.travis.yml b/vendor/github.com/leodido/go-urn/.travis.yml new file mode 100644 index 0000000000..21f348d65a --- /dev/null +++ b/vendor/github.com/leodido/go-urn/.travis.yml @@ -0,0 +1,16 @@ +language: go + +go: + - 1.13.x + - 1.14.x + - 1.15.x + - tip + +before_install: + - go get -t -v ./... + +script: + - go test -race -coverprofile=coverage.txt -covermode=atomic + +after_success: + - bash <(curl -s https://codecov.io/bash) \ No newline at end of file diff --git a/vendor/github.com/leodido/go-urn/LICENSE b/vendor/github.com/leodido/go-urn/LICENSE new file mode 100644 index 0000000000..8c3504a5a9 --- /dev/null +++ b/vendor/github.com/leodido/go-urn/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 Leonardo Di Donato + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/leodido/go-urn/README.md b/vendor/github.com/leodido/go-urn/README.md new file mode 100644 index 0000000000..cc902ec0e3 --- /dev/null +++ b/vendor/github.com/leodido/go-urn/README.md @@ -0,0 +1,55 @@ +[![Build](https://img.shields.io/travis/leodido/go-urn/master.svg?style=for-the-badge)](https://travis-ci.org/leodido/go-urn) [![Coverage](https://img.shields.io/codecov/c/github/leodido/go-urn.svg?style=for-the-badge)](https://codecov.io/gh/leodido/go-urn) [![Documentation](https://img.shields.io/badge/godoc-reference-blue.svg?style=for-the-badge)](https://godoc.org/github.com/leodido/go-urn) + +**A parser for URNs**. + +> As seen on [RFC 2141](https://tools.ietf.org/html/rfc2141#ref-1). + +[API documentation](https://godoc.org/github.com/leodido/go-urn). + +## Installation + +``` +go get github.com/leodido/go-urn +``` + +## Performances + +This implementation results to be really fast. + +Usually below ½ microsecond on my machine[1](#mymachine). + +Notice it also performs, while parsing: + +1. fine-grained and informative erroring +2. specific-string normalization + +``` +ok/00/urn:a:b______________________________________/-4 20000000 265 ns/op 182 B/op 6 allocs/op +ok/01/URN:foo:a123,456_____________________________/-4 30000000 296 ns/op 200 B/op 6 allocs/op +ok/02/urn:foo:a123%2c456___________________________/-4 20000000 331 ns/op 208 B/op 6 allocs/op +ok/03/urn:ietf:params:scim:schemas:core:2.0:User___/-4 20000000 430 ns/op 280 B/op 6 allocs/op +ok/04/urn:ietf:params:scim:schemas:extension:enterp/-4 20000000 411 ns/op 312 B/op 6 allocs/op +ok/05/urn:ietf:params:scim:schemas:extension:enterp/-4 20000000 472 ns/op 344 B/op 6 allocs/op +ok/06/urn:burnout:nss______________________________/-4 30000000 257 ns/op 192 B/op 6 allocs/op +ok/07/urn:abcdefghilmnopqrstuvzabcdefghilm:x_______/-4 20000000 375 ns/op 213 B/op 6 allocs/op +ok/08/urn:urnurnurn:urn____________________________/-4 30000000 265 ns/op 197 B/op 6 allocs/op +ok/09/urn:ciao:@!=%2c(xyz)+a,b.*@g=$_'_____________/-4 20000000 307 ns/op 248 B/op 6 allocs/op +ok/10/URN:x:abc%1dz%2f%3az_________________________/-4 30000000 259 ns/op 212 B/op 6 allocs/op +no/11/URN:-xxx:x___________________________________/-4 20000000 445 ns/op 320 B/op 6 allocs/op +no/12/urn::colon:nss_______________________________/-4 20000000 461 ns/op 320 B/op 6 allocs/op +no/13/urn:abcdefghilmnopqrstuvzabcdefghilmn:specifi/-4 10000000 660 ns/op 320 B/op 6 allocs/op +no/14/URN:a!?:x____________________________________/-4 20000000 507 ns/op 320 B/op 6 allocs/op +no/15/urn:urn:NSS__________________________________/-4 20000000 429 ns/op 288 B/op 6 allocs/op +no/16/urn:white_space:NSS__________________________/-4 20000000 482 ns/op 320 B/op 6 allocs/op +no/17/urn:concat:no_spaces_________________________/-4 20000000 539 ns/op 328 B/op 7 allocs/op +no/18/urn:a:/______________________________________/-4 20000000 470 ns/op 320 B/op 7 allocs/op +no/19/urn:UrN:NSS__________________________________/-4 20000000 399 ns/op 288 B/op 6 allocs/op +``` + +--- + +* [1]: Intel Core i7-7600U CPU @ 2.80GHz + +--- + +[![Analytics](https://ga-beacon.appspot.com/UA-49657176-1/go-urn?flat)](https://github.com/igrigorik/ga-beacon) \ No newline at end of file diff --git a/vendor/github.com/leodido/go-urn/machine.go b/vendor/github.com/leodido/go-urn/machine.go new file mode 100644 index 0000000000..fe5a0cc861 --- /dev/null +++ b/vendor/github.com/leodido/go-urn/machine.go @@ -0,0 +1,1691 @@ +package urn + +import ( + "fmt" +) + +var ( + errPrefix = "expecting the prefix to be the \"urn\" string (whatever case) [col %d]" + errIdentifier = "expecting the identifier to be string (1..31 alnum chars, also containing dashes but not at its start) [col %d]" + errSpecificString = "expecting the specific string to be a string containing alnum, hex, or others ([()+,-.:=@;$_!*']) chars [col %d]" + errNoUrnWithinID = "expecting the identifier to not contain the \"urn\" reserved string [col %d]" + errHex = "expecting the specific string hex chars to be well-formed (%%alnum{2}) [col %d]" + errParse = "parsing error [col %d]" +) + +const start int = 1 +const firstFinal int = 44 + +const enFail int = 46 +const enMain int = 1 + +// Machine is the interface representing the FSM +type Machine interface { + Error() error + Parse(input []byte) (*URN, error) +} + +type machine struct { + data []byte + cs int + p, pe, eof, pb int + err error + tolower []int +} + +// NewMachine creates a new FSM able to parse RFC 2141 strings. +func NewMachine() Machine { + m := &machine{} + + return m +} + +// Err returns the error that occurred on the last call to Parse. +// +// If the result is nil, then the line was parsed successfully. +func (m *machine) Error() error { + return m.err +} + +func (m *machine) text() []byte { + return m.data[m.pb:m.p] +} + +// Parse parses the input byte array as a RFC 2141 string. +func (m *machine) Parse(input []byte) (*URN, error) { + m.data = input + m.p = 0 + m.pb = 0 + m.pe = len(input) + m.eof = len(input) + m.err = nil + m.tolower = []int{} + output := &URN{} + + { + m.cs = start + } + + { + if (m.p) == (m.pe) { + goto _testEof + } + switch m.cs { + case 1: + goto stCase1 + case 0: + goto stCase0 + case 2: + goto stCase2 + case 3: + goto stCase3 + case 4: + goto stCase4 + case 5: + goto stCase5 + case 6: + goto stCase6 + case 7: + goto stCase7 + case 8: + goto stCase8 + case 9: + goto stCase9 + case 10: + goto stCase10 + case 11: + goto stCase11 + case 12: + goto stCase12 + case 13: + goto stCase13 + case 14: + goto stCase14 + case 15: + goto stCase15 + case 16: + goto stCase16 + case 17: + goto stCase17 + case 18: + goto stCase18 + case 19: + goto stCase19 + case 20: + goto stCase20 + case 21: + goto stCase21 + case 22: + goto stCase22 + case 23: + goto stCase23 + case 24: + goto stCase24 + case 25: + goto stCase25 + case 26: + goto stCase26 + case 27: + goto stCase27 + case 28: + goto stCase28 + case 29: + goto stCase29 + case 30: + goto stCase30 + case 31: + goto stCase31 + case 32: + goto stCase32 + case 33: + goto stCase33 + case 34: + goto stCase34 + case 35: + goto stCase35 + case 36: + goto stCase36 + case 37: + goto stCase37 + case 38: + goto stCase38 + case 44: + goto stCase44 + case 39: + goto stCase39 + case 40: + goto stCase40 + case 45: + goto stCase45 + case 41: + goto stCase41 + case 42: + goto stCase42 + case 43: + goto stCase43 + case 46: + goto stCase46 + } + goto stOut + stCase1: + switch (m.data)[(m.p)] { + case 85: + goto tr1 + case 117: + goto tr1 + } + goto tr0 + tr0: + + m.err = fmt.Errorf(errParse, m.p) + (m.p)-- + + { + goto st46 + } + + goto st0 + tr3: + + m.err = fmt.Errorf(errPrefix, m.p) + (m.p)-- + + { + goto st46 + } + + m.err = fmt.Errorf(errParse, m.p) + (m.p)-- + + { + goto st46 + } + + goto st0 + tr6: + + m.err = fmt.Errorf(errIdentifier, m.p) + (m.p)-- + + { + goto st46 + } + + m.err = fmt.Errorf(errParse, m.p) + (m.p)-- + + { + goto st46 + } + + goto st0 + tr41: + + m.err = fmt.Errorf(errSpecificString, m.p) + (m.p)-- + + { + goto st46 + } + + m.err = fmt.Errorf(errParse, m.p) + (m.p)-- + + { + goto st46 + } + + goto st0 + tr44: + + m.err = fmt.Errorf(errHex, m.p) + (m.p)-- + + { + goto st46 + } + + m.err = fmt.Errorf(errSpecificString, m.p) + (m.p)-- + + { + goto st46 + } + + m.err = fmt.Errorf(errParse, m.p) + (m.p)-- + + { + goto st46 + } + + goto st0 + tr50: + + m.err = fmt.Errorf(errPrefix, m.p) + (m.p)-- + + { + goto st46 + } + + m.err = fmt.Errorf(errIdentifier, m.p) + (m.p)-- + + { + goto st46 + } + + m.err = fmt.Errorf(errParse, m.p) + (m.p)-- + + { + goto st46 + } + + goto st0 + tr52: + + m.err = fmt.Errorf(errNoUrnWithinID, m.p) + (m.p)-- + + { + goto st46 + } + + m.err = fmt.Errorf(errIdentifier, m.p) + (m.p)-- + + { + goto st46 + } + + m.err = fmt.Errorf(errParse, m.p) + (m.p)-- + + { + goto st46 + } + + goto st0 + stCase0: + st0: + m.cs = 0 + goto _out + tr1: + + m.pb = m.p + + goto st2 + st2: + if (m.p)++; (m.p) == (m.pe) { + goto _testEof2 + } + stCase2: + switch (m.data)[(m.p)] { + case 82: + goto st3 + case 114: + goto st3 + } + goto tr0 + st3: + if (m.p)++; (m.p) == (m.pe) { + goto _testEof3 + } + stCase3: + switch (m.data)[(m.p)] { + case 78: + goto st4 + case 110: + goto st4 + } + goto tr3 + st4: + if (m.p)++; (m.p) == (m.pe) { + goto _testEof4 + } + stCase4: + if (m.data)[(m.p)] == 58 { + goto tr5 + } + goto tr0 + tr5: + + output.prefix = string(m.text()) + + goto st5 + st5: + if (m.p)++; (m.p) == (m.pe) { + goto _testEof5 + } + stCase5: + switch (m.data)[(m.p)] { + case 85: + goto tr8 + case 117: + goto tr8 + } + switch { + case (m.data)[(m.p)] < 65: + if 48 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 57 { + goto tr7 + } + case (m.data)[(m.p)] > 90: + if 97 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 122 { + goto tr7 + } + default: + goto tr7 + } + goto tr6 + tr7: + + m.pb = m.p + + goto st6 + st6: + if (m.p)++; (m.p) == (m.pe) { + goto _testEof6 + } + stCase6: + switch (m.data)[(m.p)] { + case 45: + goto st7 + case 58: + goto tr10 + } + switch { + case (m.data)[(m.p)] < 65: + if 48 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 57 { + goto st7 + } + case (m.data)[(m.p)] > 90: + if 97 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 122 { + goto st7 + } + default: + goto st7 + } + goto tr6 + st7: + if (m.p)++; (m.p) == (m.pe) { + goto _testEof7 + } + stCase7: + switch (m.data)[(m.p)] { + case 45: + goto st8 + case 58: + goto tr10 + } + switch { + case (m.data)[(m.p)] < 65: + if 48 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 57 { + goto st8 + } + case (m.data)[(m.p)] > 90: + if 97 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 122 { + goto st8 + } + default: + goto st8 + } + goto tr6 + st8: + if (m.p)++; (m.p) == (m.pe) { + goto _testEof8 + } + stCase8: + switch (m.data)[(m.p)] { + case 45: + goto st9 + case 58: + goto tr10 + } + switch { + case (m.data)[(m.p)] < 65: + if 48 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 57 { + goto st9 + } + case (m.data)[(m.p)] > 90: + if 97 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 122 { + goto st9 + } + default: + goto st9 + } + goto tr6 + st9: + if (m.p)++; (m.p) == (m.pe) { + goto _testEof9 + } + stCase9: + switch (m.data)[(m.p)] { + case 45: + goto st10 + case 58: + goto tr10 + } + switch { + case (m.data)[(m.p)] < 65: + if 48 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 57 { + goto st10 + } + case (m.data)[(m.p)] > 90: + if 97 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 122 { + goto st10 + } + default: + goto st10 + } + goto tr6 + st10: + if (m.p)++; (m.p) == (m.pe) { + goto _testEof10 + } + stCase10: + switch (m.data)[(m.p)] { + case 45: + goto st11 + case 58: + goto tr10 + } + switch { + case (m.data)[(m.p)] < 65: + if 48 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 57 { + goto st11 + } + case (m.data)[(m.p)] > 90: + if 97 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 122 { + goto st11 + } + default: + goto st11 + } + goto tr6 + st11: + if (m.p)++; (m.p) == (m.pe) { + goto _testEof11 + } + stCase11: + switch (m.data)[(m.p)] { + case 45: + goto st12 + case 58: + goto tr10 + } + switch { + case (m.data)[(m.p)] < 65: + if 48 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 57 { + goto st12 + } + case (m.data)[(m.p)] > 90: + if 97 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 122 { + goto st12 + } + default: + goto st12 + } + goto tr6 + st12: + if (m.p)++; (m.p) == (m.pe) { + goto _testEof12 + } + stCase12: + switch (m.data)[(m.p)] { + case 45: + goto st13 + case 58: + goto tr10 + } + switch { + case (m.data)[(m.p)] < 65: + if 48 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 57 { + goto st13 + } + case (m.data)[(m.p)] > 90: + if 97 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 122 { + goto st13 + } + default: + goto st13 + } + goto tr6 + st13: + if (m.p)++; (m.p) == (m.pe) { + goto _testEof13 + } + stCase13: + switch (m.data)[(m.p)] { + case 45: + goto st14 + case 58: + goto tr10 + } + switch { + case (m.data)[(m.p)] < 65: + if 48 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 57 { + goto st14 + } + case (m.data)[(m.p)] > 90: + if 97 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 122 { + goto st14 + } + default: + goto st14 + } + goto tr6 + st14: + if (m.p)++; (m.p) == (m.pe) { + goto _testEof14 + } + stCase14: + switch (m.data)[(m.p)] { + case 45: + goto st15 + case 58: + goto tr10 + } + switch { + case (m.data)[(m.p)] < 65: + if 48 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 57 { + goto st15 + } + case (m.data)[(m.p)] > 90: + if 97 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 122 { + goto st15 + } + default: + goto st15 + } + goto tr6 + st15: + if (m.p)++; (m.p) == (m.pe) { + goto _testEof15 + } + stCase15: + switch (m.data)[(m.p)] { + case 45: + goto st16 + case 58: + goto tr10 + } + switch { + case (m.data)[(m.p)] < 65: + if 48 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 57 { + goto st16 + } + case (m.data)[(m.p)] > 90: + if 97 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 122 { + goto st16 + } + default: + goto st16 + } + goto tr6 + st16: + if (m.p)++; (m.p) == (m.pe) { + goto _testEof16 + } + stCase16: + switch (m.data)[(m.p)] { + case 45: + goto st17 + case 58: + goto tr10 + } + switch { + case (m.data)[(m.p)] < 65: + if 48 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 57 { + goto st17 + } + case (m.data)[(m.p)] > 90: + if 97 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 122 { + goto st17 + } + default: + goto st17 + } + goto tr6 + st17: + if (m.p)++; (m.p) == (m.pe) { + goto _testEof17 + } + stCase17: + switch (m.data)[(m.p)] { + case 45: + goto st18 + case 58: + goto tr10 + } + switch { + case (m.data)[(m.p)] < 65: + if 48 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 57 { + goto st18 + } + case (m.data)[(m.p)] > 90: + if 97 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 122 { + goto st18 + } + default: + goto st18 + } + goto tr6 + st18: + if (m.p)++; (m.p) == (m.pe) { + goto _testEof18 + } + stCase18: + switch (m.data)[(m.p)] { + case 45: + goto st19 + case 58: + goto tr10 + } + switch { + case (m.data)[(m.p)] < 65: + if 48 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 57 { + goto st19 + } + case (m.data)[(m.p)] > 90: + if 97 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 122 { + goto st19 + } + default: + goto st19 + } + goto tr6 + st19: + if (m.p)++; (m.p) == (m.pe) { + goto _testEof19 + } + stCase19: + switch (m.data)[(m.p)] { + case 45: + goto st20 + case 58: + goto tr10 + } + switch { + case (m.data)[(m.p)] < 65: + if 48 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 57 { + goto st20 + } + case (m.data)[(m.p)] > 90: + if 97 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 122 { + goto st20 + } + default: + goto st20 + } + goto tr6 + st20: + if (m.p)++; (m.p) == (m.pe) { + goto _testEof20 + } + stCase20: + switch (m.data)[(m.p)] { + case 45: + goto st21 + case 58: + goto tr10 + } + switch { + case (m.data)[(m.p)] < 65: + if 48 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 57 { + goto st21 + } + case (m.data)[(m.p)] > 90: + if 97 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 122 { + goto st21 + } + default: + goto st21 + } + goto tr6 + st21: + if (m.p)++; (m.p) == (m.pe) { + goto _testEof21 + } + stCase21: + switch (m.data)[(m.p)] { + case 45: + goto st22 + case 58: + goto tr10 + } + switch { + case (m.data)[(m.p)] < 65: + if 48 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 57 { + goto st22 + } + case (m.data)[(m.p)] > 90: + if 97 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 122 { + goto st22 + } + default: + goto st22 + } + goto tr6 + st22: + if (m.p)++; (m.p) == (m.pe) { + goto _testEof22 + } + stCase22: + switch (m.data)[(m.p)] { + case 45: + goto st23 + case 58: + goto tr10 + } + switch { + case (m.data)[(m.p)] < 65: + if 48 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 57 { + goto st23 + } + case (m.data)[(m.p)] > 90: + if 97 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 122 { + goto st23 + } + default: + goto st23 + } + goto tr6 + st23: + if (m.p)++; (m.p) == (m.pe) { + goto _testEof23 + } + stCase23: + switch (m.data)[(m.p)] { + case 45: + goto st24 + case 58: + goto tr10 + } + switch { + case (m.data)[(m.p)] < 65: + if 48 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 57 { + goto st24 + } + case (m.data)[(m.p)] > 90: + if 97 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 122 { + goto st24 + } + default: + goto st24 + } + goto tr6 + st24: + if (m.p)++; (m.p) == (m.pe) { + goto _testEof24 + } + stCase24: + switch (m.data)[(m.p)] { + case 45: + goto st25 + case 58: + goto tr10 + } + switch { + case (m.data)[(m.p)] < 65: + if 48 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 57 { + goto st25 + } + case (m.data)[(m.p)] > 90: + if 97 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 122 { + goto st25 + } + default: + goto st25 + } + goto tr6 + st25: + if (m.p)++; (m.p) == (m.pe) { + goto _testEof25 + } + stCase25: + switch (m.data)[(m.p)] { + case 45: + goto st26 + case 58: + goto tr10 + } + switch { + case (m.data)[(m.p)] < 65: + if 48 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 57 { + goto st26 + } + case (m.data)[(m.p)] > 90: + if 97 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 122 { + goto st26 + } + default: + goto st26 + } + goto tr6 + st26: + if (m.p)++; (m.p) == (m.pe) { + goto _testEof26 + } + stCase26: + switch (m.data)[(m.p)] { + case 45: + goto st27 + case 58: + goto tr10 + } + switch { + case (m.data)[(m.p)] < 65: + if 48 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 57 { + goto st27 + } + case (m.data)[(m.p)] > 90: + if 97 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 122 { + goto st27 + } + default: + goto st27 + } + goto tr6 + st27: + if (m.p)++; (m.p) == (m.pe) { + goto _testEof27 + } + stCase27: + switch (m.data)[(m.p)] { + case 45: + goto st28 + case 58: + goto tr10 + } + switch { + case (m.data)[(m.p)] < 65: + if 48 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 57 { + goto st28 + } + case (m.data)[(m.p)] > 90: + if 97 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 122 { + goto st28 + } + default: + goto st28 + } + goto tr6 + st28: + if (m.p)++; (m.p) == (m.pe) { + goto _testEof28 + } + stCase28: + switch (m.data)[(m.p)] { + case 45: + goto st29 + case 58: + goto tr10 + } + switch { + case (m.data)[(m.p)] < 65: + if 48 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 57 { + goto st29 + } + case (m.data)[(m.p)] > 90: + if 97 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 122 { + goto st29 + } + default: + goto st29 + } + goto tr6 + st29: + if (m.p)++; (m.p) == (m.pe) { + goto _testEof29 + } + stCase29: + switch (m.data)[(m.p)] { + case 45: + goto st30 + case 58: + goto tr10 + } + switch { + case (m.data)[(m.p)] < 65: + if 48 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 57 { + goto st30 + } + case (m.data)[(m.p)] > 90: + if 97 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 122 { + goto st30 + } + default: + goto st30 + } + goto tr6 + st30: + if (m.p)++; (m.p) == (m.pe) { + goto _testEof30 + } + stCase30: + switch (m.data)[(m.p)] { + case 45: + goto st31 + case 58: + goto tr10 + } + switch { + case (m.data)[(m.p)] < 65: + if 48 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 57 { + goto st31 + } + case (m.data)[(m.p)] > 90: + if 97 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 122 { + goto st31 + } + default: + goto st31 + } + goto tr6 + st31: + if (m.p)++; (m.p) == (m.pe) { + goto _testEof31 + } + stCase31: + switch (m.data)[(m.p)] { + case 45: + goto st32 + case 58: + goto tr10 + } + switch { + case (m.data)[(m.p)] < 65: + if 48 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 57 { + goto st32 + } + case (m.data)[(m.p)] > 90: + if 97 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 122 { + goto st32 + } + default: + goto st32 + } + goto tr6 + st32: + if (m.p)++; (m.p) == (m.pe) { + goto _testEof32 + } + stCase32: + switch (m.data)[(m.p)] { + case 45: + goto st33 + case 58: + goto tr10 + } + switch { + case (m.data)[(m.p)] < 65: + if 48 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 57 { + goto st33 + } + case (m.data)[(m.p)] > 90: + if 97 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 122 { + goto st33 + } + default: + goto st33 + } + goto tr6 + st33: + if (m.p)++; (m.p) == (m.pe) { + goto _testEof33 + } + stCase33: + switch (m.data)[(m.p)] { + case 45: + goto st34 + case 58: + goto tr10 + } + switch { + case (m.data)[(m.p)] < 65: + if 48 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 57 { + goto st34 + } + case (m.data)[(m.p)] > 90: + if 97 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 122 { + goto st34 + } + default: + goto st34 + } + goto tr6 + st34: + if (m.p)++; (m.p) == (m.pe) { + goto _testEof34 + } + stCase34: + switch (m.data)[(m.p)] { + case 45: + goto st35 + case 58: + goto tr10 + } + switch { + case (m.data)[(m.p)] < 65: + if 48 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 57 { + goto st35 + } + case (m.data)[(m.p)] > 90: + if 97 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 122 { + goto st35 + } + default: + goto st35 + } + goto tr6 + st35: + if (m.p)++; (m.p) == (m.pe) { + goto _testEof35 + } + stCase35: + switch (m.data)[(m.p)] { + case 45: + goto st36 + case 58: + goto tr10 + } + switch { + case (m.data)[(m.p)] < 65: + if 48 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 57 { + goto st36 + } + case (m.data)[(m.p)] > 90: + if 97 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 122 { + goto st36 + } + default: + goto st36 + } + goto tr6 + st36: + if (m.p)++; (m.p) == (m.pe) { + goto _testEof36 + } + stCase36: + switch (m.data)[(m.p)] { + case 45: + goto st37 + case 58: + goto tr10 + } + switch { + case (m.data)[(m.p)] < 65: + if 48 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 57 { + goto st37 + } + case (m.data)[(m.p)] > 90: + if 97 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 122 { + goto st37 + } + default: + goto st37 + } + goto tr6 + st37: + if (m.p)++; (m.p) == (m.pe) { + goto _testEof37 + } + stCase37: + if (m.data)[(m.p)] == 58 { + goto tr10 + } + goto tr6 + tr10: + + output.ID = string(m.text()) + + goto st38 + st38: + if (m.p)++; (m.p) == (m.pe) { + goto _testEof38 + } + stCase38: + switch (m.data)[(m.p)] { + case 33: + goto tr42 + case 36: + goto tr42 + case 37: + goto tr43 + case 61: + goto tr42 + case 95: + goto tr42 + } + switch { + case (m.data)[(m.p)] < 48: + if 39 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 46 { + goto tr42 + } + case (m.data)[(m.p)] > 59: + switch { + case (m.data)[(m.p)] > 90: + if 97 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 122 { + goto tr42 + } + case (m.data)[(m.p)] >= 64: + goto tr42 + } + default: + goto tr42 + } + goto tr41 + tr42: + + m.pb = m.p + + goto st44 + st44: + if (m.p)++; (m.p) == (m.pe) { + goto _testEof44 + } + stCase44: + switch (m.data)[(m.p)] { + case 33: + goto st44 + case 36: + goto st44 + case 37: + goto st39 + case 61: + goto st44 + case 95: + goto st44 + } + switch { + case (m.data)[(m.p)] < 48: + if 39 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 46 { + goto st44 + } + case (m.data)[(m.p)] > 59: + switch { + case (m.data)[(m.p)] > 90: + if 97 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 122 { + goto st44 + } + case (m.data)[(m.p)] >= 64: + goto st44 + } + default: + goto st44 + } + goto tr41 + tr43: + + m.pb = m.p + + goto st39 + st39: + if (m.p)++; (m.p) == (m.pe) { + goto _testEof39 + } + stCase39: + switch { + case (m.data)[(m.p)] < 65: + if 48 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 57 { + goto st40 + } + case (m.data)[(m.p)] > 90: + if 97 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 122 { + goto st40 + } + default: + goto tr46 + } + goto tr44 + tr46: + + m.tolower = append(m.tolower, m.p-m.pb) + + goto st40 + st40: + if (m.p)++; (m.p) == (m.pe) { + goto _testEof40 + } + stCase40: + switch { + case (m.data)[(m.p)] < 65: + if 48 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 57 { + goto st45 + } + case (m.data)[(m.p)] > 90: + if 97 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 122 { + goto st45 + } + default: + goto tr48 + } + goto tr44 + tr48: + + m.tolower = append(m.tolower, m.p-m.pb) + + goto st45 + st45: + if (m.p)++; (m.p) == (m.pe) { + goto _testEof45 + } + stCase45: + switch (m.data)[(m.p)] { + case 33: + goto st44 + case 36: + goto st44 + case 37: + goto st39 + case 61: + goto st44 + case 95: + goto st44 + } + switch { + case (m.data)[(m.p)] < 48: + if 39 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 46 { + goto st44 + } + case (m.data)[(m.p)] > 59: + switch { + case (m.data)[(m.p)] > 90: + if 97 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 122 { + goto st44 + } + case (m.data)[(m.p)] >= 64: + goto st44 + } + default: + goto st44 + } + goto tr44 + tr8: + + m.pb = m.p + + goto st41 + st41: + if (m.p)++; (m.p) == (m.pe) { + goto _testEof41 + } + stCase41: + switch (m.data)[(m.p)] { + case 45: + goto st7 + case 58: + goto tr10 + case 82: + goto st42 + case 114: + goto st42 + } + switch { + case (m.data)[(m.p)] < 65: + if 48 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 57 { + goto st7 + } + case (m.data)[(m.p)] > 90: + if 97 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 122 { + goto st7 + } + default: + goto st7 + } + goto tr6 + st42: + if (m.p)++; (m.p) == (m.pe) { + goto _testEof42 + } + stCase42: + switch (m.data)[(m.p)] { + case 45: + goto st8 + case 58: + goto tr10 + case 78: + goto st43 + case 110: + goto st43 + } + switch { + case (m.data)[(m.p)] < 65: + if 48 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 57 { + goto st8 + } + case (m.data)[(m.p)] > 90: + if 97 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 122 { + goto st8 + } + default: + goto st8 + } + goto tr50 + st43: + if (m.p)++; (m.p) == (m.pe) { + goto _testEof43 + } + stCase43: + if (m.data)[(m.p)] == 45 { + goto st9 + } + switch { + case (m.data)[(m.p)] < 65: + if 48 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 57 { + goto st9 + } + case (m.data)[(m.p)] > 90: + if 97 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 122 { + goto st9 + } + default: + goto st9 + } + goto tr52 + st46: + if (m.p)++; (m.p) == (m.pe) { + goto _testEof46 + } + stCase46: + switch (m.data)[(m.p)] { + case 10: + goto st0 + case 13: + goto st0 + } + goto st46 + stOut: + _testEof2: + m.cs = 2 + goto _testEof + _testEof3: + m.cs = 3 + goto _testEof + _testEof4: + m.cs = 4 + goto _testEof + _testEof5: + m.cs = 5 + goto _testEof + _testEof6: + m.cs = 6 + goto _testEof + _testEof7: + m.cs = 7 + goto _testEof + _testEof8: + m.cs = 8 + goto _testEof + _testEof9: + m.cs = 9 + goto _testEof + _testEof10: + m.cs = 10 + goto _testEof + _testEof11: + m.cs = 11 + goto _testEof + _testEof12: + m.cs = 12 + goto _testEof + _testEof13: + m.cs = 13 + goto _testEof + _testEof14: + m.cs = 14 + goto _testEof + _testEof15: + m.cs = 15 + goto _testEof + _testEof16: + m.cs = 16 + goto _testEof + _testEof17: + m.cs = 17 + goto _testEof + _testEof18: + m.cs = 18 + goto _testEof + _testEof19: + m.cs = 19 + goto _testEof + _testEof20: + m.cs = 20 + goto _testEof + _testEof21: + m.cs = 21 + goto _testEof + _testEof22: + m.cs = 22 + goto _testEof + _testEof23: + m.cs = 23 + goto _testEof + _testEof24: + m.cs = 24 + goto _testEof + _testEof25: + m.cs = 25 + goto _testEof + _testEof26: + m.cs = 26 + goto _testEof + _testEof27: + m.cs = 27 + goto _testEof + _testEof28: + m.cs = 28 + goto _testEof + _testEof29: + m.cs = 29 + goto _testEof + _testEof30: + m.cs = 30 + goto _testEof + _testEof31: + m.cs = 31 + goto _testEof + _testEof32: + m.cs = 32 + goto _testEof + _testEof33: + m.cs = 33 + goto _testEof + _testEof34: + m.cs = 34 + goto _testEof + _testEof35: + m.cs = 35 + goto _testEof + _testEof36: + m.cs = 36 + goto _testEof + _testEof37: + m.cs = 37 + goto _testEof + _testEof38: + m.cs = 38 + goto _testEof + _testEof44: + m.cs = 44 + goto _testEof + _testEof39: + m.cs = 39 + goto _testEof + _testEof40: + m.cs = 40 + goto _testEof + _testEof45: + m.cs = 45 + goto _testEof + _testEof41: + m.cs = 41 + goto _testEof + _testEof42: + m.cs = 42 + goto _testEof + _testEof43: + m.cs = 43 + goto _testEof + _testEof46: + m.cs = 46 + goto _testEof + + _testEof: + { + } + if (m.p) == (m.eof) { + switch m.cs { + case 44, 45: + + raw := m.text() + output.SS = string(raw) + // Iterate upper letters lowering them + for _, i := range m.tolower { + raw[i] = raw[i] + 32 + } + output.norm = string(raw) + + case 1, 2, 4: + + m.err = fmt.Errorf(errParse, m.p) + (m.p)-- + + { + goto st46 + } + + case 3: + + m.err = fmt.Errorf(errPrefix, m.p) + (m.p)-- + + { + goto st46 + } + + m.err = fmt.Errorf(errParse, m.p) + (m.p)-- + + { + goto st46 + } + + case 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 41: + + m.err = fmt.Errorf(errIdentifier, m.p) + (m.p)-- + + { + goto st46 + } + + m.err = fmt.Errorf(errParse, m.p) + (m.p)-- + + { + goto st46 + } + + case 38: + + m.err = fmt.Errorf(errSpecificString, m.p) + (m.p)-- + + { + goto st46 + } + + m.err = fmt.Errorf(errParse, m.p) + (m.p)-- + + { + goto st46 + } + + case 42: + + m.err = fmt.Errorf(errPrefix, m.p) + (m.p)-- + + { + goto st46 + } + + m.err = fmt.Errorf(errIdentifier, m.p) + (m.p)-- + + { + goto st46 + } + + m.err = fmt.Errorf(errParse, m.p) + (m.p)-- + + { + goto st46 + } + + case 43: + + m.err = fmt.Errorf(errNoUrnWithinID, m.p) + (m.p)-- + + { + goto st46 + } + + m.err = fmt.Errorf(errIdentifier, m.p) + (m.p)-- + + { + goto st46 + } + + m.err = fmt.Errorf(errParse, m.p) + (m.p)-- + + { + goto st46 + } + + case 39, 40: + + m.err = fmt.Errorf(errHex, m.p) + (m.p)-- + + { + goto st46 + } + + m.err = fmt.Errorf(errSpecificString, m.p) + (m.p)-- + + { + goto st46 + } + + m.err = fmt.Errorf(errParse, m.p) + (m.p)-- + + { + goto st46 + } + + } + } + + _out: + { + } + } + + if m.cs < firstFinal || m.cs == enFail { + return nil, m.err + } + + return output, nil +} diff --git a/vendor/github.com/leodido/go-urn/machine.go.rl b/vendor/github.com/leodido/go-urn/machine.go.rl new file mode 100644 index 0000000000..3bc05a651a --- /dev/null +++ b/vendor/github.com/leodido/go-urn/machine.go.rl @@ -0,0 +1,159 @@ +package urn + +import ( + "fmt" +) + +var ( + errPrefix = "expecting the prefix to be the \"urn\" string (whatever case) [col %d]" + errIdentifier = "expecting the identifier to be string (1..31 alnum chars, also containing dashes but not at its start) [col %d]" + errSpecificString = "expecting the specific string to be a string containing alnum, hex, or others ([()+,-.:=@;$_!*']) chars [col %d]" + errNoUrnWithinID = "expecting the identifier to not contain the \"urn\" reserved string [col %d]" + errHex = "expecting the specific string hex chars to be well-formed (%%alnum{2}) [col %d]" + errParse = "parsing error [col %d]" +) + +%%{ +machine urn; + +# unsigned alphabet +alphtype uint8; + +action mark { + m.pb = m.p +} + +action tolower { + m.tolower = append(m.tolower, m.p - m.pb) +} + +action set_pre { + output.prefix = string(m.text()) +} + +action set_nid { + output.ID = string(m.text()) +} + +action set_nss { + raw := m.text() + output.SS = string(raw) + // Iterate upper letters lowering them + for _, i := range m.tolower { + raw[i] = raw[i] + 32 + } + output.norm = string(raw) +} + +action err_pre { + m.err = fmt.Errorf(errPrefix, m.p) + fhold; + fgoto fail; +} + +action err_nid { + m.err = fmt.Errorf(errIdentifier, m.p) + fhold; + fgoto fail; +} + +action err_nss { + m.err = fmt.Errorf(errSpecificString, m.p) + fhold; + fgoto fail; +} + +action err_urn { + m.err = fmt.Errorf(errNoUrnWithinID, m.p) + fhold; + fgoto fail; +} + +action err_hex { + m.err = fmt.Errorf(errHex, m.p) + fhold; + fgoto fail; +} + +action err_parse { + m.err = fmt.Errorf(errParse, m.p) + fhold; + fgoto fail; +} + +pre = ([uU][rR][nN] @err(err_pre)) >mark %set_pre; + +nid = (alnum >mark (alnum | '-'){0,31}) %set_nid; + +hex = '%' (digit | lower | upper >tolower){2} $err(err_hex); + +sss = (alnum | [()+,\-.:=@;$_!*']); + +nss = (sss | hex)+ $err(err_nss); + +fail := (any - [\n\r])* @err{ fgoto main; }; + +main := (pre ':' (nid - pre %err(err_urn)) $err(err_nid) ':' nss >mark %set_nss) $err(err_parse); + +}%% + +%% write data noerror noprefix; + +// Machine is the interface representing the FSM +type Machine interface { + Error() error + Parse(input []byte) (*URN, error) +} + +type machine struct { + data []byte + cs int + p, pe, eof, pb int + err error + tolower []int +} + +// NewMachine creates a new FSM able to parse RFC 2141 strings. +func NewMachine() Machine { + m := &machine{} + + %% access m.; + %% variable p m.p; + %% variable pe m.pe; + %% variable eof m.eof; + %% variable data m.data; + + return m +} + +// Err returns the error that occurred on the last call to Parse. +// +// If the result is nil, then the line was parsed successfully. +func (m *machine) Error() error { + return m.err +} + +func (m *machine) text() []byte { + return m.data[m.pb:m.p] +} + +// Parse parses the input byte array as a RFC 2141 string. +func (m *machine) Parse(input []byte) (*URN, error) { + m.data = input + m.p = 0 + m.pb = 0 + m.pe = len(input) + m.eof = len(input) + m.err = nil + m.tolower = []int{} + output := &URN{} + + %% write init; + %% write exec; + + if m.cs < first_final || m.cs == en_fail { + return nil, m.err + } + + return output, nil +} diff --git a/vendor/github.com/leodido/go-urn/makefile b/vendor/github.com/leodido/go-urn/makefile new file mode 100644 index 0000000000..47026d5099 --- /dev/null +++ b/vendor/github.com/leodido/go-urn/makefile @@ -0,0 +1,39 @@ +SHELL := /bin/bash + +build: machine.go + +images: docs/urn.png + +machine.go: machine.go.rl + ragel -Z -G2 -e -o $@ $< + @sed -i '/^\/\/line/d' $@ + @$(MAKE) -s file=$@ snake2camel + @gofmt -w -s $@ + +docs/urn.dot: machine.go.rl + @mkdir -p docs + ragel -Z -e -Vp $< -o $@ + +docs/urn.png: docs/urn.dot + dot $< -Tpng -o $@ + +.PHONY: bench +bench: *_test.go machine.go + go test -bench=. -benchmem -benchtime=5s ./... + +.PHONY: tests +tests: *_test.go machine.go + go test -race -timeout 10s -coverprofile=coverage.out -covermode=atomic -v ./... + +.PHONY: clean +clean: + @rm -rf docs + @rm -f machine.go + +.PHONY: snake2camel +snake2camel: + @awk -i inplace '{ \ + while ( match($$0, /(.*)([a-z]+[0-9]*)_([a-zA-Z0-9])(.*)/, cap) ) \ + $$0 = cap[1] cap[2] toupper(cap[3]) cap[4]; \ + print \ + }' $(file) \ No newline at end of file diff --git a/vendor/github.com/leodido/go-urn/urn.go b/vendor/github.com/leodido/go-urn/urn.go new file mode 100644 index 0000000000..d51a6c915b --- /dev/null +++ b/vendor/github.com/leodido/go-urn/urn.go @@ -0,0 +1,86 @@ +package urn + +import ( + "encoding/json" + "fmt" + "strings" +) + +const errInvalidURN = "invalid URN: %s" + +// URN represents an Uniform Resource Name. +// +// The general form represented is: +// +// urn:: +// +// Details at https://tools.ietf.org/html/rfc2141. +type URN struct { + prefix string // Static prefix. Equal to "urn" when empty. + ID string // Namespace identifier + SS string // Namespace specific string + norm string // Normalized namespace specific string +} + +// Normalize turns the receiving URN into its norm version. +// +// Which means: lowercase prefix, lowercase namespace identifier, and immutate namespace specific string chars (except tokens which are lowercased). +func (u *URN) Normalize() *URN { + return &URN{ + prefix: "urn", + ID: strings.ToLower(u.ID), + SS: u.norm, + } +} + +// Equal checks the lexical equivalence of the current URN with another one. +func (u *URN) Equal(x *URN) bool { + return *u.Normalize() == *x.Normalize() +} + +// String reassembles the URN into a valid URN string. +// +// This requires both ID and SS fields to be non-empty. +// Otherwise it returns an empty string. +// +// Default URN prefix is "urn". +func (u *URN) String() string { + var res string + if u.ID != "" && u.SS != "" { + if u.prefix == "" { + res += "urn" + } + res += u.prefix + ":" + u.ID + ":" + u.SS + } + + return res +} + +// Parse is responsible to create an URN instance from a byte array matching the correct URN syntax. +func Parse(u []byte) (*URN, bool) { + urn, err := NewMachine().Parse(u) + if err != nil { + return nil, false + } + + return urn, true +} + +// MarshalJSON marshals the URN to JSON string form (e.g. `"urn:oid:1.2.3.4"`). +func (u URN) MarshalJSON() ([]byte, error) { + return json.Marshal(u.String()) +} + +// MarshalJSON unmarshals a URN from JSON string form (e.g. `"urn:oid:1.2.3.4"`). +func (u *URN) UnmarshalJSON(bytes []byte) error { + var str string + if err := json.Unmarshal(bytes, &str); err != nil { + return err + } + if value, ok := Parse([]byte(str)); !ok { + return fmt.Errorf(errInvalidURN, str) + } else { + *u = *value + } + return nil +} \ No newline at end of file diff --git a/vendor/github.com/opencontainers/image-spec/LICENSE b/vendor/github.com/opencontainers/image-spec/LICENSE new file mode 100644 index 0000000000..9fdc20fdb6 --- /dev/null +++ b/vendor/github.com/opencontainers/image-spec/LICENSE @@ -0,0 +1,191 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + Copyright 2016 The Linux Foundation. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/opencontainers/image-spec/specs-go/v1/annotations.go b/vendor/github.com/opencontainers/image-spec/specs-go/v1/annotations.go new file mode 100644 index 0000000000..581cf7cdfa --- /dev/null +++ b/vendor/github.com/opencontainers/image-spec/specs-go/v1/annotations.go @@ -0,0 +1,62 @@ +// Copyright 2016 The Linux Foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package v1 + +const ( + // AnnotationCreated is the annotation key for the date and time on which the image was built (date-time string as defined by RFC 3339). + AnnotationCreated = "org.opencontainers.image.created" + + // AnnotationAuthors is the annotation key for the contact details of the people or organization responsible for the image (freeform string). + AnnotationAuthors = "org.opencontainers.image.authors" + + // AnnotationURL is the annotation key for the URL to find more information on the image. + AnnotationURL = "org.opencontainers.image.url" + + // AnnotationDocumentation is the annotation key for the URL to get documentation on the image. + AnnotationDocumentation = "org.opencontainers.image.documentation" + + // AnnotationSource is the annotation key for the URL to get source code for building the image. + AnnotationSource = "org.opencontainers.image.source" + + // AnnotationVersion is the annotation key for the version of the packaged software. + // The version MAY match a label or tag in the source code repository. + // The version MAY be Semantic versioning-compatible. + AnnotationVersion = "org.opencontainers.image.version" + + // AnnotationRevision is the annotation key for the source control revision identifier for the packaged software. + AnnotationRevision = "org.opencontainers.image.revision" + + // AnnotationVendor is the annotation key for the name of the distributing entity, organization or individual. + AnnotationVendor = "org.opencontainers.image.vendor" + + // AnnotationLicenses is the annotation key for the license(s) under which contained software is distributed as an SPDX License Expression. + AnnotationLicenses = "org.opencontainers.image.licenses" + + // AnnotationRefName is the annotation key for the name of the reference for a target. + // SHOULD only be considered valid when on descriptors on `index.json` within image layout. + AnnotationRefName = "org.opencontainers.image.ref.name" + + // AnnotationTitle is the annotation key for the human-readable title of the image. + AnnotationTitle = "org.opencontainers.image.title" + + // AnnotationDescription is the annotation key for the human-readable description of the software packaged in the image. + AnnotationDescription = "org.opencontainers.image.description" + + // AnnotationBaseImageDigest is the annotation key for the digest of the image's base image. + AnnotationBaseImageDigest = "org.opencontainers.image.base.digest" + + // AnnotationBaseImageName is the annotation key for the image reference of the image's base image. + AnnotationBaseImageName = "org.opencontainers.image.base.name" +) diff --git a/vendor/github.com/opencontainers/image-spec/specs-go/v1/config.go b/vendor/github.com/opencontainers/image-spec/specs-go/v1/config.go new file mode 100644 index 0000000000..ffff4b6d18 --- /dev/null +++ b/vendor/github.com/opencontainers/image-spec/specs-go/v1/config.go @@ -0,0 +1,114 @@ +// Copyright 2016 The Linux Foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package v1 + +import ( + "time" + + digest "github.com/opencontainers/go-digest" +) + +// ImageConfig defines the execution parameters which should be used as a base when running a container using an image. +type ImageConfig struct { + // User defines the username or UID which the process in the container should run as. + User string `json:"User,omitempty"` + + // ExposedPorts a set of ports to expose from a container running this image. + ExposedPorts map[string]struct{} `json:"ExposedPorts,omitempty"` + + // Env is a list of environment variables to be used in a container. + Env []string `json:"Env,omitempty"` + + // Entrypoint defines a list of arguments to use as the command to execute when the container starts. + Entrypoint []string `json:"Entrypoint,omitempty"` + + // Cmd defines the default arguments to the entrypoint of the container. + Cmd []string `json:"Cmd,omitempty"` + + // Volumes is a set of directories describing where the process is likely write data specific to a container instance. + Volumes map[string]struct{} `json:"Volumes,omitempty"` + + // WorkingDir sets the current working directory of the entrypoint process in the container. + WorkingDir string `json:"WorkingDir,omitempty"` + + // Labels contains arbitrary metadata for the container. + Labels map[string]string `json:"Labels,omitempty"` + + // StopSignal contains the system call signal that will be sent to the container to exit. + StopSignal string `json:"StopSignal,omitempty"` +} + +// RootFS describes a layer content addresses +type RootFS struct { + // Type is the type of the rootfs. + Type string `json:"type"` + + // DiffIDs is an array of layer content hashes (DiffIDs), in order from bottom-most to top-most. + DiffIDs []digest.Digest `json:"diff_ids"` +} + +// History describes the history of a layer. +type History struct { + // Created is the combined date and time at which the layer was created, formatted as defined by RFC 3339, section 5.6. + Created *time.Time `json:"created,omitempty"` + + // CreatedBy is the command which created the layer. + CreatedBy string `json:"created_by,omitempty"` + + // Author is the author of the build point. + Author string `json:"author,omitempty"` + + // Comment is a custom message set when creating the layer. + Comment string `json:"comment,omitempty"` + + // EmptyLayer is used to mark if the history item created a filesystem diff. + EmptyLayer bool `json:"empty_layer,omitempty"` +} + +// Image is the JSON structure which describes some basic information about the image. +// This provides the `application/vnd.oci.image.config.v1+json` mediatype when marshalled to JSON. +type Image struct { + // Created is the combined date and time at which the image was created, formatted as defined by RFC 3339, section 5.6. + Created *time.Time `json:"created,omitempty"` + + // Author defines the name and/or email address of the person or entity which created and is responsible for maintaining the image. + Author string `json:"author,omitempty"` + + // Architecture is the CPU architecture which the binaries in this image are built to run on. + Architecture string `json:"architecture"` + + // Variant is the variant of the specified CPU architecture which image binaries are intended to run on. + Variant string `json:"variant,omitempty"` + + // OS is the name of the operating system which the image is built to run on. + OS string `json:"os"` + + // OSVersion is an optional field specifying the operating system + // version, for example on Windows `10.0.14393.1066`. + OSVersion string `json:"os.version,omitempty"` + + // OSFeatures is an optional field specifying an array of strings, + // each listing a required OS feature (for example on Windows `win32k`). + OSFeatures []string `json:"os.features,omitempty"` + + // Config defines the execution parameters which should be used as a base when running a container using the image. + Config ImageConfig `json:"config,omitempty"` + + // RootFS references the layer content addresses used by the image. + RootFS RootFS `json:"rootfs"` + + // History describes the history of each layer. + History []History `json:"history,omitempty"` +} diff --git a/vendor/github.com/opencontainers/image-spec/specs-go/v1/descriptor.go b/vendor/github.com/opencontainers/image-spec/specs-go/v1/descriptor.go new file mode 100644 index 0000000000..6e442a0853 --- /dev/null +++ b/vendor/github.com/opencontainers/image-spec/specs-go/v1/descriptor.go @@ -0,0 +1,64 @@ +// Copyright 2016 The Linux Foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package v1 + +import digest "github.com/opencontainers/go-digest" + +// Descriptor describes the disposition of targeted content. +// This structure provides `application/vnd.oci.descriptor.v1+json` mediatype +// when marshalled to JSON. +type Descriptor struct { + // MediaType is the media type of the object this schema refers to. + MediaType string `json:"mediaType,omitempty"` + + // Digest is the digest of the targeted content. + Digest digest.Digest `json:"digest"` + + // Size specifies the size in bytes of the blob. + Size int64 `json:"size"` + + // URLs specifies a list of URLs from which this object MAY be downloaded + URLs []string `json:"urls,omitempty"` + + // Annotations contains arbitrary metadata relating to the targeted content. + Annotations map[string]string `json:"annotations,omitempty"` + + // Platform describes the platform which the image in the manifest runs on. + // + // This should only be used when referring to a manifest. + Platform *Platform `json:"platform,omitempty"` +} + +// Platform describes the platform which the image in the manifest runs on. +type Platform struct { + // Architecture field specifies the CPU architecture, for example + // `amd64` or `ppc64`. + Architecture string `json:"architecture"` + + // OS specifies the operating system, for example `linux` or `windows`. + OS string `json:"os"` + + // OSVersion is an optional field specifying the operating system + // version, for example on Windows `10.0.14393.1066`. + OSVersion string `json:"os.version,omitempty"` + + // OSFeatures is an optional field specifying an array of strings, + // each listing a required OS feature (for example on Windows `win32k`). + OSFeatures []string `json:"os.features,omitempty"` + + // Variant is an optional field specifying a variant of the CPU, for + // example `v7` to specify ARMv7 when architecture is `arm`. + Variant string `json:"variant,omitempty"` +} diff --git a/vendor/github.com/opencontainers/image-spec/specs-go/v1/index.go b/vendor/github.com/opencontainers/image-spec/specs-go/v1/index.go new file mode 100644 index 0000000000..ed4a56e59e --- /dev/null +++ b/vendor/github.com/opencontainers/image-spec/specs-go/v1/index.go @@ -0,0 +1,32 @@ +// Copyright 2016 The Linux Foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package v1 + +import "github.com/opencontainers/image-spec/specs-go" + +// Index references manifests for various platforms. +// This structure provides `application/vnd.oci.image.index.v1+json` mediatype when marshalled to JSON. +type Index struct { + specs.Versioned + + // MediaType specifies the type of this document data structure e.g. `application/vnd.oci.image.index.v1+json` + MediaType string `json:"mediaType,omitempty"` + + // Manifests references platform specific manifests. + Manifests []Descriptor `json:"manifests"` + + // Annotations contains arbitrary metadata for the image index. + Annotations map[string]string `json:"annotations,omitempty"` +} diff --git a/vendor/github.com/opencontainers/image-spec/specs-go/v1/layout.go b/vendor/github.com/opencontainers/image-spec/specs-go/v1/layout.go new file mode 100644 index 0000000000..fc79e9e0d1 --- /dev/null +++ b/vendor/github.com/opencontainers/image-spec/specs-go/v1/layout.go @@ -0,0 +1,28 @@ +// Copyright 2016 The Linux Foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package v1 + +const ( + // ImageLayoutFile is the file name of oci image layout file + ImageLayoutFile = "oci-layout" + // ImageLayoutVersion is the version of ImageLayout + ImageLayoutVersion = "1.0.0" +) + +// ImageLayout is the structure in the "oci-layout" file, found in the root +// of an OCI Image-layout directory. +type ImageLayout struct { + Version string `json:"imageLayoutVersion"` +} diff --git a/vendor/github.com/opencontainers/image-spec/specs-go/v1/manifest.go b/vendor/github.com/opencontainers/image-spec/specs-go/v1/manifest.go new file mode 100644 index 0000000000..8212d520c0 --- /dev/null +++ b/vendor/github.com/opencontainers/image-spec/specs-go/v1/manifest.go @@ -0,0 +1,35 @@ +// Copyright 2016 The Linux Foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package v1 + +import "github.com/opencontainers/image-spec/specs-go" + +// Manifest provides `application/vnd.oci.image.manifest.v1+json` mediatype structure when marshalled to JSON. +type Manifest struct { + specs.Versioned + + // MediaType specifies the type of this document data structure e.g. `application/vnd.oci.image.manifest.v1+json` + MediaType string `json:"mediaType,omitempty"` + + // Config references a configuration object for a container, by digest. + // The referenced configuration object is a JSON blob that the runtime uses to set up the container. + Config Descriptor `json:"config"` + + // Layers is an indexed list of layers referenced by the manifest. + Layers []Descriptor `json:"layers"` + + // Annotations contains arbitrary metadata for the image manifest. + Annotations map[string]string `json:"annotations,omitempty"` +} diff --git a/vendor/github.com/opencontainers/image-spec/specs-go/v1/mediatype.go b/vendor/github.com/opencontainers/image-spec/specs-go/v1/mediatype.go new file mode 100644 index 0000000000..4f35ac134f --- /dev/null +++ b/vendor/github.com/opencontainers/image-spec/specs-go/v1/mediatype.go @@ -0,0 +1,57 @@ +// Copyright 2016 The Linux Foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package v1 + +const ( + // MediaTypeDescriptor specifies the media type for a content descriptor. + MediaTypeDescriptor = "application/vnd.oci.descriptor.v1+json" + + // MediaTypeLayoutHeader specifies the media type for the oci-layout. + MediaTypeLayoutHeader = "application/vnd.oci.layout.header.v1+json" + + // MediaTypeImageManifest specifies the media type for an image manifest. + MediaTypeImageManifest = "application/vnd.oci.image.manifest.v1+json" + + // MediaTypeImageIndex specifies the media type for an image index. + MediaTypeImageIndex = "application/vnd.oci.image.index.v1+json" + + // MediaTypeImageLayer is the media type used for layers referenced by the manifest. + MediaTypeImageLayer = "application/vnd.oci.image.layer.v1.tar" + + // MediaTypeImageLayerGzip is the media type used for gzipped layers + // referenced by the manifest. + MediaTypeImageLayerGzip = "application/vnd.oci.image.layer.v1.tar+gzip" + + // MediaTypeImageLayerZstd is the media type used for zstd compressed + // layers referenced by the manifest. + MediaTypeImageLayerZstd = "application/vnd.oci.image.layer.v1.tar+zstd" + + // MediaTypeImageLayerNonDistributable is the media type for layers referenced by + // the manifest but with distribution restrictions. + MediaTypeImageLayerNonDistributable = "application/vnd.oci.image.layer.nondistributable.v1.tar" + + // MediaTypeImageLayerNonDistributableGzip is the media type for + // gzipped layers referenced by the manifest but with distribution + // restrictions. + MediaTypeImageLayerNonDistributableGzip = "application/vnd.oci.image.layer.nondistributable.v1.tar+gzip" + + // MediaTypeImageLayerNonDistributableZstd is the media type for zstd + // compressed layers referenced by the manifest but with distribution + // restrictions. + MediaTypeImageLayerNonDistributableZstd = "application/vnd.oci.image.layer.nondistributable.v1.tar+zstd" + + // MediaTypeImageConfig specifies the media type for the image configuration. + MediaTypeImageConfig = "application/vnd.oci.image.config.v1+json" +) diff --git a/vendor/github.com/opencontainers/image-spec/specs-go/version.go b/vendor/github.com/opencontainers/image-spec/specs-go/version.go new file mode 100644 index 0000000000..31f99cf645 --- /dev/null +++ b/vendor/github.com/opencontainers/image-spec/specs-go/version.go @@ -0,0 +1,32 @@ +// Copyright 2016 The Linux Foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package specs + +import "fmt" + +const ( + // VersionMajor is for an API incompatible changes + VersionMajor = 1 + // VersionMinor is for functionality in a backwards-compatible manner + VersionMinor = 0 + // VersionPatch is for backwards-compatible bug fixes + VersionPatch = 2 + + // VersionDev indicates development branch. Releases will be empty string. + VersionDev = "-dev" +) + +// Version is the specification version that the package types support. +var Version = fmt.Sprintf("%d.%d.%d%s", VersionMajor, VersionMinor, VersionPatch, VersionDev) diff --git a/vendor/github.com/opencontainers/image-spec/specs-go/versioned.go b/vendor/github.com/opencontainers/image-spec/specs-go/versioned.go new file mode 100644 index 0000000000..58a1510f33 --- /dev/null +++ b/vendor/github.com/opencontainers/image-spec/specs-go/versioned.go @@ -0,0 +1,23 @@ +// Copyright 2016 The Linux Foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package specs + +// Versioned provides a struct with the manifest schemaVersion and mediaType. +// Incoming content with unknown schema version can be decoded against this +// struct to check the version. +type Versioned struct { + // SchemaVersion is the image manifest schema that this image follows + SchemaVersion int `json:"schemaVersion"` +} diff --git a/vendor/github.com/pb33f/libopenapi/LICENSE b/vendor/github.com/pb33f/libopenapi/LICENSE new file mode 100644 index 0000000000..15d9dc462d --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/LICENSE @@ -0,0 +1,23 @@ +MIT License + +libopenapi + +Copyright (c) 2022-2023 Princess Beef Heavy Industries & Dave Shanley + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/pb33f/libopenapi/README.md b/vendor/github.com/pb33f/libopenapi/README.md new file mode 100644 index 0000000000..15688ea416 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/README.md @@ -0,0 +1,78 @@ +

+ libopenapi +

+ +# libopenapi - enterprise grade OpenAPI tools for golang. + + +![Pipeline](https://github.com/pb33f/libopenapi/workflows/Build/badge.svg) +[![GoReportCard](https://goreportcard.com/badge/github.com/pb33f/libopenapi)](https://goreportcard.com/report/github.com/pb33f/libopenapi) +[![codecov](https://codecov.io/gh/pb33f/libopenapi/branch/main/graph/badge.svg?)](https://codecov.io/gh/pb33f/libopenapi) +[![discord](https://img.shields.io/discord/923258363540815912)](https://discord.gg/x7VACVuEGP) +[![Docs](https://img.shields.io/badge/godoc-reference-5fafd7)](https://pkg.go.dev/github.com/pb33f/libopenapi) + +libopenapi has full support for Swagger (OpenAPI 2), OpenAPI 3, and OpenAPI 3.1. It can handle the largest and most +complex specifications you can think of. + +--- + +## Sponsors & users +If your company is using `libopenapi`, please considering [supporting this project](https://github.com/sponsors/daveshanley), +like our _very kind_ sponsors: + +

+ Speakeasy +
+ Speakeasy +

+ +`libopenapi` is pretty new, so our list of notable projects that depend on `libopenapi` is small (let me know if you'd like to add your project) + +- [github.com/danielgtaylor/restish](https://github.com/danielgtaylor/restish) - "Restish is a CLI for interacting with REST-ish HTTP APIs" +- [github.com/daveshanley/vacuum](https://github.com/daveshanley/vacuum) - "The world's fastest and most scalable OpenAPI/Swagger linter/quality tool" +- [github.com/pb33f/openapi-changes](https://github.com/pb33f/openapi-changes) - "The world's **sexiest** OpenAPI diff tool" +- [github.com/speakeasy-api/speakeasy](https://github.com/speakeasy-api/speakeasy) - "Speakeasy CLI makes validating OpenAPI docs and generating idiomatic SDKs easy!" + +--- + +## Come chat with us + +Need help? Have a question? Want to share your work? [Join our discord](https://discord.gg/x7VACVuEGP) and +come say hi! + +## Check out the `libopenapi-validator` + +Need to validate requests, responses, parameters or schemas? Use the new +[libopenapi-validator](https://github.com/pb33f/libopenapi-validator) module. + +## Documentation + +See all the documentation at https://pb33f.io/libopenapi/ + +- [Installing libopenapi](https://pb33f.io/libopenapi/installing/) +- [Using OpenAPI](https://pb33f.io/libopenapi/openapi/) +- [Using Swagger](https://pb33f.io/libopenapi/swagger/) +- [The Data Model](https://pb33f.io/libopenapi/model/) +- [Validation](https://pb33f.io/libopenapi/validation/) +- [Modifying / Mutating the OpenAPI Model](https://pb33f.io/libopenapi/modifying/) +- [Using Vendor Extensions](https://pb33f.io/libopenapi/extensions/) +- [The Index](https://pb33f.io/libopenapi/index/) +- [The Resolver](https://pb33f.io/libopenapi/resolver/) +- [Circular References](https://pb33f.io/libopenapi/circular-references/) +- [What Changed / Diff Engine](https://pb33f.io/libopenapi/what-changed/) +- [FAQ](https://pb33f.io/libopenapi/faq/) +- [About libopenapi](https://pb33f.io/libopenapi/about/) + +> **Read the go docs at [https://pkg.go.dev/github.com/pb33f/libopenapi](https://pkg.go.dev/github.com/pb33f/libopenapi)** +--- + +### Quick-start tutorial + +👀 **Get rolling fast using `libopenapi` with the +[Parsing OpenAPI files using go](https://quobix.com/articles/parsing-openapi-using-go/)** guide 👀 + +> Read the full docs at [https://pkg.go.dev](https://pkg.go.dev/github.com/pb33f/libopenapi) + +--- + +Logo gopher is modified, originally from [egonelbre](https://github.com/egonelbre/gophers) diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/constants.go b/vendor/github.com/pb33f/libopenapi/datamodel/constants.go new file mode 100644 index 0000000000..b1e51e3f7f --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/constants.go @@ -0,0 +1,59 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +// Package datamodel contains two sets of models, high and low. +// +// The low level (or plumbing) models are designed to capture every single detail about specification, including +// all lines, columns, positions, tags, comments and essentially everything you would ever want to know. +// Positions of every key, value and meta-data that is lost when blindly un-marshaling JSON/YAML into a struct. +// +// The high model (porcelain) is a much simpler representation of the low model, keys are simple strings and indices +// are numbers. When developing consumers of the model, the high model is really what you want to use instead of the +// low model, it's much easier to navigate and is designed for easy consumption. +// +// The high model requires the low model to be built. Every high model has a 'GoLow' method that allows the consumer +// to 'drop down' from the porcelain API to the plumbing API, which gives instant access to everything low. +package datamodel + +import ( + _ "embed" +) + +// Constants used by utilities to determine the version of OpenAPI that we're referring to. +const ( + // OAS2 represents Swagger Documents + OAS2 = "oas2" + + // OAS3 represents OpenAPI 3.0+ Documents + OAS3 = "oas3" + + // OAS31 represents OpenAPI 3.1+ Documents + OAS31 = "oas3_1" +) + +// OpenAPI3SchemaData is an embedded version of the OpenAPI 3 Schema +//go:embed schemas/oas3-schema.json +var OpenAPI3SchemaData string // embedded OAS3 schema + +// OpenAPI31SchemaData is an embedded version of the OpenAPI 3.1 Schema +//go:embed schemas/oas31-schema.json +var OpenAPI31SchemaData string // embedded OAS31 schema + +// OpenAPI2SchemaData is an embedded version of the OpenAPI 2 (Swagger) Schema +//go:embed schemas/swagger2-schema.json +var OpenAPI2SchemaData string // embedded OAS3 schema + +// OAS3_1Format defines documents that can only be version 3.1 +var OAS3_1Format = []string{OAS31} + +// OAS3Format defines documents that can only be version 3.0 +var OAS3Format = []string{OAS3} + +// OAS3AllFormat defines documents that compose all 3+ versions +var OAS3AllFormat = []string{OAS3, OAS31} + +// OAS2Format defines documents that compose swagger documnets (version 2.0) +var OAS2Format = []string{OAS2} + +// AllFormats defines all versions of OpenAPI +var AllFormats = []string{OAS3, OAS31, OAS2} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/document_config.go b/vendor/github.com/pb33f/libopenapi/datamodel/document_config.go new file mode 100644 index 0000000000..e29c78fae0 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/document_config.go @@ -0,0 +1,41 @@ +// Copyright 2023 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package datamodel + +import "net/url" + +// DocumentConfiguration is used to configure the document creation process. It was added in v0.6.0 to allow +// for more fine-grained control over controls and new features. +// +// The default configuration will set AllowFileReferences to false and AllowRemoteReferences to false, which means +// any non-local (local being the specification, not the file system) references, will be ignored. +type DocumentConfiguration struct { + // The BaseURL will be the root from which relative references will be resolved from if they can't be found locally. + // Schema must be set to "http/https". + BaseURL *url.URL + + // If resolving locally, the BasePath will be the root from which relative references will be resolved from. + // It's usually the location of the root specification. + BasePath string // set the Base Path for resolving relative references if the spec is exploded. + + // AllowFileReferences will allow the index to locate relative file references. This is disabled by default. + AllowFileReferences bool + + // AllowRemoteReferences will allow the index to lookup remote references. This is disabled by default. + AllowRemoteReferences bool +} + +func NewOpenDocumentConfiguration() *DocumentConfiguration { + return &DocumentConfiguration{ + AllowFileReferences: true, + AllowRemoteReferences: true, + } +} + +func NewClosedDocumentConfiguration() *DocumentConfiguration { + return &DocumentConfiguration{ + AllowFileReferences: false, + AllowRemoteReferences: false, + } +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/high/base/base.go b/vendor/github.com/pb33f/libopenapi/datamodel/high/base/base.go new file mode 100644 index 0000000000..f567bf4c67 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/high/base/base.go @@ -0,0 +1,12 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +// Package base contains shared high-level models that are used between both versions 2 and 3 of OpenAPI. +// These models are consistent across both specifications, except for the Schema. +// +// OpenAPI 3 contains all the same properties that an OpenAPI 2 specification does, and more. The choice +// to not duplicate the schemas is to allow a graceful degradation pattern to be used. Schemas are the most complex +// beats, particularly when polymorphism is used. By re-using the same superset Schema across versions, we can ensure +// that all the latest features are collected, without damaging backwards compatibility. +package base + diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/high/base/contact.go b/vendor/github.com/pb33f/libopenapi/datamodel/high/base/contact.go new file mode 100644 index 0000000000..e8dc31eaa7 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/high/base/contact.go @@ -0,0 +1,52 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package base + +import ( + low2 "github.com/pb33f/libopenapi/datamodel/high" + low "github.com/pb33f/libopenapi/datamodel/low/base" + "gopkg.in/yaml.v3" +) + +// Contact represents a high-level representation of the Contact definitions found at +// v2 - https://swagger.io/specification/v2/#contactObject +// v3 - https://spec.openapis.org/oas/v3.1.0#contact-object +type Contact struct { + Name string `json:"name,omitempty" yaml:"name,omitempty"` + URL string `json:"url,omitempty" yaml:"url,omitempty"` + Email string `json:"email,omitempty" yaml:"email,omitempty"` + low *low.Contact `json:"-" yaml:"-"` // low-level representation +} + +// NewContact will create a new Contact instance using a low-level Contact +func NewContact(contact *low.Contact) *Contact { + c := new(Contact) + c.low = contact + c.URL = contact.URL.Value + c.Name = contact.Name.Value + c.Email = contact.Email.Value + return c +} + +// GoLow returns the low level Contact object used to create the high-level one. +func (c *Contact) GoLow() *low.Contact { + return c.low +} + +// GoLowUntyped will return the low-level Contact instance that was used to create the high-level one, with no type +func (c *Contact) GoLowUntyped() any { + return c.low +} + +func (c *Contact) Render() ([]byte, error) { + return yaml.Marshal(c) +} + +func (c *Contact) MarshalYAML() (interface{}, error) { + nb := low2.NewNodeBuilder(c, c.low) + return nb.Render(), nil +} + + + diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/high/base/discriminator.go b/vendor/github.com/pb33f/libopenapi/datamodel/high/base/discriminator.go new file mode 100644 index 0000000000..9ae81f19f3 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/high/base/discriminator.go @@ -0,0 +1,58 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package base + +import ( + low2 "github.com/pb33f/libopenapi/datamodel/high" + low "github.com/pb33f/libopenapi/datamodel/low/base" + "gopkg.in/yaml.v3" +) + +// Discriminator is only used by OpenAPI 3+ documents, it represents a polymorphic discriminator used for schemas +// +// When request bodies or response payloads may be one of a number of different schemas, a discriminator object can be +// used to aid in serialization, deserialization, and validation. The discriminator is a specific object in a schema +// which is used to inform the consumer of the document of an alternative schema based on the value associated with it. +// +// When using the discriminator, inline schemas will not be considered. +// v3 - https://spec.openapis.org/oas/v3.1.0#discriminator-object +type Discriminator struct { + PropertyName string `json:"propertyName,omitempty" yaml:"propertyName,omitempty"` + Mapping map[string]string `json:"mapping,omitempty" yaml:"mapping,omitempty"` + low *low.Discriminator +} + +// NewDiscriminator will create a new high-level Discriminator from a low-level one. +func NewDiscriminator(disc *low.Discriminator) *Discriminator { + d := new(Discriminator) + d.low = disc + d.PropertyName = disc.PropertyName.Value + mapping := make(map[string]string) + for k, v := range disc.Mapping.Value { + mapping[k.Value] = v.Value + } + d.Mapping = mapping + return d +} + +// GoLow returns the low-level Discriminator used to build the high-level one. +func (d *Discriminator) GoLow() *low.Discriminator { + return d.low +} + +// GoLowUntyped will return the low-level Discriminator instance that was used to create the high-level one, with no type +func (d *Discriminator) GoLowUntyped() any { + return d.low +} + +// Render will return a YAML representation of the Discriminator object as a byte slice. +func (d *Discriminator) Render() ([]byte, error) { + return yaml.Marshal(d) +} + +// MarshalYAML will create a ready to render YAML representation of the Discriminator object. +func (d *Discriminator) MarshalYAML() (interface{}, error) { + nb := low2.NewNodeBuilder(d, d.low) + return nb.Render(), nil +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/high/base/dynamic_value.go b/vendor/github.com/pb33f/libopenapi/datamodel/high/base/dynamic_value.go new file mode 100644 index 0000000000..c949ad8f25 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/high/base/dynamic_value.go @@ -0,0 +1,101 @@ +// Copyright 2023 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package base + +import ( + "github.com/pb33f/libopenapi/datamodel/high" + "gopkg.in/yaml.v3" + "reflect" +) + +// DynamicValue is used to hold multiple possible values for a schema property. There are two values, a left +// value (A) and a right value (B). The left value (A) is a 3.0 schema property value, the right value (B) is a 3.1 +// schema value. +// +// OpenAPI 3.1 treats a Schema as a real JSON schema, which means some properties become incompatible, or others +// now support more than one primitive type or structure. +// The N value is a bit to make it each to know which value (A or B) is used, this prevents having to +// if/else on the value to determine which one is set. +type DynamicValue[A any, B any] struct { + N int // 0 == A, 1 == B + A A + B B + inline bool +} + +// IsA will return true if the 'A' or left value is set. (OpenAPI 3) +func (d *DynamicValue[A, B]) IsA() bool { + return d.N == 0 +} + +// IsB will return true if the 'B' or right value is set (OpenAPI 3.1) +func (d *DynamicValue[A, B]) IsB() bool { + return d.N == 1 +} + +func (d *DynamicValue[A, B]) Render() ([]byte, error) { + d.inline = false + return yaml.Marshal(d) +} + +func (d *DynamicValue[A, B]) RenderInline() ([]byte, error) { + d.inline = true + return yaml.Marshal(d) +} + + +// MarshalYAML will create a ready to render YAML representation of the DynamicValue object. +func (d *DynamicValue[A, B]) MarshalYAML() (interface{}, error) { + // this is a custom renderer, we can't use the NodeBuilder out of the gate. + var n yaml.Node + var err error + var value any + + if d.IsA() { + value = d.A + } + if d.IsB() { + value = d.B + } + to := reflect.TypeOf(value) + switch to.Kind() { + case reflect.Ptr: + if d.inline { + if r, ok := value.(high.RenderableInline); ok { + return r.MarshalYAMLInline() + } else { + _ = n.Encode(value) + } + } else { + if r, ok := value.(high.Renderable); ok { + return r.MarshalYAML() + } else { + _ = n.Encode(value) + } + } + case reflect.Bool: + _ = n.Encode(value.(bool)) + case reflect.Int: + _ = n.Encode(value.(int)) + case reflect.String: + _ = n.Encode(value.(string)) + case reflect.Int64: + _ = n.Encode(value.(int64)) + case reflect.Float64: + _ = n.Encode(value.(float64)) + case reflect.Float32: + _ = n.Encode(value.(float32)) + case reflect.Int32: + _ = n.Encode(value.(int32)) + + } + return &n, err +} + +// MarshalYAMLInline will create a ready to render YAML representation of the DynamicValue object. The +// references will be inlined instead of kept as references. +func (d *DynamicValue[A, B]) MarshalYAMLInline() (interface{}, error) { + d.inline = true + return d.MarshalYAML() +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/high/base/example.go b/vendor/github.com/pb33f/libopenapi/datamodel/high/base/example.go new file mode 100644 index 0000000000..31d711b080 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/high/base/example.go @@ -0,0 +1,65 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package base + +import ( + "github.com/pb33f/libopenapi/datamodel/high" + lowmodel "github.com/pb33f/libopenapi/datamodel/low" + low "github.com/pb33f/libopenapi/datamodel/low/base" + "gopkg.in/yaml.v3" +) + +// Example represents a high-level Example object as defined by OpenAPI 3+ +// v3 - https://spec.openapis.org/oas/v3.1.0#example-object +type Example struct { + Summary string `json:"summary,omitempty" yaml:"summary,omitempty"` + Description string `json:"description,omitempty" yaml:"description,omitempty"` + Value any `json:"value,omitempty" yaml:"value,omitempty"` + ExternalValue string `json:"externalValue,omitempty" yaml:"externalValue,omitempty"` + Extensions map[string]any `json:"-" yaml:"-"` + low *low.Example +} + +// NewExample will create a new instance of an Example, using a low-level Example. +func NewExample(example *low.Example) *Example { + e := new(Example) + e.low = example + e.Summary = example.Summary.Value + e.Description = example.Description.Value + e.Value = example.Value.Value + e.ExternalValue = example.ExternalValue.Value + e.Extensions = high.ExtractExtensions(example.Extensions) + return e +} + +// GoLow will return the low-level Example used to build the high level one. +func (e *Example) GoLow() *low.Example { + return e.low +} + +// GoLowUntyped will return the low-level Example instance that was used to create the high-level one, with no type +func (e *Example) GoLowUntyped() any { + return e.low +} + +// Render will return a YAML representation of the Example object as a byte slice. +func (e *Example) Render() ([]byte, error) { + return yaml.Marshal(e) +} + +// MarshalYAML will create a ready to render YAML representation of the Example object. +func (e *Example) MarshalYAML() (interface{}, error) { + nb := high.NewNodeBuilder(e, e.low) + return nb.Render(), nil +} + +// ExtractExamples will convert a low-level example map, into a high level one that is simple to navigate. +// no fidelity is lost, everything is still available via GoLow() +func ExtractExamples(elements map[lowmodel.KeyReference[string]]lowmodel.ValueReference[*low.Example]) map[string]*Example { + extracted := make(map[string]*Example) + for k, v := range elements { + extracted[k.Value] = NewExample(v.Value) + } + return extracted +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/high/base/external_doc.go b/vendor/github.com/pb33f/libopenapi/datamodel/high/base/external_doc.go new file mode 100644 index 0000000000..79dc117e24 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/high/base/external_doc.go @@ -0,0 +1,61 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package base + +import ( + "github.com/pb33f/libopenapi/datamodel/high" + low "github.com/pb33f/libopenapi/datamodel/low/base" + "gopkg.in/yaml.v3" +) + +// ExternalDoc represents a high-level External Documentation object as defined by OpenAPI 2 and 3 +// +// Allows referencing an external resource for extended documentation. +// v2 - https://swagger.io/specification/v2/#externalDocumentationObject +// v3 - https://spec.openapis.org/oas/v3.1.0#external-documentation-object +type ExternalDoc struct { + Description string `json:"description,omitempty" yaml:"description,omitempty"` + URL string `json:"url,omitempty" yaml:"url,omitempty"` + Extensions map[string]any `json:"-" yaml:"-"` + low *low.ExternalDoc +} + +// NewExternalDoc will create a new high-level External Documentation object from a low-level one. +func NewExternalDoc(extDoc *low.ExternalDoc) *ExternalDoc { + d := new(ExternalDoc) + d.low = extDoc + if !extDoc.Description.IsEmpty() { + d.Description = extDoc.Description.Value + } + if !extDoc.URL.IsEmpty() { + d.URL = extDoc.URL.Value + } + d.Extensions = high.ExtractExtensions(extDoc.Extensions) + return d +} + +// GoLow returns the low-level ExternalDoc instance used to create the high-level one. +func (e *ExternalDoc) GoLow() *low.ExternalDoc { + return e.low +} + +// GoLowUntyped will return the low-level ExternalDoc instance that was used to create the high-level one, with no type +func (e *ExternalDoc) GoLowUntyped() any { + return e.low +} + +func (e *ExternalDoc) GetExtensions() map[string]any { + return e.Extensions +} + +// Render will return a YAML representation of the ExternalDoc object as a byte slice. +func (e *ExternalDoc) Render() ([]byte, error) { + return yaml.Marshal(e) +} + +// MarshalYAML will create a ready to render YAML representation of the ExternalDoc object. +func (e *ExternalDoc) MarshalYAML() (interface{}, error) { + nb := high.NewNodeBuilder(e, e.low) + return nb.Render(), nil +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/high/base/info.go b/vendor/github.com/pb33f/libopenapi/datamodel/high/base/info.go new file mode 100644 index 0000000000..8c623fb00e --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/high/base/info.go @@ -0,0 +1,81 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package base + +import ( + "github.com/pb33f/libopenapi/datamodel/high" + low "github.com/pb33f/libopenapi/datamodel/low/base" + "gopkg.in/yaml.v3" +) + +// Info represents a high-level Info object as defined by both OpenAPI 2 and OpenAPI 3. +// +// The object provides metadata about the API. The metadata MAY be used by the clients if needed, and MAY be presented +// in editing or documentation generation tools for convenience. +// +// v2 - https://swagger.io/specification/v2/#infoObject +// v3 - https://spec.openapis.org/oas/v3.1.0#info-object +type Info struct { + Summary string `json:"summary,omitempty" yaml:"summary,omitempty"` + Title string `json:"title,omitempty" yaml:"title,omitempty"` + Description string `json:"description,omitempty" yaml:"description,omitempty"` + TermsOfService string `json:"termsOfService,omitempty" yaml:"termsOfService,omitempty"` + Contact *Contact `json:"contact,omitempty" yaml:"contact,omitempty"` + License *License `json:"license,omitempty" yaml:"license,omitempty"` + Version string `json:"version,omitempty" yaml:"version,omitempty"` + Extensions map[string]any + low *low.Info +} + +// NewInfo will create a new high-level Info instance from a low-level one. +func NewInfo(info *low.Info) *Info { + i := new(Info) + i.low = info + if !info.Title.IsEmpty() { + i.Title = info.Title.Value + } + if !info.Summary.IsEmpty() { + i.Summary = info.Summary.Value + } + if !info.Description.IsEmpty() { + i.Description = info.Description.Value + } + if !info.TermsOfService.IsEmpty() { + i.TermsOfService = info.TermsOfService.Value + } + if !info.Contact.IsEmpty() { + i.Contact = NewContact(info.Contact.Value) + } + if !info.License.IsEmpty() { + i.License = NewLicense(info.License.Value) + } + if !info.Version.IsEmpty() { + i.Version = info.Version.Value + } + if len(info.Extensions) > 0 { + i.Extensions = high.ExtractExtensions(info.Extensions) + } + return i +} + +// GoLow will return the low-level Info instance that was used to create the high-level one. +func (i *Info) GoLow() *low.Info { + return i.low +} + +// GoLowUntyped will return the low-level Info instance that was used to create the high-level one, with no type +func (i *Info) GoLowUntyped() any { + return i.low +} + +// Render will return a YAML representation of the Info object as a byte slice. +func (i *Info) Render() ([]byte, error) { + return yaml.Marshal(i) +} + +// MarshalYAML will create a ready to render YAML representation of the Info object. +func (i *Info) MarshalYAML() (interface{}, error) { + nb := high.NewNodeBuilder(i, i.low) + return nb.Render(), nil +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/high/base/license.go b/vendor/github.com/pb33f/libopenapi/datamodel/high/base/license.go new file mode 100644 index 0000000000..acc614adda --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/high/base/license.go @@ -0,0 +1,53 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package base + +import ( + low2 "github.com/pb33f/libopenapi/datamodel/high" + low "github.com/pb33f/libopenapi/datamodel/low/base" + "gopkg.in/yaml.v3" +) + +// License is a high-level representation of a License object as defined by OpenAPI 2 and OpenAPI 3 +// v2 - https://swagger.io/specification/v2/#licenseObject +// v3 - https://spec.openapis.org/oas/v3.1.0#license-object +type License struct { + Name string `json:"name,omitempty" yaml:"name,omitempty"` + URL string `json:"url,omitempty" yaml:"url,omitempty"` + low *low.License +} + +// NewLicense will create a new high-level License instance from a low-level one. +func NewLicense(license *low.License) *License { + l := new(License) + l.low = license + if !license.URL.IsEmpty() { + l.URL = license.URL.Value + } + if !license.Name.IsEmpty() { + l.Name = license.Name.Value + } + return l +} + +// GoLow will return the low-level License used to create the high-level one. +func (l *License) GoLow() *low.License { + return l.low +} + +// GoLowUntyped will return the low-level License instance that was used to create the high-level one, with no type +func (l *License) GoLowUntyped() any { + return l.low +} + +// Render will return a YAML representation of the License object as a byte slice. +func (l *License) Render() ([]byte, error) { + return yaml.Marshal(l) +} + +// MarshalYAML will create a ready to render YAML representation of the License object. +func (l *License) MarshalYAML() (interface{}, error) { + nb := low2.NewNodeBuilder(l, l.low) + return nb.Render(), nil +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/high/base/schema.go b/vendor/github.com/pb33f/libopenapi/datamodel/high/base/schema.go new file mode 100644 index 0000000000..550814a11d --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/high/base/schema.go @@ -0,0 +1,484 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package base + +import ( + "gopkg.in/yaml.v3" + "sync" + + "github.com/pb33f/libopenapi/datamodel/high" + lowmodel "github.com/pb33f/libopenapi/datamodel/low" + "github.com/pb33f/libopenapi/datamodel/low/base" +) + +// Schema represents a JSON Schema that support Swagger, OpenAPI 3 and OpenAPI 3.1 +// +// Until 3.1 OpenAPI had a strange relationship with JSON Schema. It's been a super-set/sub-set +// mix, which has been confusing. So, instead of building a bunch of different models, we have compressed +// all variations into a single model that makes it easy to support multiple spec types. +// +// - v2 schema: https://swagger.io/specification/v2/#schemaObject +// - v3 schema: https://swagger.io/specification/#schema-object +// - v3.1 schema: https://spec.openapis.org/oas/v3.1.0#schema-object +type Schema struct { + // 3.1 only, used to define a dialect for this schema, label is '$schema'. + SchemaTypeRef string `json:"$schema,omitempty" yaml:"$schema,omitempty"` + + // In versions 2 and 3.0, this ExclusiveMaximum can only be a boolean. + // In version 3.1, ExclusiveMaximum is an integer. + ExclusiveMaximum *DynamicValue[bool, int64] `json:"exclusiveMaximum,omitempty" yaml:"exclusiveMaximum,omitempty"` + + // In versions 2 and 3.0, this ExclusiveMinimum can only be a boolean. + // In version 3.1, ExclusiveMinimum is an integer. + ExclusiveMinimum *DynamicValue[bool, int64] `json:"exclusiveMinimum,omitempty" yaml:"exclusiveMinimum,omitempty"` + + // In versions 2 and 3.0, this Type is a single value, so array will only ever have one value + // in version 3.1, Type can be multiple values + Type []string `json:"type,omitempty" yaml:"type,omitempty"` + + // Schemas are resolved on demand using a SchemaProxy + AllOf []*SchemaProxy `json:"allOf,omitempty" yaml:"allOf,omitempty"` + + // Polymorphic Schemas are only available in version 3+ + OneOf []*SchemaProxy `json:"oneOf,omitempty" yaml:"oneOf,omitempty"` + AnyOf []*SchemaProxy `json:"anyOf,omitempty" yaml:"anyOf,omitempty"` + Discriminator *Discriminator `json:"discriminator,omitempty" yaml:"discriminator,omitempty"` + + // in 3.1 examples can be an array (which is recommended) + Examples []any `json:"examples,omitempty" yaml:"examples,omitempty"` + + // in 3.1 prefixItems provides tuple validation support. + PrefixItems []*SchemaProxy `json:"prefixItems,omitempty" yaml:"prefixItems,omitempty"` + + // 3.1 Specific properties + Contains *SchemaProxy `json:"contains,omitempty" yaml:"contains,omitempty"` + MinContains *int64 `json:"minContains,omitempty" yaml:"minContains,omitempty"` + MaxContains *int64 `json:"maxContains,omitempty" yaml:"maxContains,omitempty"` + If *SchemaProxy `json:"if,omitempty" yaml:"if,omitempty"` + Else *SchemaProxy `json:"else,omitempty" yaml:"else,omitempty"` + Then *SchemaProxy `json:"then,omitempty" yaml:"then,omitempty"` + DependentSchemas map[string]*SchemaProxy `json:"dependentSchemas,omitempty" yaml:"dependentSchemas,omitempty"` + PatternProperties map[string]*SchemaProxy `json:"patternProperties,omitempty" yaml:"patternProperties,omitempty"` + PropertyNames *SchemaProxy `json:"propertyNames,omitempty" yaml:"propertyNames,omitempty"` + UnevaluatedItems *SchemaProxy `json:"unevaluatedItems,omitempty" yaml:"unevaluatedItems,omitempty"` + UnevaluatedProperties *SchemaProxy `json:"unevaluatedProperties,omitempty" yaml:"unevaluatedProperties,omitempty"` + + // in 3.1 Items can be a Schema or a boolean + Items *DynamicValue[*SchemaProxy, bool] `json:"items,omitempty" yaml:"items,omitempty"` + + // 3.1 only, part of the JSON Schema spec provides a way to identify a subschema + Anchor string `json:"$anchor,omitempty" yaml:"$anchor,omitempty"` + + // Compatible with all versions + Not *SchemaProxy `json:"not,omitempty" yaml:"not,omitempty"` + Properties map[string]*SchemaProxy `json:"properties,omitempty" yaml:"properties,omitempty"` + Title string `json:"title,omitempty" yaml:"title,omitempty"` + MultipleOf *int64 `json:"multipleOf,omitempty" yaml:"multipleOf,omitempty"` + Maximum *int64 `json:"maximum,omitempty" yaml:"maximum,omitempty"` + Minimum *int64 `json:"minimum,omitempty" yaml:"minimum,omitempty"` + MaxLength *int64 `json:"maxLength,omitempty" yaml:"maxLength,omitempty"` + MinLength *int64 `json:"minLength,omitempty" yaml:"minLength,omitempty"` + Pattern string `json:"pattern,omitempty" yaml:"pattern,omitempty"` + Format string `json:"format,omitempty" yaml:"format,omitempty"` + MaxItems *int64 `json:"maxItems,omitempty" yaml:"maxItems,omitempty"` + MinItems *int64 `json:"minItems,omitempty" yaml:"minItems,omitempty"` + UniqueItems *bool `json:"uniqueItems,omitempty" yaml:"uniqueItems,omitempty"` + MaxProperties *int64 `json:"maxProperties,omitempty" yaml:"maxProperties,omitempty"` + MinProperties *int64 `json:"minProperties,omitempty" yaml:"minProperties,omitempty"` + Required []string `json:"required,omitempty" yaml:"required,omitempty"` + Enum []any `json:"enum,omitempty" yaml:"enum,omitempty"` + AdditionalProperties any `json:"additionalProperties,omitempty" yaml:"additionalProperties,renderZero,omitempty"` + Description string `json:"description,omitempty" yaml:"description,omitempty"` + Default any `json:"default,omitempty" yaml:"default,renderZero,omitempty"` + Nullable *bool `json:"nullable,omitempty" yaml:"nullable,omitempty"` + ReadOnly bool `json:"readOnly,omitempty" yaml:"readOnly,omitempty"` // https://github.com/pb33f/libopenapi/issues/30 + WriteOnly bool `json:"writeOnly,omitempty" yaml:"writeOnly,omitempty"` // https://github.com/pb33f/libopenapi/issues/30 + XML *XML `json:"xml,omitempty" yaml:"xml,omitempty"` + ExternalDocs *ExternalDoc `json:"externalDocs,omitempty" yaml:"externalDocs,omitempty"` + Example any `json:"example,omitempty" yaml:"example,omitempty"` + Deprecated *bool `json:"deprecated,omitempty" yaml:"deprecated,omitempty"` + Extensions map[string]any `json:"-" yaml:"-"` + low *base.Schema + + // Parent Proxy refers back to the low level SchemaProxy that is proxying this schema. + ParentProxy *SchemaProxy `json:"-" yaml:"-"` +} + +// NewSchema will create a new high-level schema from a low-level one. +func NewSchema(schema *base.Schema) *Schema { + s := new(Schema) + s.low = schema + s.Title = schema.Title.Value + if !schema.MultipleOf.IsEmpty() { + s.MultipleOf = &schema.MultipleOf.Value + } + if !schema.Maximum.IsEmpty() { + s.Maximum = &schema.Maximum.Value + } + if !schema.Minimum.IsEmpty() { + s.Minimum = &schema.Minimum.Value + } + // if we're dealing with a 3.0 spec using a bool + if !schema.ExclusiveMaximum.IsEmpty() && schema.ExclusiveMaximum.Value.IsA() { + s.ExclusiveMaximum = &DynamicValue[bool, int64]{ + A: schema.ExclusiveMaximum.Value.A, + } + } + // if we're dealing with a 3.1 spec using an int + if !schema.ExclusiveMaximum.IsEmpty() && schema.ExclusiveMaximum.Value.IsB() { + s.ExclusiveMaximum = &DynamicValue[bool, int64]{ + N: 1, + B: schema.ExclusiveMaximum.Value.B, + } + } + // if we're dealing with a 3.0 spec using a bool + if !schema.ExclusiveMinimum.IsEmpty() && schema.ExclusiveMinimum.Value.IsA() { + s.ExclusiveMinimum = &DynamicValue[bool, int64]{ + A: schema.ExclusiveMinimum.Value.A, + } + } + // if we're dealing with a 3.1 spec, using an int + if !schema.ExclusiveMinimum.IsEmpty() && schema.ExclusiveMinimum.Value.IsB() { + s.ExclusiveMinimum = &DynamicValue[bool, int64]{ + N: 1, + B: schema.ExclusiveMinimum.Value.B, + } + } + if !schema.MaxLength.IsEmpty() { + s.MaxLength = &schema.MaxLength.Value + } + if !schema.MinLength.IsEmpty() { + s.MinLength = &schema.MinLength.Value + } + if !schema.MaxItems.IsEmpty() { + s.MaxItems = &schema.MaxItems.Value + } + if !schema.MinItems.IsEmpty() { + s.MinItems = &schema.MinItems.Value + } + if !schema.MaxProperties.IsEmpty() { + s.MaxProperties = &schema.MaxProperties.Value + } + if !schema.MinProperties.IsEmpty() { + s.MinProperties = &schema.MinProperties.Value + } + + if !schema.MaxContains.IsEmpty() { + s.MaxContains = &schema.MaxContains.Value + } + if !schema.MinContains.IsEmpty() { + s.MinContains = &schema.MinContains.Value + } + if !schema.UniqueItems.IsEmpty() { + s.UniqueItems = &schema.UniqueItems.Value + } + if !schema.Contains.IsEmpty() { + s.Contains = &SchemaProxy{schema: &lowmodel.NodeReference[*base.SchemaProxy]{ + ValueNode: schema.Contains.ValueNode, + Value: schema.Contains.Value, + }} + } + if !schema.If.IsEmpty() { + s.If = &SchemaProxy{schema: &lowmodel.NodeReference[*base.SchemaProxy]{ + ValueNode: schema.If.ValueNode, + Value: schema.If.Value, + }} + } + if !schema.Else.IsEmpty() { + s.Else = &SchemaProxy{schema: &lowmodel.NodeReference[*base.SchemaProxy]{ + ValueNode: schema.Else.ValueNode, + Value: schema.Else.Value, + }} + } + if !schema.Then.IsEmpty() { + s.Then = &SchemaProxy{schema: &lowmodel.NodeReference[*base.SchemaProxy]{ + ValueNode: schema.Then.ValueNode, + Value: schema.Then.Value, + }} + } + if !schema.PropertyNames.IsEmpty() { + s.PropertyNames = &SchemaProxy{schema: &lowmodel.NodeReference[*base.SchemaProxy]{ + ValueNode: schema.PropertyNames.ValueNode, + Value: schema.PropertyNames.Value, + }} + } + if !schema.UnevaluatedItems.IsEmpty() { + s.UnevaluatedItems = &SchemaProxy{schema: &lowmodel.NodeReference[*base.SchemaProxy]{ + ValueNode: schema.UnevaluatedItems.ValueNode, + Value: schema.UnevaluatedItems.Value, + }} + } + if !schema.UnevaluatedProperties.IsEmpty() { + s.UnevaluatedProperties = &SchemaProxy{schema: &lowmodel.NodeReference[*base.SchemaProxy]{ + ValueNode: schema.UnevaluatedProperties.ValueNode, + Value: schema.UnevaluatedProperties.Value, + }} + } + + s.Pattern = schema.Pattern.Value + s.Format = schema.Format.Value + + // 3.0 spec is a single value + if !schema.Type.IsEmpty() && schema.Type.Value.IsA() { + s.Type = []string{schema.Type.Value.A} + } + // 3.1 spec may have multiple values + if !schema.Type.IsEmpty() && schema.Type.Value.IsB() { + for i := range schema.Type.Value.B { + s.Type = append(s.Type, schema.Type.Value.B[i].Value) + } + } + if schema.AdditionalProperties.Value != nil { + if addPropSchema, ok := schema.AdditionalProperties.Value.(*base.SchemaProxy); ok { + s.AdditionalProperties = NewSchemaProxy(&lowmodel.NodeReference[*base.SchemaProxy]{ + KeyNode: schema.AdditionalProperties.KeyNode, + ValueNode: schema.AdditionalProperties.ValueNode, + Value: addPropSchema, + }) + } else { + // TODO: check for slice and map types and unpack correctly. + + s.AdditionalProperties = schema.AdditionalProperties.Value + } + } + s.Description = schema.Description.Value + s.Default = schema.Default.Value + if !schema.Nullable.IsEmpty() { + s.Nullable = &schema.Nullable.Value + } + if !schema.ReadOnly.IsEmpty() { + s.ReadOnly = schema.ReadOnly.Value + } + if !schema.WriteOnly.IsEmpty() { + s.WriteOnly = schema.WriteOnly.Value + } + if !schema.Deprecated.IsEmpty() { + s.Deprecated = &schema.Deprecated.Value + } + s.Example = schema.Example.Value + if len(schema.Examples.Value) > 0 { + examples := make([]any, len(schema.Examples.Value)) + for i := 0; i < len(schema.Examples.Value); i++ { + examples[i] = schema.Examples.Value[i].Value + } + s.Examples = examples + } + s.Extensions = high.ExtractExtensions(schema.Extensions) + if !schema.Discriminator.IsEmpty() { + s.Discriminator = NewDiscriminator(schema.Discriminator.Value) + } + if !schema.XML.IsEmpty() { + s.XML = NewXML(schema.XML.Value) + } + if !schema.ExternalDocs.IsEmpty() { + s.ExternalDocs = NewExternalDoc(schema.ExternalDocs.Value) + } + var req []string + for i := range schema.Required.Value { + req = append(req, schema.Required.Value[i].Value) + } + s.Required = req + + var enum []any + if !schema.Anchor.IsEmpty() { + s.Anchor = schema.Anchor.Value + } + + // TODO: check this behavior. + for i := range schema.Enum.Value { + enum = append(enum, schema.Enum.Value[i].Value) + } + s.Enum = enum + + // async work. + // any polymorphic properties need to be handled in their own threads + // any properties each need to be processed in their own thread. + // we go as fast as we can. + polyCompletedChan := make(chan bool) + propsChan := make(chan bool) + errChan := make(chan error) + + type buildResult struct { + idx int + s *SchemaProxy + } + + // for every item, build schema async + buildSchema := func(sch lowmodel.ValueReference[*base.SchemaProxy], idx int, bChan chan buildResult) { + p := &SchemaProxy{schema: &lowmodel.NodeReference[*base.SchemaProxy]{ + ValueNode: sch.ValueNode, + Value: sch.Value, + Reference: sch.GetReference(), + }} + + bChan <- buildResult{idx: idx, s: p} + } + + // schema async + buildOutSchemas := func(schemas []lowmodel.ValueReference[*base.SchemaProxy], items *[]*SchemaProxy, + doneChan chan bool, e chan error, + ) { + bChan := make(chan buildResult) + totalSchemas := len(schemas) + for i := range schemas { + go buildSchema(schemas[i], i, bChan) + } + j := 0 + for j < totalSchemas { + select { + case r := <-bChan: + j++ + (*items)[r.idx] = r.s + } + } + doneChan <- true + } + + // props async + var plock sync.Mutex + buildProps := func(k lowmodel.KeyReference[string], v lowmodel.ValueReference[*base.SchemaProxy], c chan bool, + props map[string]*SchemaProxy, sw int, + ) { + plock.Lock() + props[k.Value] = &SchemaProxy{ + schema: &lowmodel.NodeReference[*base.SchemaProxy]{ + Value: v.Value, + KeyNode: k.KeyNode, + ValueNode: v.ValueNode, + }, + } + plock.Unlock() + + switch sw { + case 0: + s.Properties = props + case 1: + s.DependentSchemas = props + case 2: + s.PatternProperties = props + } + c <- true + } + + props := make(map[string]*SchemaProxy) + for k, v := range schema.Properties.Value { + go buildProps(k, v, propsChan, props, 0) + } + + dependents := make(map[string]*SchemaProxy) + for k, v := range schema.DependentSchemas.Value { + go buildProps(k, v, propsChan, dependents, 1) + } + patternProps := make(map[string]*SchemaProxy) + for k, v := range schema.PatternProperties.Value { + go buildProps(k, v, propsChan, patternProps, 2) + } + + var allOf []*SchemaProxy + var oneOf []*SchemaProxy + var anyOf []*SchemaProxy + var not *SchemaProxy + var items *DynamicValue[*SchemaProxy, bool] + var prefixItems []*SchemaProxy + + children := 0 + if !schema.AllOf.IsEmpty() { + children++ + allOf = make([]*SchemaProxy, len(schema.AllOf.Value)) + go buildOutSchemas(schema.AllOf.Value, &allOf, polyCompletedChan, errChan) + } + if !schema.AnyOf.IsEmpty() { + children++ + anyOf = make([]*SchemaProxy, len(schema.AnyOf.Value)) + go buildOutSchemas(schema.AnyOf.Value, &anyOf, polyCompletedChan, errChan) + } + if !schema.OneOf.IsEmpty() { + children++ + oneOf = make([]*SchemaProxy, len(schema.OneOf.Value)) + go buildOutSchemas(schema.OneOf.Value, &oneOf, polyCompletedChan, errChan) + } + if !schema.Not.IsEmpty() { + not = NewSchemaProxy(&schema.Not) + } + if !schema.Items.IsEmpty() { + if schema.Items.Value.IsA() { + items = &DynamicValue[*SchemaProxy, bool]{A: &SchemaProxy{schema: &lowmodel.NodeReference[*base.SchemaProxy]{ + ValueNode: schema.Items.ValueNode, + Value: schema.Items.Value.A, + KeyNode: schema.Items.KeyNode, + }}} + } else { + items = &DynamicValue[*SchemaProxy, bool]{N: 1, B: schema.Items.Value.B} + } + } + if !schema.PrefixItems.IsEmpty() { + children++ + prefixItems = make([]*SchemaProxy, len(schema.PrefixItems.Value)) + go buildOutSchemas(schema.PrefixItems.Value, &prefixItems, polyCompletedChan, errChan) + } + + completeChildren := 0 + completedProps := 0 + totalProps := len(schema.Properties.Value) + len(schema.DependentSchemas.Value) + len(schema.PatternProperties.Value) + if totalProps+children > 0 { + allDone: + for true { + select { + case <-polyCompletedChan: + completeChildren++ + if totalProps == completedProps && children == completeChildren { + break allDone + } + case <-propsChan: + completedProps++ + if totalProps == completedProps && children == completeChildren { + break allDone + } + } + } + } + s.OneOf = oneOf + s.AnyOf = anyOf + s.AllOf = allOf + s.Items = items + s.PrefixItems = prefixItems + s.Not = not + return s +} + +// GoLow will return the low-level instance of Schema that was used to create the high level one. +func (s *Schema) GoLow() *base.Schema { + return s.low +} + +// GoLowUntyped will return the low-level Schema instance that was used to create the high-level one, with no type +func (s *Schema) GoLowUntyped() any { + return s.low +} + +// Render will return a YAML representation of the Schema object as a byte slice. +func (s *Schema) Render() ([]byte, error) { + return yaml.Marshal(s) +} + +// RenderInline will return a YAML representation of the Schema object as a byte slice. All of the +// $ref values will be inlined, as in resolved in place. +// +// Make sure you don't have any circular references! +func (s *Schema) RenderInline() ([]byte, error) { + d, _ := s.MarshalYAMLInline() + return yaml.Marshal(d) +} + +// MarshalYAML will create a ready to render YAML representation of the ExternalDoc object. +func (s *Schema) MarshalYAML() (interface{}, error) { + nb := high.NewNodeBuilder(s, s.low) + return nb.Render(), nil +} + +func (s *Schema) MarshalYAMLInline() (interface{}, error) { + nb := high.NewNodeBuilder(s, s.low) + nb.Resolve = true + return nb.Render(), nil +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/high/base/schema_proxy.go b/vendor/github.com/pb33f/libopenapi/datamodel/high/base/schema_proxy.go new file mode 100644 index 0000000000..8097d6ca70 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/high/base/schema_proxy.go @@ -0,0 +1,177 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package base + +import ( + "github.com/pb33f/libopenapi/datamodel/high" + "github.com/pb33f/libopenapi/datamodel/low" + "github.com/pb33f/libopenapi/datamodel/low/base" + "github.com/pb33f/libopenapi/utils" + "gopkg.in/yaml.v3" +) + +// SchemaProxy exists as a stub that will create a Schema once (and only once) the Schema() method is called. An +// underlying low-level SchemaProxy backs this high-level one. +// +// Why use a Proxy design? +// +// There are three reasons. +// +// 1. Circular References and Endless Loops. +// +// JSON Schema allows for references to be used. This means references can loop around and create infinite recursive +// structures, These 'Circular references' technically mean a schema can NEVER be resolved, not without breaking the +// loop somewhere along the chain. +// +// Polymorphism in the form of 'oneOf' and 'anyOf' in version 3+ only exacerbates the problem. +// +// These circular traps can be discovered using the resolver, however it's still not enough to stop endless loops and +// endless goroutine spawning. A proxy design means that resolving occurs on demand and runs down a single level only. +// preventing any run-away loops. +// +// 2. Performance +// +// Even without circular references, Polymorphism creates large additional resolving chains that take a long time +// and slow things down when building. By preventing recursion through every polymorphic item, building models is kept +// fast and snappy, which is desired for realtime processing of specs. +// +// - Q: Yeah, but, why not just use state to avoiding re-visiting seen polymorphic nodes? +// - A: It's slow, takes up memory and still has runaway potential in very, very long chains. +// +// 3. Short Circuit Errors. +// +// Schemas are where things can get messy, mainly because the Schema standard changes between versions, and +// it's not actually JSONSchema until 3.1, so lots of times a bad schema will break parsing. Errors are only found +// when a schema is needed, so the rest of the document is parsed and ready to use. +type SchemaProxy struct { + schema *low.NodeReference[*base.SchemaProxy] + buildError error + rendered *Schema + refStr string +} + +// NewSchemaProxy creates a new high-level SchemaProxy from a low-level one. +func NewSchemaProxy(schema *low.NodeReference[*base.SchemaProxy]) *SchemaProxy { + return &SchemaProxy{schema: schema} +} + +// CreateSchemaProxy will create a new high-level SchemaProxy from a high-level Schema, this acts the same +// as if the SchemaProxy is pre-rendered. +func CreateSchemaProxy(schema *Schema) *SchemaProxy { + return &SchemaProxy{rendered: schema} +} + +// CreateSchemaProxyRef will create a new high-level SchemaProxy from a reference string, this is used only when +// building out new models from scratch that require a reference rather than a schema implementation. +func CreateSchemaProxyRef(ref string) *SchemaProxy { + return &SchemaProxy{refStr: ref} +} + +// Schema will create a new Schema instance using NewSchema from the low-level SchemaProxy backing this high-level one. +// If there is a problem building the Schema, then this method will return nil. Use GetBuildError to gain access +// to that building error. +func (sp *SchemaProxy) Schema() *Schema { + if sp.rendered == nil { + s := sp.schema.Value.Schema() + if s == nil { + sp.buildError = sp.schema.Value.GetBuildError() + return nil + } + sch := NewSchema(s) + sch.ParentProxy = sp + sp.rendered = sch + return sch + } else { + return sp.rendered + } +} + +// IsReference returns true if the SchemaProxy is a reference to another Schema. +func (sp *SchemaProxy) IsReference() bool { + if sp.refStr != "" { + return true + } + if sp.schema != nil { + return sp.schema.Value.IsSchemaReference() + } + return false +} + +// GetReference returns the location of the $ref if this SchemaProxy is a reference to another Schema. +func (sp *SchemaProxy) GetReference() string { + if sp.refStr != "" { + return sp.refStr + } + return sp.schema.Value.GetSchemaReference() +} + +// BuildSchema operates the same way as Schema, except it will return any error along with the *Schema +func (sp *SchemaProxy) BuildSchema() (*Schema, error) { + if sp.rendered != nil { + return sp.rendered, sp.buildError + } + schema := sp.Schema() + er := sp.buildError + return schema, er +} + +// GetBuildError returns any error that was thrown when calling Schema() +func (sp *SchemaProxy) GetBuildError() error { + return sp.buildError +} + +func (sp *SchemaProxy) GoLow() *base.SchemaProxy { + if sp.schema == nil { + return nil + } + return sp.schema.Value +} + +func (sp *SchemaProxy) GoLowUntyped() any { + if sp.schema == nil { + return nil + } + return sp.schema.Value +} + +// Render will return a YAML representation of the Schema object as a byte slice. +func (sp *SchemaProxy) Render() ([]byte, error) { + return yaml.Marshal(sp) +} + +// MarshalYAML will create a ready to render YAML representation of the ExternalDoc object. +func (sp *SchemaProxy) MarshalYAML() (interface{}, error) { + var s *Schema + var err error + // if this schema isn't a reference, then build it out. + if !sp.IsReference() { + s, err = sp.BuildSchema() + if err != nil { + return nil, err + } + nb := high.NewNodeBuilder(s, s.low) + return nb.Render(), nil + } else { + // do not build out a reference, just marshal the reference. + mp := utils.CreateEmptyMapNode() + mp.Content = append(mp.Content, + utils.CreateStringNode("$ref"), + utils.CreateStringNode(sp.GetReference())) + return mp, nil + } +} + +// MarshalYAMLInline will create a ready to render YAML representation of the ExternalDoc object. The +// $ref values will be inlined instead of kept as is. +func (sp *SchemaProxy) MarshalYAMLInline() (interface{}, error) { + var s *Schema + var err error + s, err = sp.BuildSchema() + if err != nil { + return nil, err + } + nb := high.NewNodeBuilder(s, s.low) + nb.Resolve = true + return nb.Render(), nil +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/high/base/security_requirement.go b/vendor/github.com/pb33f/libopenapi/datamodel/high/base/security_requirement.go new file mode 100644 index 0000000000..b96cae26d8 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/high/base/security_requirement.go @@ -0,0 +1,135 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package base + +import ( + "github.com/pb33f/libopenapi/datamodel/low" + "github.com/pb33f/libopenapi/datamodel/low/base" + "github.com/pb33f/libopenapi/utils" + "gopkg.in/yaml.v3" + "sort" +) + +// SecurityRequirement is a high-level representation of a Swagger / OpenAPI 3 SecurityRequirement object. +// +// SecurityRequirement lists the required security schemes to execute this operation. The object can have multiple +// security schemes declared in it which are all required (that is, there is a logical AND between the schemes). +// +// The name used for each property MUST correspond to a security scheme declared in the Security Definitions +// - https://swagger.io/specification/v2/#securityDefinitionsObject +type SecurityRequirement struct { + Requirements map[string][]string `json:"-" yaml:"-"` + low *base.SecurityRequirement +} + +// NewSecurityRequirement creates a new high-level SecurityRequirement from a low-level one. +func NewSecurityRequirement(req *base.SecurityRequirement) *SecurityRequirement { + r := new(SecurityRequirement) + r.low = req + values := make(map[string][]string) + // to keep things fast, avoiding copying anything - makes it a little hard to read. + for reqK := range req.Requirements.Value { + var vals []string + for valK := range req.Requirements.Value[reqK].Value { + vals = append(vals, req.Requirements.Value[reqK].Value[valK].Value) + } + values[reqK.Value] = vals + } + r.Requirements = values + return r +} + +// GoLow returns the low-level SecurityRequirement used to create the high-level one. +func (s *SecurityRequirement) GoLow() *base.SecurityRequirement { + return s.low +} + +// GoLowUntyped will return the low-level Discriminator instance that was used to create the high-level one, with no type +func (s *SecurityRequirement) GoLowUntyped() any { + return s.low +} + +// Render will return a YAML representation of the SecurityRequirement object as a byte slice. +func (s *SecurityRequirement) Render() ([]byte, error) { + return yaml.Marshal(s) +} + +// MarshalYAML will create a ready to render YAML representation of the SecurityRequirement object. +func (s *SecurityRequirement) MarshalYAML() (interface{}, error) { + + type req struct { + line int + key string + val []string + lowKey *low.KeyReference[string] + lowVal *low.ValueReference[[]low.ValueReference[string]] + } + + m := utils.CreateEmptyMapNode() + keys := make([]*req, len(s.Requirements)) + + i := 0 + + for k := range s.Requirements { + keys[i] = &req{key: k, val: s.Requirements[k]} + i++ + } + i = 0 + if s.low != nil { + for o := range keys { + kv := keys[o].key + for k := range s.low.Requirements.Value { + if k.Value == kv { + gh := s.low.Requirements.Value[k] + keys[o].line = k.KeyNode.Line + keys[o].lowKey = &k + keys[o].lowVal = &gh + } + i++ + } + } + } + sort.Slice(keys, func(i, j int) bool { + return keys[i].line < keys[j].line + }) + + for k := range keys { + l := utils.CreateStringNode(keys[k].key) + l.Line = keys[k].line + + // for each key, extract all the values and order them. + type req struct { + line int + val string + } + + reqs := make([]*req, len(keys[k].val)) + for t := range keys[k].val { + reqs[t] = &req{val: keys[k].val[t], line: 9999 + t} + if keys[k].lowVal != nil { + for _ = range keys[k].lowVal.Value[t].Value { + fh := keys[k].val[t] + df := keys[k].lowVal.Value[t].Value + if fh == df { + reqs[t].line = keys[k].lowVal.Value[t].ValueNode.Line + break + } + } + } + } + sort.Slice(reqs, func(i, j int) bool { + return reqs[i].line < reqs[j].line + }) + sn := utils.CreateEmptySequenceNode() + sn.Line = keys[k].line + 1 + for z := range reqs { + n := utils.CreateStringNode(reqs[z].val) + n.Line = reqs[z].line + 1 + sn.Content = append(sn.Content, n) + } + + m.Content = append(m.Content, l, sn) + } + return m, nil +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/high/base/tag.go b/vendor/github.com/pb33f/libopenapi/datamodel/high/base/tag.go new file mode 100644 index 0000000000..0b6bfcecce --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/high/base/tag.go @@ -0,0 +1,74 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package base + +import ( + "github.com/pb33f/libopenapi/datamodel/high" + low "github.com/pb33f/libopenapi/datamodel/low/base" + "gopkg.in/yaml.v3" +) + +// Tag represents a high-level Tag instance that is backed by a low-level one. +// +// Adds metadata to a single tag that is used by the Operation Object. It is not mandatory to have a Tag Object per +// tag defined in the Operation Object instances. +// - v2: https://swagger.io/specification/v2/#tagObject +// - v3: https://swagger.io/specification/#tag-object +type Tag struct { + Name string `json:"name,omitempty" yaml:"name,omitempty"` + Description string `json:"description,omitempty" yaml:"description,omitempty"` + ExternalDocs *ExternalDoc `json:"externalDocs,omitempty" yaml:"externalDocs,omitempty"` + Extensions map[string]any + low *low.Tag +} + +// NewTag creates a new high-level Tag instance that is backed by a low-level one. +func NewTag(tag *low.Tag) *Tag { + t := new(Tag) + t.low = tag + if !tag.Name.IsEmpty() { + t.Name = tag.Name.Value + } + if !tag.Description.IsEmpty() { + t.Description = tag.Description.Value + } + if !tag.ExternalDocs.IsEmpty() { + t.ExternalDocs = NewExternalDoc(tag.ExternalDocs.Value) + } + t.Extensions = high.ExtractExtensions(tag.Extensions) + return t +} + +// GoLow returns the low-level Tag instance used to create the high-level one. +func (t *Tag) GoLow() *low.Tag { + return t.low +} + +// GoLowUntyped will return the low-level Tag instance that was used to create the high-level one, with no type +func (t *Tag) GoLowUntyped() any { + return t.low +} + +// Render will return a YAML representation of the Info object as a byte slice. +func (t *Tag) Render() ([]byte, error) { + return yaml.Marshal(t) +} + +// Render will return a YAML representation of the Info object as a byte slice. +func (t *Tag) RenderInline() ([]byte, error) { + d, _ := t.MarshalYAMLInline() + return yaml.Marshal(d) +} + +// MarshalYAML will create a ready to render YAML representation of the Info object. +func (t *Tag) MarshalYAML() (interface{}, error) { + nb := high.NewNodeBuilder(t, t.low) + return nb.Render(), nil +} + +func (t *Tag) MarshalYAMLInline() (interface{}, error) { + nb := high.NewNodeBuilder(t, t.low) + nb.Resolve = true + return nb.Render(), nil +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/high/base/xml.go b/vendor/github.com/pb33f/libopenapi/datamodel/high/base/xml.go new file mode 100644 index 0000000000..d6596d35d1 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/high/base/xml.go @@ -0,0 +1,64 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package base + +import ( + "github.com/pb33f/libopenapi/datamodel/high" + low "github.com/pb33f/libopenapi/datamodel/low/base" + "gopkg.in/yaml.v3" +) + +// XML represents a high-level representation of an XML object defined by all versions of OpenAPI and backed by +// low-level XML object. +// +// A metadata object that allows for more fine-tuned XML model definitions. +// +// When using arrays, XML element names are not inferred (for singular/plural forms) and the name property SHOULD be +// used to add that information. See examples for expected behavior. +// v2 - https://swagger.io/specification/v2/#xmlObject +// v3 - https://swagger.io/specification/#xml-object +type XML struct { + Name string `json:"name,omitempty" yaml:"name,omitempty"` + Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"` + Prefix string `json:"prefix,omitempty" yaml:"prefix,omitempty"` + Attribute bool `json:"attribute,omitempty" yaml:"attribute,omitempty"` + Wrapped bool `json:"wrapped,omitempty" yaml:"wrapped,omitempty"` + Extensions map[string]any + low *low.XML +} + +// NewXML creates a new high-level XML instance from a low-level one. +func NewXML(xml *low.XML) *XML { + x := new(XML) + x.low = xml + x.Name = xml.Name.Value + x.Namespace = xml.Namespace.Value + x.Prefix = xml.Prefix.Value + x.Attribute = xml.Attribute.Value + x.Wrapped = xml.Wrapped.Value + x.Extensions = high.ExtractExtensions(xml.Extensions) + return x +} + +// GoLow returns the low level XML reference used to create the high level one. +func (x *XML) GoLow() *low.XML { + return x.low +} + +// GoLowUntyped will return the low-level XML instance that was used to create the high-level one, with no type +func (x *XML) GoLowUntyped() any { + return x.low +} + +// Render will return a YAML representation of the XML object as a byte slice. +func (x *XML) Render() ([]byte, error) { + return yaml.Marshal(x) +} + +// MarshalYAML will create a ready to render YAML representation of the XML object. +func (x *XML) MarshalYAML() (interface{}, error) { + nb := high.NewNodeBuilder(x, x.low) + return nb.Render(), nil +} + diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/high/node_builder.go b/vendor/github.com/pb33f/libopenapi/datamodel/high/node_builder.go new file mode 100644 index 0000000000..19eb1b3a15 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/high/node_builder.go @@ -0,0 +1,655 @@ +// Copyright 2023 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package high + +import ( + "fmt" + "github.com/pb33f/libopenapi/datamodel/low" + "github.com/pb33f/libopenapi/utils" + "gopkg.in/yaml.v3" + "reflect" + "sort" + "strconv" + "strings" + "unicode" +) + +// NodeEntry represents a single node used by NodeBuilder. +type NodeEntry struct { + Tag string + Key string + Value any + StringValue string + Line int + RenderZero bool +} + +// NodeBuilder is a structure used by libopenapi high-level objects, to render themselves back to YAML. +// this allows high-level objects to be 'mutable' because all changes will be rendered out. +type NodeBuilder struct { + Nodes []*NodeEntry + High any + Low any + Resolve bool // If set to true, all references will be rendered inline +} + +const renderZero = "renderZero" + +// NewNodeBuilder will create a new NodeBuilder instance, this is the only way to create a NodeBuilder. +// The function accepts a high level object and a low level object (need to be siblings/same type). +// +// Using reflection, a map of every field in the high level object is created, ready to be rendered. +func NewNodeBuilder(high any, low any) *NodeBuilder { + // create a new node builder + nb := new(NodeBuilder) + nb.High = high + if low != nil { + nb.Low = low + } + + // extract fields from the high level object and add them into our node builder. + // this will allow us to extract the line numbers from the low level object as well. + v := reflect.ValueOf(high).Elem() + num := v.NumField() + for i := 0; i < num; i++ { + nb.add(v.Type().Field(i).Name, i) + } + return nb +} + +func (n *NodeBuilder) add(key string, i int) { + + // only operate on exported fields. + if unicode.IsLower(rune(key[0])) { + return + } + + // if the key is 'Extensions' then we need to extract the keys from the map + // and add them to the node builder. + if key == "Extensions" { + extensions := reflect.ValueOf(n.High).Elem().FieldByName(key) + for b, e := range extensions.MapKeys() { + v := extensions.MapIndex(e) + + extKey := e.String() + extValue := v.Interface() + nodeEntry := &NodeEntry{Tag: extKey, Key: extKey, Value: extValue, Line: 9999 + b} + + if n.Low != nil && !reflect.ValueOf(n.Low).IsZero() { + fieldValue := reflect.ValueOf(n.Low).Elem().FieldByName("Extensions") + f := fieldValue.Interface() + value := reflect.ValueOf(f) + switch value.Kind() { + case reflect.Map: + if j, ok := n.Low.(low.HasExtensionsUntyped); ok { + originalExtensions := j.GetExtensions() + u := 0 + for k := range originalExtensions { + if k.Value == extKey { + if originalExtensions[k].ValueNode.Line != 0 { + nodeEntry.Line = originalExtensions[k].ValueNode.Line + u + } else { + nodeEntry.Line = 999999 + b + u + } + } + u++ + } + } + } + } + n.Nodes = append(n.Nodes, nodeEntry) + } + // done, extensions are handled separately. + return + } + + // find the field with the tag supplied. + field, _ := reflect.TypeOf(n.High).Elem().FieldByName(key) + tag := string(field.Tag.Get("yaml")) + tagName := strings.Split(tag, ",")[0] + + if tag == "-" { + return + } + + renderZeroVal := strings.Split(tag, ",")[1] + + // extract the value of the field + fieldValue := reflect.ValueOf(n.High).Elem().FieldByName(key) + f := fieldValue.Interface() + value := reflect.ValueOf(f) + + if renderZeroVal != renderZero && (f == nil || value.IsZero()) { + return + } + + // create a new node entry + nodeEntry := &NodeEntry{Tag: tagName, Key: key} + if renderZeroVal == renderZero { + nodeEntry.RenderZero = true + } + + switch value.Kind() { + case reflect.Float64, reflect.Float32: + nodeEntry.Value = value.Float() + x := float64(int(value.Float()*100)) / 100 // trim this down + nodeEntry.StringValue = strconv.FormatFloat(x, 'f', -1, 64) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + nodeEntry.Value = value.Int() + nodeEntry.StringValue = value.String() + case reflect.String: + nodeEntry.Value = value.String() + case reflect.Bool: + nodeEntry.Value = value.Bool() + case reflect.Slice: + if tagName == "type" { + if value.Len() == 1 { + nodeEntry.Value = value.Index(0).String() + } else { + nodeEntry.Value = f + } + } else { + if (renderZeroVal == renderZero) || (!value.IsNil() && !value.IsZero()) { + nodeEntry.Value = f + } + } + case reflect.Ptr: + if !value.IsNil() { + nodeEntry.Value = f + } + case reflect.Map: + if !value.IsNil() && value.Len() > 0 { + nodeEntry.Value = f + } + default: + nodeEntry.Value = f + } + + // if there is no low level object, then we cannot extract line numbers, + // so skip and default to 0, which means a new entry to the spec. + // this will place new content and the top of the rendered object. + if n.Low != nil && !reflect.ValueOf(n.Low).IsZero() { + lowFieldValue := reflect.ValueOf(n.Low).Elem().FieldByName(key) + fLow := lowFieldValue.Interface() + value = reflect.ValueOf(fLow) + switch value.Kind() { + + case reflect.Slice: + l := value.Len() + lines := make([]int, l) + for g := 0; g < l; g++ { + qw := value.Index(g).Interface() + if we, wok := qw.(low.HasKeyNode); wok { + lines[g] = we.GetKeyNode().Line + } + } + sort.Ints(lines) + nodeEntry.Line = lines[0] // pick the lowest line number so this key is sorted in order. + break + case reflect.Map: + + l := value.Len() + lines := make([]int, l) + for q, ky := range value.MapKeys() { + if we, wok := ky.Interface().(low.HasKeyNode); wok { + lines[q] = we.GetKeyNode().Line + } + } + sort.Ints(lines) + nodeEntry.Line = lines[0] // pick the lowest line number, sort in order + + case reflect.Struct: + y := value.Interface() + nodeEntry.Line = 9999 + i + if nb, ok := y.(low.HasValueNodeUntyped); ok { + if nb.IsReference() { + if jk, kj := y.(low.HasKeyNode); kj { + nodeEntry.Line = jk.GetKeyNode().Line + break + } + } + if nb.GetValueNode() != nil { + nodeEntry.Line = nb.GetValueNode().Line + } + } + default: + // everything else, weight it to the bottom of the rendered object. + // this is things that we have no way of knowing where they should be placed. + nodeEntry.Line = 9999 + i + } + } + if nodeEntry.Value != nil { + n.Nodes = append(n.Nodes, nodeEntry) + } +} + +func (n *NodeBuilder) renderReference() []*yaml.Node { + fg := n.Low.(low.IsReferenced) + nodes := make([]*yaml.Node, 2) + nodes[0] = utils.CreateStringNode("$ref") + nodes[1] = utils.CreateStringNode(fg.GetReference()) + return nodes +} + +// Render will render the NodeBuilder back to a YAML node, iterating over every NodeEntry defined +func (n *NodeBuilder) Render() *yaml.Node { + if len(n.Nodes) == 0 { + return utils.CreateEmptyMapNode() + } + + // order nodes by line number, retain original order + m := utils.CreateEmptyMapNode() + if fg, ok := n.Low.(low.IsReferenced); ok { + g := reflect.ValueOf(fg) + if !g.IsNil() { + if fg.IsReference() && !n.Resolve { + m.Content = append(m.Content, n.renderReference()...) + return m + } + } + } + + sort.Slice(n.Nodes, func(i, j int) bool { + if n.Nodes[i].Line != n.Nodes[j].Line { + return n.Nodes[i].Line < n.Nodes[j].Line + } + return false + }) + + for i := range n.Nodes { + node := n.Nodes[i] + n.AddYAMLNode(m, node) + } + return m +} + +// AddYAMLNode will add a new *yaml.Node to the parent node, using the tag, key and value provided. +// If the value is nil, then the node will not be added. This method is recursive, so it will dig down +// into any non-scalar types. +func (n *NodeBuilder) AddYAMLNode(parent *yaml.Node, entry *NodeEntry) *yaml.Node { + if entry.Value == nil { + return parent + } + + // check the type + t := reflect.TypeOf(entry.Value) + var l *yaml.Node + if entry.Tag != "" { + l = utils.CreateStringNode(entry.Tag) + } + + value := entry.Value + line := entry.Line + key := entry.Key + + var valueNode *yaml.Node + switch t.Kind() { + + case reflect.String: + val := value.(string) + valueNode = utils.CreateStringNode(val) + valueNode.Line = line + break + + case reflect.Bool: + val := value.(bool) + if !val { + valueNode = utils.CreateBoolNode("false") + } else { + valueNode = utils.CreateBoolNode("true") + } + valueNode.Line = line + break + + case reflect.Int: + val := strconv.Itoa(value.(int)) + valueNode = utils.CreateIntNode(val) + valueNode.Line = line + break + + case reflect.Int64: + val := strconv.FormatInt(value.(int64), 10) + valueNode = utils.CreateIntNode(val) + valueNode.Line = line + break + + case reflect.Float32: + val := strconv.FormatFloat(float64(value.(float32)), 'f', 2, 64) + valueNode = utils.CreateFloatNode(val) + valueNode.Line = line + break + + case reflect.Float64: + precision := -1 + if entry.StringValue != "" && strings.Contains(entry.StringValue, ".") { + precision = len(strings.Split(fmt.Sprint(entry.StringValue), ".")[1]) + } + val := strconv.FormatFloat(value.(float64), 'f', precision, 64) + valueNode = utils.CreateFloatNode(val) + valueNode.Line = line + break + + case reflect.Map: + + // the keys will be rendered randomly, if we don't find out the original line + // number of the tag. + + var orderedCollection []*NodeEntry + m := reflect.ValueOf(value) + for g, k := range m.MapKeys() { + var x string + // extract key + yu := k.Interface() + if o, ok := yu.(low.HasKeyNode); ok { + x = o.GetKeyNode().Value + } else { + x = k.String() + } + + // go low and pull out the line number. + lowProps := reflect.ValueOf(n.Low) + if n.Low != nil && !lowProps.IsZero() && !lowProps.IsNil() { + gu := lowProps.Elem() + gi := gu.FieldByName(key) + jl := reflect.ValueOf(gi) + if !jl.IsZero() && gi.Interface() != nil { + gh := gi.Interface() + // extract low level key line number + if pr, ok := gh.(low.HasValueUnTyped); ok { + fg := reflect.ValueOf(pr.GetValueUntyped()) + found := false + found, orderedCollection = n.extractLowMapKeys(fg, x, found, orderedCollection, m, k) + if found != true { + // this is something new, add it. + orderedCollection = append(orderedCollection, &NodeEntry{ + Tag: x, + Key: x, + Line: 9999 + g, + Value: m.MapIndex(k).Interface(), + }) + } + } else { + // this is a map, but it may be wrapped still. + bj := reflect.ValueOf(gh) + orderedCollection = n.extractLowMapKeysWrapped(bj, x, orderedCollection, g) + } + } else { + // this is a map, without any low level details available (probably an extension map). + orderedCollection = append(orderedCollection, &NodeEntry{ + Tag: x, + Key: x, + Line: 9999 + g, + Value: m.MapIndex(k).Interface(), + }) + } + } else { + // this is a map, without any low level details available (probably an extension map). + orderedCollection = append(orderedCollection, &NodeEntry{ + Tag: x, + Key: x, + Line: 9999 + g, + Value: m.MapIndex(k).Interface(), + }) + } + } + + // sort the slice by line number to ensure everything is rendered in order. + sort.Slice(orderedCollection, func(i, j int) bool { + return orderedCollection[i].Line < orderedCollection[j].Line + }) + + // create an empty map. + p := utils.CreateEmptyMapNode() + + // build out each map node in original order. + for _, cv := range orderedCollection { + n.AddYAMLNode(p, cv) + } + if len(p.Content) > 0 { + valueNode = p + } + + case reflect.Slice: + + var rawNode yaml.Node + m := reflect.ValueOf(value) + sl := utils.CreateEmptySequenceNode() + skip := false + for i := 0; i < m.Len(); i++ { + sqi := m.Index(i).Interface() + // check if this is a reference. + if glu, ok := sqi.(GoesLowUntyped); ok { + if glu != nil { + ut := glu.GoLowUntyped() + if !reflect.ValueOf(ut).IsNil() { + r := ut.(low.IsReferenced) + if ut != nil && r.GetReference() != "" && + ut.(low.IsReferenced).IsReference() { + if !n.Resolve { + refNode := utils.CreateRefNode(glu.GoLowUntyped().(low.IsReferenced).GetReference()) + sl.Content = append(sl.Content, refNode) + skip = true + } else { + skip = false + } + } else { + skip = false + } + } + } + } + if !skip { + if er, ko := sqi.(Renderable); ko { + var rend interface{} + if !n.Resolve { + rend, _ = er.(Renderable).MarshalYAML() + } else { + // try and render inline, if we can, otherwise treat as normal. + if _, ko := er.(RenderableInline); ko { + rend, _ = er.(RenderableInline).MarshalYAMLInline() + } else { + rend, _ = er.(Renderable).MarshalYAML() + } + } + // check if this is a pointer or not. + if _, ok := rend.(*yaml.Node); ok { + sl.Content = append(sl.Content, rend.(*yaml.Node)) + } + if _, ok := rend.(yaml.Node); ok { + k := rend.(yaml.Node) + sl.Content = append(sl.Content, &k) + } + } + } + } + + if len(sl.Content) > 0 { + valueNode = sl + break + } + if skip { + break + } + + err := rawNode.Encode(value) + if err != nil { + return parent + } else { + valueNode = &rawNode + } + + case reflect.Struct: + if r, ok := value.(low.ValueReference[any]); ok { + valueNode = r.GetValueNode() + break + } + if r, ok := value.(low.ValueReference[string]); ok { + valueNode = r.GetValueNode() + break + } + if r, ok := value.(low.NodeReference[string]); ok { + valueNode = r.GetValueNode() + break + } + return parent + + case reflect.Ptr: + if r, ok := value.(Renderable); ok { + if gl, lg := value.(GoesLowUntyped); lg { + if gl.GoLowUntyped() != nil { + ut := reflect.ValueOf(gl.GoLowUntyped()) + if !ut.IsNil() { + if gl.GoLowUntyped().(low.IsReferenced).IsReference() { + if !n.Resolve { + // TODO: use renderReference here. + rvn := utils.CreateEmptyMapNode() + rvn.Content = append(rvn.Content, utils.CreateStringNode("$ref")) + rvn.Content = append(rvn.Content, utils.CreateStringNode(gl.GoLowUntyped().(low.IsReferenced).GetReference())) + valueNode = rvn + break + } + } + } + } + } + var rawRender interface{} + if !n.Resolve { + rawRender, _ = r.MarshalYAML() + } else { + // try an inline render if we can, otherwise there is no option but to default to the + // full render. + if _, ko := r.(RenderableInline); ko { + rawRender, _ = r.(RenderableInline).MarshalYAMLInline() + } else { + rawRender, _ = r.MarshalYAML() + } + } + if rawRender != nil { + if _, ko := rawRender.(*yaml.Node); ko { + valueNode = rawRender.(*yaml.Node) + } + if _, ko := rawRender.(yaml.Node); ko { + d := rawRender.(yaml.Node) + valueNode = &d + } + } + } else { + + encodeSkip := false + // check if the value is a bool, int or float + if b, bok := value.(*bool); bok { + encodeSkip = true + if *b { + valueNode = utils.CreateBoolNode("true") + valueNode.Line = line + } else { + if entry.RenderZero { + valueNode = utils.CreateBoolNode("false") + valueNode.Line = line + } + } + } + if b, bok := value.(*int64); bok { + encodeSkip = true + if *b > 0 { + valueNode = utils.CreateIntNode(strconv.Itoa(int(*b))) + valueNode.Line = line + } + } + if b, bok := value.(*float64); bok { + encodeSkip = true + if *b > 0 { + valueNode = utils.CreateFloatNode(strconv.FormatFloat(*b, 'f', -1, 64)) + valueNode.Line = line + } + } + if !encodeSkip { + var rawNode yaml.Node + err := rawNode.Encode(value) + if err != nil { + return parent + } else { + valueNode = &rawNode + valueNode.Line = line + } + } + } + + } + if valueNode == nil { + return parent + } + if l != nil { + parent.Content = append(parent.Content, l, valueNode) + } else { + parent.Content = valueNode.Content + } + return parent +} + +func (n *NodeBuilder) extractLowMapKeysWrapped(iu reflect.Value, x string, orderedCollection []*NodeEntry, g int) []*NodeEntry { + for _, ky := range iu.MapKeys() { + ty := ky.Interface() + if ere, eok := ty.(low.HasKeyNode); eok { + er := ere.GetKeyNode().Value + if er == x { + orderedCollection = append(orderedCollection, &NodeEntry{ + Tag: x, + Key: x, + Line: ky.Interface().(low.HasKeyNode).GetKeyNode().Line, + Value: iu.MapIndex(ky).Interface(), + }) + } + } else { + orderedCollection = append(orderedCollection, &NodeEntry{ + Tag: x, + Key: x, + Line: 9999 + g, + Value: iu.MapIndex(ky).Interface(), + }) + } + } + return orderedCollection +} + +func (n *NodeBuilder) extractLowMapKeys(fg reflect.Value, x string, found bool, orderedCollection []*NodeEntry, m reflect.Value, k reflect.Value) (bool, []*NodeEntry) { + for j, ky := range fg.MapKeys() { + hu := ky.Interface() + if we, wok := hu.(low.HasKeyNode); wok { + er := we.GetKeyNode().Value + if er == x { + found = true + orderedCollection = append(orderedCollection, &NodeEntry{ + Tag: x, + Key: x, + Line: we.GetKeyNode().Line, + Value: m.MapIndex(k).Interface(), + }) + } + } else { + uu := ky.Interface() + if uu == x { + // this is a map, without any low level details available + found = true + orderedCollection = append(orderedCollection, &NodeEntry{ + Tag: uu.(string), + Key: uu.(string), + Line: 9999 + j, + Value: m.MapIndex(k).Interface(), + }) + } + } + } + return found, orderedCollection +} + +// Renderable is an interface that can be implemented by types that provide a custom MarshaYAML method. +type Renderable interface { + MarshalYAML() (interface{}, error) +} + +// RenderableInline is an interface that can be implemented by types that provide a custom MarshaYAML method. +type RenderableInline interface { + MarshalYAMLInline() (interface{}, error) +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/high/shared.go b/vendor/github.com/pb33f/libopenapi/datamodel/high/shared.go new file mode 100644 index 0000000000..24bce080ae --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/high/shared.go @@ -0,0 +1,78 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +// Package high contains a set of high-level models that represent OpenAPI 2 and 3 documents. +// These high-level models (porcelain) are used by applications directly, rather than the low-level models +// plumbing) that are used to compose high level models. +// +// High level models are simple to navigate, strongly typed, precise representations of the OpenAPI schema +// that are created from an OpenAPI specification. +// +// All high level objects contains a 'GoLow' method. This 'GoLow' method will return the low-level model that +// was used to create it, which provides an engineer as much low level detail about the raw spec used to create +// those models, things like key/value breakdown of each value, lines, column, source comments etc. +package high + +import ( + "github.com/pb33f/libopenapi/datamodel/low" +) + +// GoesLow is used to represent any high-level model. All high level models meet this interface and can be used to +// extract low-level models from any high-level model. +type GoesLow[T any] interface { + + // GoLow returns the low-level object that was used to create the high-level object. This allows consumers + // to dive-down into the plumbing API at any point in the model. + GoLow() T +} + +// GoesLowUnTyped is used to represent any high-level model. All high level models meet this interface and can be used to +// extract low-level models from any high-level model. +type GoesLowUntyped interface { + + // GoLow returns the low-level object that was used to create the high-level object. This allows consumers + // to dive-down into the plumbing API at any point in the model. + GoLowUntyped() any +} + +// ExtractExtensions is a convenience method for converting low-level extension definitions, to a high level map[string]any +// definition that is easier to consume in applications. +func ExtractExtensions(extensions map[low.KeyReference[string]]low.ValueReference[any]) map[string]any { + extracted := make(map[string]any) + for k, v := range extensions { + extracted[k.Value] = v.Value + } + return extracted +} + +// UnpackExtensions is a convenience function that makes it easy and simple to unpack an objects extensions +// into a complex type, provided as a generic. This function is for high-level models that implement `GoesLow()` +// and for low-level models that support extensions via `HasExtensions`. +// +// This feature will be upgraded at some point to hold a registry of types and extension mappings to make this +// functionality available a little more automatically. +// You can read more about the discussion here: https://github.com/pb33f/libopenapi/issues/8 +// +// `T` represents the Type you want to unpack into +// `R` represents the LOW type of the object that contains the extensions (not the high) +// `low` represents the HIGH type of the object that contains the extensions. +// +// to use: +// schema := schemaProxy.Schema() // any high-level object that has extensions +// extensions, err := UnpackExtensions[MyComplexType, low.Schema](schema) +func UnpackExtensions[T any, R low.HasExtensions[T]](low GoesLow[R]) (map[string]*T, error) { + m := make(map[string]*T) + ext := low.GoLow().GetExtensions() + for i := range ext { + key := i.Value + g := new(T) + valueNode := ext[i].ValueNode + err := valueNode.Decode(g) + if err != nil { + return nil, err + } + m[key] = g + } + return m, nil +} + diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/high/v2/definitions.go b/vendor/github.com/pb33f/libopenapi/datamodel/high/v2/definitions.go new file mode 100644 index 0000000000..ae1e247da4 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/high/v2/definitions.go @@ -0,0 +1,40 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package v2 + +import ( + highbase "github.com/pb33f/libopenapi/datamodel/high/base" + lowmodel "github.com/pb33f/libopenapi/datamodel/low" + lowbase "github.com/pb33f/libopenapi/datamodel/low/base" + low "github.com/pb33f/libopenapi/datamodel/low/v2" +) + +// Definitions is a high-level represents of a Swagger / OpenAPI 2 Definitions object, backed by a low-level one. +// +// An object to hold data types that can be consumed and produced by operations. These data types can be primitives, +// arrays or models. +// - https://swagger.io/specification/v2/#definitionsObject +type Definitions struct { + Definitions map[string]*highbase.SchemaProxy + low *low.Definitions +} + +// NewDefinitions will create a new high-level instance of a Definition from a low-level one. +func NewDefinitions(definitions *low.Definitions) *Definitions { + rd := new(Definitions) + rd.low = definitions + defs := make(map[string]*highbase.SchemaProxy) + for k := range definitions.Schemas { + defs[k.Value] = highbase.NewSchemaProxy(&lowmodel.NodeReference[*lowbase.SchemaProxy]{ + Value: definitions.Schemas[k].Value, + }) + } + rd.Definitions = defs + return rd +} + +// GoLow returns the low-level Definitions object used to create the high-level one. +func (d *Definitions) GoLow() *low.Definitions { + return d.low +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/high/v2/examples.go b/vendor/github.com/pb33f/libopenapi/datamodel/high/v2/examples.go new file mode 100644 index 0000000000..d863a16cae --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/high/v2/examples.go @@ -0,0 +1,33 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package v2 + +import low "github.com/pb33f/libopenapi/datamodel/low/v2" + +// Example represents a high-level Swagger / OpenAPI 2 Example object, backed by a low level one. +// Allows sharing examples for operation responses +// - https://swagger.io/specification/v2/#exampleObject +type Example struct { + Values map[string]any + low *low.Examples +} + +// NewExample creates a new high-level Example instance from a low-level one. +func NewExample(examples *low.Examples) *Example { + e := new(Example) + e.low = examples + if len(examples.Values) > 0 { + values := make(map[string]any) + for k := range examples.Values { + values[k.Value] = examples.Values[k].Value + } + e.Values = values + } + return e +} + +// GoLow returns the low-level Example used to create the high-level one. +func (e *Example) GoLow() *low.Examples { + return e.low +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/high/v2/header.go b/vendor/github.com/pb33f/libopenapi/datamodel/high/v2/header.go new file mode 100644 index 0000000000..157f834917 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/high/v2/header.go @@ -0,0 +1,106 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package v2 + +import ( + "github.com/pb33f/libopenapi/datamodel/high" + low "github.com/pb33f/libopenapi/datamodel/low/v2" +) + +// Header Represents a high-level Swagger / OpenAPI 2 Header object, backed by a low-level one. +// A Header is essentially identical to a Parameter, except it does not contain 'name' or 'in' properties. +// - https://swagger.io/specification/v2/#headerObject +type Header struct { + Type string + Format string + Description string + Items *Items + CollectionFormat string + Default any + Maximum int + ExclusiveMaximum bool + Minimum int + ExclusiveMinimum bool + MaxLength int + MinLength int + Pattern string + MaxItems int + MinItems int + UniqueItems bool + Enum []any + MultipleOf int + Extensions map[string]any + low *low.Header +} + +// NewHeader will create a new high-level Swagger / OpenAPI 2 Header instance, from a low-level one. +func NewHeader(header *low.Header) *Header { + h := new(Header) + h.low = header + h.Extensions = high.ExtractExtensions(header.Extensions) + if !header.Type.IsEmpty() { + h.Type = header.Type.Value + } + if !header.Format.IsEmpty() { + h.Format = header.Type.Value + } + if !header.Description.IsEmpty() { + h.Description = header.Description.Value + } + if !header.Items.IsEmpty() { + h.Items = NewItems(header.Items.Value) + } + if !header.CollectionFormat.IsEmpty() { + h.CollectionFormat = header.CollectionFormat.Value + } + if !header.Default.IsEmpty() { + h.Default = header.Default.Value + } + if !header.Maximum.IsEmpty() { + h.Maximum = header.Maximum.Value + } + if !header.ExclusiveMaximum.IsEmpty() { + h.ExclusiveMaximum = header.ExclusiveMaximum.Value + } + if !header.Minimum.IsEmpty() { + h.Minimum = header.Minimum.Value + } + if !header.ExclusiveMinimum.Value { + h.ExclusiveMinimum = header.ExclusiveMinimum.Value + } + if !header.MaxLength.IsEmpty() { + h.MaxLength = header.MaxLength.Value + } + if !header.MinLength.IsEmpty() { + h.MinLength = header.MinLength.Value + } + if !header.Pattern.IsEmpty() { + h.Pattern = header.Pattern.Value + } + if !header.MinItems.IsEmpty() { + h.MinItems = header.MinItems.Value + } + if !header.MaxItems.IsEmpty() { + h.MaxItems = header.MaxItems.Value + } + if !header.UniqueItems.IsEmpty() { + h.UniqueItems = header.UniqueItems.IsEmpty() + } + if !header.Enum.IsEmpty() { + var enums []any + for e := range header.Enum.Value { + enums = append(enums, header.Enum.Value[e].Value) + } + h.Enum = enums + } + if !header.MultipleOf.IsEmpty() { + h.MultipleOf = header.MultipleOf.Value + } + return h +} + +// GoLow returns the low-level header used to create the high-level one. +func (h *Header) GoLow() *low.Header { + return h.low +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/high/v2/items.go b/vendor/github.com/pb33f/libopenapi/datamodel/high/v2/items.go new file mode 100644 index 0000000000..cb07b53ee9 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/high/v2/items.go @@ -0,0 +1,100 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package v2 + +import ( + low "github.com/pb33f/libopenapi/datamodel/low/v2" +) + +// Items is a high-level representation of a Swagger / OpenAPI 2 Items object, backed by a low level one. +// Items is a limited subset of JSON-Schema's items object. It is used by parameter definitions that are not +// located in "body" +// - https://swagger.io/specification/v2/#itemsObject +type Items struct { + Type string + Format string + CollectionFormat string + Items *Items + Default any + Maximum int + ExclusiveMaximum bool + Minimum int + ExclusiveMinimum bool + MaxLength int + MinLength int + Pattern string + MaxItems int + MinItems int + UniqueItems bool + Enum []any + MultipleOf int + low *low.Items +} + +// NewItems creates a new high-level Items instance from a low-level one. +func NewItems(items *low.Items) *Items { + i := new(Items) + i.low = items + if !items.Type.IsEmpty() { + i.Type = items.Type.Value + } + if !items.Format.IsEmpty() { + i.Format = items.Format.Value + } + if !items.Items.IsEmpty() { + i.Items = NewItems(items.Items.Value) + } + if !items.CollectionFormat.IsEmpty() { + i.CollectionFormat = items.CollectionFormat.Value + } + if !items.Default.IsEmpty() { + i.Default = items.Default.Value + } + if !items.Maximum.IsEmpty() { + i.Maximum = items.Maximum.Value + } + if !items.ExclusiveMaximum.IsEmpty() { + i.ExclusiveMaximum = items.ExclusiveMaximum.Value + } + if !items.Minimum.IsEmpty() { + i.Minimum = items.Minimum.Value + } + if !items.ExclusiveMinimum.IsEmpty() { + i.ExclusiveMinimum = items.ExclusiveMinimum.Value + } + if !items.MaxLength.IsEmpty() { + i.MaxLength = items.MaxLength.Value + } + if !items.MinLength.IsEmpty() { + i.MinLength = items.MinLength.Value + } + if !items.Pattern.IsEmpty() { + i.Pattern = items.Pattern.Value + } + if !items.MinItems.IsEmpty() { + i.MinItems = items.MinItems.Value + } + if !items.MaxItems.IsEmpty() { + i.MaxItems = items.MaxItems.Value + } + if !items.UniqueItems.IsEmpty() { + i.UniqueItems = items.UniqueItems.Value + } + if !items.Enum.IsEmpty() { + var enums []any + for e := range items.Enum.Value { + enums = append(enums, items.Enum.Value[e].Value) + } + i.Enum = enums + } + if !items.MultipleOf.IsEmpty() { + i.MultipleOf = items.MultipleOf.Value + } + return i +} + +// GoLow returns the low-level Items object that was used to create the high-level one. +func (i *Items) GoLow() *low.Items { + return i.low +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/high/v2/operation.go b/vendor/github.com/pb33f/libopenapi/datamodel/high/v2/operation.go new file mode 100644 index 0000000000..8dbccb7657 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/high/v2/operation.go @@ -0,0 +1,103 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package v2 + +import ( + "github.com/pb33f/libopenapi/datamodel/high" + "github.com/pb33f/libopenapi/datamodel/high/base" + low "github.com/pb33f/libopenapi/datamodel/low/v2" +) + +// Operation represents a high-level Swagger / OpenAPI 2 Operation object, backed by a low-level one. +// It describes a single API operation on a path. +// - https://swagger.io/specification/v2/#operationObject +type Operation struct { + Tags []string + Summary string + Description string + ExternalDocs *base.ExternalDoc + OperationId string + Consumes []string + Produces []string + Parameters []*Parameter + Responses *Responses + Schemes []string + Deprecated bool + Security []*base.SecurityRequirement + Extensions map[string]any + low *low.Operation +} + +// NewOperation creates a new high-level Operation instance from a low-level one. +func NewOperation(operation *low.Operation) *Operation { + o := new(Operation) + o.low = operation + o.Extensions = high.ExtractExtensions(operation.Extensions) + if !operation.Tags.IsEmpty() { + var tags []string + for t := range operation.Tags.Value { + tags = append(tags, operation.Tags.Value[t].Value) + } + o.Tags = tags + } + if !operation.Summary.IsEmpty() { + o.Summary = operation.Summary.Value + } + if !operation.Description.IsEmpty() { + o.Description = operation.Description.Value + } + if !operation.ExternalDocs.IsEmpty() { + o.ExternalDocs = base.NewExternalDoc(operation.ExternalDocs.Value) + } + if !operation.OperationId.IsEmpty() { + o.OperationId = operation.OperationId.Value + } + if !operation.Consumes.IsEmpty() { + var cons []string + for c := range operation.Consumes.Value { + cons = append(cons, operation.Consumes.Value[c].Value) + } + o.Consumes = cons + } + if !operation.Produces.IsEmpty() { + var prods []string + for p := range operation.Produces.Value { + prods = append(prods, operation.Produces.Value[p].Value) + } + o.Produces = prods + } + if !operation.Parameters.IsEmpty() { + var params []*Parameter + for p := range operation.Parameters.Value { + params = append(params, NewParameter(operation.Parameters.Value[p].Value)) + } + o.Parameters = params + } + if !operation.Responses.IsEmpty() { + o.Responses = NewResponses(operation.Responses.Value) + } + if !operation.Schemes.IsEmpty() { + var schemes []string + for s := range operation.Schemes.Value { + schemes = append(schemes, operation.Schemes.Value[s].Value) + } + o.Schemes = schemes + } + if !operation.Deprecated.IsEmpty() { + o.Deprecated = operation.Deprecated.Value + } + if !operation.Security.IsEmpty() { + var sec []*base.SecurityRequirement + for s := range operation.Security.Value { + sec = append(sec, base.NewSecurityRequirement(operation.Security.Value[s].Value)) + } + o.Security = sec + } + return o +} + +// GoLow returns the low-level operation used to create the high-level one. +func (o *Operation) GoLow() *low.Operation { + return o.low +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/high/v2/parameter.go b/vendor/github.com/pb33f/libopenapi/datamodel/high/v2/parameter.go new file mode 100644 index 0000000000..e233274a3f --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/high/v2/parameter.go @@ -0,0 +1,155 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package v2 + +import ( + "github.com/pb33f/libopenapi/datamodel/high" + "github.com/pb33f/libopenapi/datamodel/high/base" + low "github.com/pb33f/libopenapi/datamodel/low/v2" +) + +// Parameter represents a high-level Swagger / OpenAPI 2 Parameter object, backed by a low-level one. +// +// A unique parameter is defined by a combination of a name and location. +// +// There are five possible parameter types. +// +// Path +// Used together with Path Templating, where the parameter value is actually part of the operation's URL. +// This does not include the host or base path of the API. For example, in /items/{itemId}, the path parameter is itemId. +// Query +// Parameters that are appended to the URL. For example, in /items?id=###, the query parameter is id. +// Header +// Custom headers that are expected as part of the request. +// Body +// The payload that's appended to the HTTP request. Since there can only be one payload, there can only be one body parameter. +// The name of the body parameter has no effect on the parameter itself and is used for documentation purposes only. +// Since Form parameters are also in the payload, body and form parameters cannot exist together for the same operation. +// Form +// Used to describe the payload of an HTTP request when either application/x-www-form-urlencoded, multipart/form-data +// or both are used as the content type of the request (in Swagger's definition, the consumes property of an operation). +// This is the only parameter type that can be used to send files, thus supporting the file type. Since form parameters +// are sent in the payload, they cannot be declared together with a body parameter for the same operation. Form +// parameters have a different format based on the content-type used (for further details, +// consult http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4): +// application/x-www-form-urlencoded - Similar to the format of Query parameters but as a payload. For example, +// foo=1&bar=swagger - both foo and bar are form parameters. This is normally used for simple parameters that are +// being transferred. +// multipart/form-data - each parameter takes a section in the payload with an internal header. For example, for +// the header Content-Disposition: form-data; name="submit-name" the name of the parameter is +// submit-name. This type of form parameters is more commonly used for file transfers +// https://swagger.io/specification/v2/#parameterObject +type Parameter struct { + Name string + In string + Type string + Format string + Description string + Required *bool + AllowEmptyValue *bool + Schema *base.SchemaProxy + Items *Items + CollectionFormat string + Default any + Maximum *int + ExclusiveMaximum *bool + Minimum *int + ExclusiveMinimum *bool + MaxLength *int + MinLength *int + Pattern string + MaxItems *int + MinItems *int + UniqueItems *bool + Enum []any + MultipleOf *int + Extensions map[string]any + low *low.Parameter +} + +// NewParameter creates a new high-level instance of a Parameter from a low-level one. +func NewParameter(parameter *low.Parameter) *Parameter { + p := new(Parameter) + p.low = parameter + p.Extensions = high.ExtractExtensions(parameter.Extensions) + if !parameter.Name.IsEmpty() { + p.Name = parameter.Name.Value + } + if !parameter.In.IsEmpty() { + p.In = parameter.In.Value + } + if !parameter.Type.IsEmpty() { + p.Type = parameter.Type.Value + } + if !parameter.Format.IsEmpty() { + p.Format = parameter.Format.Value + } + if !parameter.Description.IsEmpty() { + p.Description = parameter.Description.Value + } + if !parameter.Required.IsEmpty() { + p.Required = ¶meter.Required.Value + } + if !parameter.AllowEmptyValue.IsEmpty() { + p.AllowEmptyValue = ¶meter.AllowEmptyValue.Value + } + if !parameter.Schema.IsEmpty() { + p.Schema = base.NewSchemaProxy(¶meter.Schema) + } + if !parameter.Items.IsEmpty() { + p.Items = NewItems(parameter.Items.Value) + } + if !parameter.CollectionFormat.IsEmpty() { + p.CollectionFormat = parameter.CollectionFormat.Value + } + if !parameter.Default.IsEmpty() { + p.Default = parameter.Default.Value + } + if !parameter.Maximum.IsEmpty() { + p.Maximum = ¶meter.Maximum.Value + } + if !parameter.ExclusiveMaximum.IsEmpty() { + p.ExclusiveMaximum = ¶meter.ExclusiveMaximum.Value + } + if !parameter.Minimum.IsEmpty() { + p.Minimum = ¶meter.Minimum.Value + } + if !parameter.ExclusiveMinimum.IsEmpty() { + p.ExclusiveMinimum = ¶meter.ExclusiveMinimum.Value + } + if !parameter.MaxLength.IsEmpty() { + p.MaxLength = ¶meter.MaxLength.Value + } + if !parameter.MinLength.IsEmpty() { + p.MinLength = ¶meter.MinLength.Value + } + if !parameter.Pattern.IsEmpty() { + p.Pattern = parameter.Pattern.Value + } + if !parameter.MinItems.IsEmpty() { + p.MinItems = ¶meter.MinItems.Value + } + if !parameter.MaxItems.IsEmpty() { + p.MaxItems = ¶meter.MaxItems.Value + } + if !parameter.UniqueItems.IsEmpty() { + p.UniqueItems = ¶meter.UniqueItems.Value + } + if !parameter.Enum.IsEmpty() { + var enums []any + for e := range parameter.Enum.Value { + enums = append(enums, parameter.Enum.Value[e].Value) + } + p.Enum = enums + } + if !parameter.MultipleOf.IsEmpty() { + p.MultipleOf = ¶meter.MultipleOf.Value + } + return p +} + +// GoLow returns the low-level Parameter used to create the high-level one. +func (p *Parameter) GoLow() *low.Parameter { + return p.low +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/high/v2/parameter_definitions.go b/vendor/github.com/pb33f/libopenapi/datamodel/high/v2/parameter_definitions.go new file mode 100644 index 0000000000..0544edcb9a --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/high/v2/parameter_definitions.go @@ -0,0 +1,51 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package v2 + +import low "github.com/pb33f/libopenapi/datamodel/low/v2" + +// ParameterDefinitions is a high-level representation of a Swagger / OpenAPI 2 Parameters Definitions object +// that is backed by a low-level one. +// +// ParameterDefinitions holds parameters to be reused across operations. Parameter definitions can be +// referenced to the ones defined here. It does not define global operation parameters +// - https://swagger.io/specification/v2/#parametersDefinitionsObject +type ParameterDefinitions struct { + Definitions map[string]*Parameter + low *low.ParameterDefinitions +} + +// NewParametersDefinitions creates a new instance of a high-level ParameterDefinitions, from a low-level one. +// Every parameter is extracted asynchronously due to the potential depth +func NewParametersDefinitions(parametersDefinitions *low.ParameterDefinitions) *ParameterDefinitions { + pd := new(ParameterDefinitions) + pd.low = parametersDefinitions + params := make(map[string]*Parameter) + var buildParam = func(name string, param *low.Parameter, rChan chan<- asyncResult[*Parameter]) { + rChan <- asyncResult[*Parameter]{ + key: name, + result: NewParameter(param), + } + } + resChan := make(chan asyncResult[*Parameter]) + for k := range parametersDefinitions.Definitions { + go buildParam(k.Value, parametersDefinitions.Definitions[k].Value, resChan) + } + totalParams := len(parametersDefinitions.Definitions) + completedParams := 0 + for completedParams < totalParams { + select { + case r := <-resChan: + completedParams++ + params[r.key] = r.result + } + } + pd.Definitions = params + return pd +} + +// GoLow returns the low-level ParameterDefinitions instance that backs the low-level one. +func (p *ParameterDefinitions) GoLow() *low.ParameterDefinitions { + return p.low +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/high/v2/path_item.go b/vendor/github.com/pb33f/libopenapi/datamodel/high/v2/path_item.go new file mode 100644 index 0000000000..eda52dc012 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/high/v2/path_item.go @@ -0,0 +1,140 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package v2 + +import ( + "github.com/pb33f/libopenapi/datamodel/high" + low "github.com/pb33f/libopenapi/datamodel/low/v2" +) + +// PathItem represents a high-level Swagger / OpenAPI 2 PathItem object backed by a low-level one. +// +// Describes the operations available on a single path. A Path Item may be empty, due to ACL constraints. +// The path itself is still exposed to the tooling, but will not know which operations and parameters +// are available. +// - https://swagger.io/specification/v2/#pathItemObject +type PathItem struct { + Ref string + Get *Operation + Put *Operation + Post *Operation + Delete *Operation + Options *Operation + Head *Operation + Patch *Operation + Parameters []*Parameter + Extensions map[string]any + low *low.PathItem +} + +// NewPathItem will create a new high-level PathItem from a low-level one. All paths are built out asynchronously. +func NewPathItem(pathItem *low.PathItem) *PathItem { + p := new(PathItem) + p.low = pathItem + p.Extensions = high.ExtractExtensions(pathItem.Extensions) + if !pathItem.Parameters.IsEmpty() { + var params []*Parameter + for k := range pathItem.Parameters.Value { + params = append(params, NewParameter(pathItem.Parameters.Value[k].Value)) + } + p.Parameters = params + } + var buildOperation = func(method string, op *low.Operation, resChan chan<- asyncResult[*Operation]) { + resChan <- asyncResult[*Operation]{ + key: method, + result: NewOperation(op), + } + } + totalOperations := 0 + resChan := make(chan asyncResult[*Operation]) + if !pathItem.Get.IsEmpty() { + totalOperations++ + go buildOperation(low.GetLabel, pathItem.Get.Value, resChan) + } + if !pathItem.Put.IsEmpty() { + totalOperations++ + go buildOperation(low.PutLabel, pathItem.Put.Value, resChan) + } + if !pathItem.Post.IsEmpty() { + totalOperations++ + go buildOperation(low.PostLabel, pathItem.Post.Value, resChan) + } + if !pathItem.Patch.IsEmpty() { + totalOperations++ + go buildOperation(low.PatchLabel, pathItem.Patch.Value, resChan) + } + if !pathItem.Delete.IsEmpty() { + totalOperations++ + go buildOperation(low.DeleteLabel, pathItem.Delete.Value, resChan) + } + if !pathItem.Head.IsEmpty() { + totalOperations++ + go buildOperation(low.HeadLabel, pathItem.Head.Value, resChan) + } + if !pathItem.Options.IsEmpty() { + totalOperations++ + go buildOperation(low.OptionsLabel, pathItem.Options.Value, resChan) + } + completedOperations := 0 + for completedOperations < totalOperations { + select { + case r := <-resChan: + switch r.key { + case low.GetLabel: + completedOperations++ + p.Get = r.result + case low.PutLabel: + completedOperations++ + p.Put = r.result + case low.PostLabel: + completedOperations++ + p.Post = r.result + case low.PatchLabel: + completedOperations++ + p.Patch = r.result + case low.DeleteLabel: + completedOperations++ + p.Delete = r.result + case low.HeadLabel: + completedOperations++ + p.Head = r.result + case low.OptionsLabel: + completedOperations++ + p.Options = r.result + } + } + } + return p +} + +// GoLow returns the low-level PathItem used to create the high-level one. +func (p *PathItem) GoLow() *low.PathItem { + return p.low +} + +func (p *PathItem) GetOperations() map[string]*Operation { + o := make(map[string]*Operation) + if p.Get != nil { + o[low.GetLabel] = p.Get + } + if p.Put != nil { + o[low.PutLabel] = p.Put + } + if p.Post != nil { + o[low.PostLabel] = p.Post + } + if p.Delete != nil { + o[low.DeleteLabel] = p.Delete + } + if p.Options != nil { + o[low.OptionsLabel] = p.Options + } + if p.Head != nil { + o[low.HeadLabel] = p.Head + } + if p.Patch != nil { + o[low.PatchLabel] = p.Patch + } + return o +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/high/v2/paths.go b/vendor/github.com/pb33f/libopenapi/datamodel/high/v2/paths.go new file mode 100644 index 0000000000..79a5d89d05 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/high/v2/paths.go @@ -0,0 +1,53 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package v2 + +import ( + "github.com/pb33f/libopenapi/datamodel/high" + low "github.com/pb33f/libopenapi/datamodel/low/v2" +) + +// Paths represents a high-level Swagger / OpenAPI Paths object, backed by a low-level one. +type Paths struct { + PathItems map[string]*PathItem + Extensions map[string]any + low *low.Paths +} + +// NewPaths creates a new high-level instance of Paths from a low-level one. +func NewPaths(paths *low.Paths) *Paths { + p := new(Paths) + p.low = paths + p.Extensions = high.ExtractExtensions(paths.Extensions) + + resultChan := make(chan asyncResult[*PathItem]) + var buildPath = func(path string, pi *low.PathItem, rChan chan<- asyncResult[*PathItem]) { + rChan <- asyncResult[*PathItem]{ + key: path, + result: NewPathItem(pi), + } + } + if len(paths.PathItems) > 0 { + pathItems := make(map[string]*PathItem) + totalPaths := len(paths.PathItems) + for k := range paths.PathItems { + go buildPath(k.Value, paths.PathItems[k].Value, resultChan) + } + completedPaths := 0 + for completedPaths < totalPaths { + select { + case res := <-resultChan: + completedPaths++ + pathItems[res.key] = res.result + } + } + p.PathItems = pathItems + } + return p +} + +// GoLow returns the low-level Paths instance that backs the high level one. +func (p *Paths) GoLow() *low.Paths { + return p.low +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/high/v2/response.go b/vendor/github.com/pb33f/libopenapi/datamodel/high/v2/response.go new file mode 100644 index 0000000000..0c3a8e9674 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/high/v2/response.go @@ -0,0 +1,51 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package v2 + +import ( + "github.com/pb33f/libopenapi/datamodel/high" + "github.com/pb33f/libopenapi/datamodel/high/base" + low "github.com/pb33f/libopenapi/datamodel/low/v2" +) + +// Response is a representation of a high-level Swagger / OpenAPI 2 Response object, backed by a low-level one. +// Response describes a single response from an API Operation +// - https://swagger.io/specification/v2/#responseObject +type Response struct { + Description string + Schema *base.SchemaProxy + Headers map[string]*Header + Examples *Example + Extensions map[string]any + low *low.Response +} + +// NewResponse creates a new high-level instance of Response from a low level one. +func NewResponse(response *low.Response) *Response { + r := new(Response) + r.low = response + r.Extensions = high.ExtractExtensions(response.Extensions) + if !response.Description.IsEmpty() { + r.Description = response.Description.Value + } + if !response.Schema.IsEmpty() { + r.Schema = base.NewSchemaProxy(&response.Schema) + } + if !response.Headers.IsEmpty() { + headers := make(map[string]*Header) + for k := range response.Headers.Value { + headers[k.Value] = NewHeader(response.Headers.Value[k].Value) + } + r.Headers = headers + } + if !response.Examples.IsEmpty() { + r.Examples = NewExample(response.Examples.Value) + } + return r +} + +// GoLow will return the low-level Response instance used to create the high level one. +func (r *Response) GoLow() *low.Response { + return r.low +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/high/v2/responses.go b/vendor/github.com/pb33f/libopenapi/datamodel/high/v2/responses.go new file mode 100644 index 0000000000..dc1d64744e --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/high/v2/responses.go @@ -0,0 +1,61 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package v2 + +import ( + "github.com/pb33f/libopenapi/datamodel/high" + low "github.com/pb33f/libopenapi/datamodel/low/v2" +) + +// Responses is a high-level representation of a Swagger / OpenAPI 2 Responses object, backed by a low level one. +type Responses struct { + Codes map[string]*Response + Default *Response + Extensions map[string]any + low *low.Responses +} + +// NewResponses will create a new high-level instance of Responses from a low-level one. +func NewResponses(responses *low.Responses) *Responses { + r := new(Responses) + r.low = responses + r.Extensions = high.ExtractExtensions(responses.Extensions) + + // async function. + var buildPath = func(code string, pi *low.Response, rChan chan<- asyncResult[*Response]) { + rChan <- asyncResult[*Response]{ + key: code, + result: NewResponse(pi), + } + } + + if !responses.Default.IsEmpty() { + r.Default = NewResponse(responses.Default.Value) + } + + // run everything async. lots of responses with lots of data are possible. + if len(responses.Codes) > 0 { + resultChan := make(chan asyncResult[*Response]) + for k := range responses.Codes { + go buildPath(k.Value, responses.Codes[k].Value, resultChan) + } + resp := make(map[string]*Response) + totalResponses := len(responses.Codes) + completedResponses := 0 + for completedResponses < totalResponses { + select { + case res := <-resultChan: + completedResponses++ + resp[res.key] = res.result + } + } + r.Codes = resp + } + return r +} + +// GoLow will return the low-level object used to create the high-level one. +func (r *Responses) GoLow() *low.Responses { + return r.low +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/high/v2/responses_definitions.go b/vendor/github.com/pb33f/libopenapi/datamodel/high/v2/responses_definitions.go new file mode 100644 index 0000000000..897269815a --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/high/v2/responses_definitions.go @@ -0,0 +1,52 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package v2 + +import low "github.com/pb33f/libopenapi/datamodel/low/v2" + +// ResponsesDefinitions is a high-level representation of a Swagger / OpenAPI 2 Responses Definitions object. +// that is backed by a low-level one. +// +// ResponsesDefinitions is an object to hold responses to be reused across operations. Response definitions can be +// referenced to the ones defined here. It does not define global operation responses +// - https://swagger.io/specification/v2/#responsesDefinitionsObject +type ResponsesDefinitions struct { + Definitions map[string]*Response + low *low.ResponsesDefinitions +} + +// NewResponsesDefinitions will create a new high-level instance of ResponsesDefinitions from a low-level one. +func NewResponsesDefinitions(responsesDefinitions *low.ResponsesDefinitions) *ResponsesDefinitions { + rd := new(ResponsesDefinitions) + rd.low = responsesDefinitions + + // build everything async. + responses := make(map[string]*Response) + var buildResp = func(name string, resp *low.Response, rChan chan<- asyncResult[*Response]) { + rChan <- asyncResult[*Response]{ + key: name, + result: NewResponse(resp), + } + } + resChan := make(chan asyncResult[*Response]) + for k := range responsesDefinitions.Definitions { + go buildResp(k.Value, responsesDefinitions.Definitions[k].Value, resChan) + } + totalResponses := len(responsesDefinitions.Definitions) + completedResponses := 0 + for completedResponses < totalResponses { + select { + case r := <-resChan: + completedResponses++ + responses[r.key] = r.result + } + } + rd.Definitions = responses + return rd +} + +// GoLow returns the low-level ResponsesDefinitions used to create the high-level one. +func (r *ResponsesDefinitions) GoLow() *low.ResponsesDefinitions { + return r.low +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/high/v2/scopes.go b/vendor/github.com/pb33f/libopenapi/datamodel/high/v2/scopes.go new file mode 100644 index 0000000000..9b27d47104 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/high/v2/scopes.go @@ -0,0 +1,34 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package v2 + +import ( + low "github.com/pb33f/libopenapi/datamodel/low/v2" +) + +// Scopes is a high-level representation of a Swagger / OpenAPI 2 OAuth2 Scopes object, that is backed by a low-level one. +// +// Scopes lists the available scopes for an OAuth2 security scheme. +// - https://swagger.io/specification/v2/#scopesObject +type Scopes struct { + Values map[string]string + low *low.Scopes +} + +// NewScopes creates a new high-level instance of Scopes from a low-level one. +func NewScopes(scopes *low.Scopes) *Scopes { + s := new(Scopes) + s.low = scopes + scopeValues := make(map[string]string) + for k := range scopes.Values { + scopeValues[k.Value] = scopes.Values[k].Value + } + s.Values = scopeValues + return s +} + +// GoLow returns the low-level instance of Scopes used to create the high-level one. +func (s *Scopes) GoLow() *low.Scopes { + return s.low +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/high/v2/security_definitions.go b/vendor/github.com/pb33f/libopenapi/datamodel/high/v2/security_definitions.go new file mode 100644 index 0000000000..ee2dd49fdb --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/high/v2/security_definitions.go @@ -0,0 +1,34 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package v2 + +import low "github.com/pb33f/libopenapi/datamodel/low/v2" + +// SecurityDefinitions is a high-level representation of a Swagger / OpenAPI 2 Security Definitions object, that +// is backed by a low-level one. +// +// A declaration of the security schemes available to be used in the specification. This does not enforce the security +// schemes on the operations and only serves to provide the relevant details for each scheme +// - https://swagger.io/specification/v2/#securityDefinitionsObject +type SecurityDefinitions struct { + Definitions map[string]*SecurityScheme + low *low.SecurityDefinitions +} + +// NewSecurityDefinitions creates a new high-level instance of a SecurityDefinitions from a low-level one. +func NewSecurityDefinitions(definitions *low.SecurityDefinitions) *SecurityDefinitions { + sd := new(SecurityDefinitions) + sd.low = definitions + schemes := make(map[string]*SecurityScheme) + for k := range definitions.Definitions { + schemes[k.Value] = NewSecurityScheme(definitions.Definitions[k].Value) + } + sd.Definitions = schemes + return sd +} + +// GoLow returns the low-level SecurityDefinitions instance used to create the high-level one. +func (sd *SecurityDefinitions) GoLow() *low.SecurityDefinitions { + return sd.low +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/high/v2/security_scheme.go b/vendor/github.com/pb33f/libopenapi/datamodel/high/v2/security_scheme.go new file mode 100644 index 0000000000..4c3c7517a9 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/high/v2/security_scheme.go @@ -0,0 +1,66 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package v2 + +import ( + "github.com/pb33f/libopenapi/datamodel/high" + low "github.com/pb33f/libopenapi/datamodel/low/v2" +) + +// SecurityScheme is a high-level representation of a Swagger / OpenAPI 2 SecurityScheme object +// backed by a low-level one. +// +// SecurityScheme allows the definition of a security scheme that can be used by the operations. Supported schemes are +// basic authentication, an API key (either as a header or as a query parameter) and OAuth2's common flows +// (implicit, password, application and access code) +// - https://swagger.io/specification/v2/#securityDefinitionsObject +type SecurityScheme struct { + Type string + Description string + Name string + In string + Flow string + AuthorizationUrl string + TokenUrl string + Scopes *Scopes + Extensions map[string]any + low *low.SecurityScheme +} + +// NewSecurityScheme creates a new instance of SecurityScheme from a low-level one. +func NewSecurityScheme(securityScheme *low.SecurityScheme) *SecurityScheme { + s := new(SecurityScheme) + s.low = securityScheme + s.Extensions = high.ExtractExtensions(securityScheme.Extensions) + if !securityScheme.Type.IsEmpty() { + s.Type = securityScheme.Type.Value + } + if !securityScheme.Description.IsEmpty() { + s.Description = securityScheme.Description.Value + } + if !securityScheme.Name.IsEmpty() { + s.Name = securityScheme.Name.Value + } + if !securityScheme.In.IsEmpty() { + s.In = securityScheme.In.Value + } + if !securityScheme.Flow.IsEmpty() { + s.Flow = securityScheme.Flow.Value + } + if !securityScheme.AuthorizationUrl.IsEmpty() { + s.AuthorizationUrl = securityScheme.AuthorizationUrl.Value + } + if !securityScheme.TokenUrl.IsEmpty() { + s.TokenUrl = securityScheme.TokenUrl.Value + } + if !securityScheme.Scopes.IsEmpty() { + s.Scopes = NewScopes(securityScheme.Scopes.Value) + } + return s +} + +// GoLow returns the low-level SecurityScheme that was used to create the high-level one. +func (s *SecurityScheme) GoLow() *low.SecurityScheme { + return s.low +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/high/v2/swagger.go b/vendor/github.com/pb33f/libopenapi/datamodel/high/v2/swagger.go new file mode 100644 index 0000000000..fcbe9f546c --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/high/v2/swagger.go @@ -0,0 +1,181 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +// Package v2 represents all Swagger / OpenAPI 2 high-level models. High-level models are easy to navigate +// and simple to extract what ever is required from a specification. +// +// High-level models are backed by low-level ones. There is a 'GoLow()' method available on every high level +// object. 'Going Low' allows engineers to transition from a high-level or 'porcelain' API, to a low-level 'plumbing' +// API, which provides fine grain detail to the underlying AST powering the data, lines, columns, raw nodes etc. +// +// IMPORTANT: As a general rule, Swagger / OpenAPI 2 should be avoided for new projects. +package v2 + +import ( + "github.com/pb33f/libopenapi/datamodel/high" + "github.com/pb33f/libopenapi/datamodel/high/base" + low "github.com/pb33f/libopenapi/datamodel/low/v2" +) + +// Swagger represents a high-level Swagger / OpenAPI 2 document. An instance of Swagger is the root of the specification. +type Swagger struct { + + // Swagger is the version of Swagger / OpenAPI being used, extracted from the 'swagger: 2.x' definition. + Swagger string + + // Info represents a specification Info definition. + // Provides metadata about the API. The metadata can be used by the clients if needed. + // - https://swagger.io/specification/v2/#infoObject + Info *base.Info + + // Host is The host (name or ip) serving the API. This MUST be the host only and does not include the scheme nor + // sub-paths. It MAY include a port. If the host is not included, the host serving the documentation is to be used + // (including the port). The host does not support path templating. + Host string + + // BasePath is The base path on which the API is served, which is relative to the host. If it is not included, the API is + // served directly under the host. The value MUST start with a leading slash (/). + // The basePath does not support path templating. + BasePath string + + // Schemes represents the transfer protocol of the API. Requirements MUST be from the list: "http", "https", "ws", "wss". + // If the schemes is not included, the default scheme to be used is the one used to access + // the Swagger definition itself. + Schemes []string + + // Consumes is a list of MIME types the APIs can consume. This is global to all APIs but can be overridden on + // specific API calls. Value MUST be as described under Mime Types. + Consumes []string + + // Produces is a list of MIME types the APIs can produce. This is global to all APIs but can be overridden on + // specific API calls. Value MUST be as described under Mime Types. + Produces []string + + // Paths are the paths and operations for the API. Perhaps the most important part of the specification. + // - https://swagger.io/specification/v2/#pathsObject + Paths *Paths + + // Definitions is an object to hold data types produced and consumed by operations. It's composed of Schema instances + // - https://swagger.io/specification/v2/#definitionsObject + Definitions *Definitions + + // Parameters is an object to hold parameters that can be used across operations. + // This property does not define global parameters for all operations. + // - https://swagger.io/specification/v2/#parametersDefinitionsObject + Parameters *ParameterDefinitions + + // Responses is an object to hold responses that can be used across operations. + // This property does not define global responses for all operations. + // - https://swagger.io/specification/v2/#responsesDefinitionsObject + Responses *ResponsesDefinitions + + // SecurityDefinitions represents security scheme definitions that can be used across the specification. + // - https://swagger.io/specification/v2/#securityDefinitionsObject + SecurityDefinitions *SecurityDefinitions + + // Security is a declaration of which security schemes are applied for the API as a whole. The list of values + // describes alternative security schemes that can be used (that is, there is a logical OR between the security + // requirements). Individual operations can override this definition. + // - https://swagger.io/specification/v2/#securityRequirementObject + Security []*base.SecurityRequirement + + // Tags are A list of tags used by the specification with additional metadata. + // The order of the tags can be used to reflect on their order by the parsing tools. Not all tags that are used + // by the Operation Object must be declared. The tags that are not declared may be organized randomly or based + // on the tools' logic. Each tag name in the list MUST be unique. + // - https://swagger.io/specification/v2/#tagObject + Tags []*base.Tag + + // ExternalDocs is an instance of base.ExternalDoc for.. well, obvious really, innit. + ExternalDocs *base.ExternalDoc + + // Extensions contains all custom extensions defined for the top-level document. + Extensions map[string]any + low *low.Swagger +} + +// NewSwaggerDocument will create a new high-level Swagger document from a low-level one. +func NewSwaggerDocument(document *low.Swagger) *Swagger { + d := new(Swagger) + d.low = document + d.Extensions = high.ExtractExtensions(document.Extensions) + if !document.Info.IsEmpty() { + d.Info = base.NewInfo(document.Info.Value) + } + if !document.Swagger.IsEmpty() { + d.Swagger = document.Swagger.Value + } + if !document.Host.IsEmpty() { + d.Host = document.Host.Value + } + if !document.BasePath.IsEmpty() { + d.BasePath = document.BasePath.Value + } + + if !document.Schemes.IsEmpty() { + var schemes []string + for s := range document.Schemes.Value { + schemes = append(schemes, document.Schemes.Value[s].Value) + } + d.Schemes = schemes + } + if !document.Consumes.IsEmpty() { + var consumes []string + for c := range document.Consumes.Value { + consumes = append(consumes, document.Consumes.Value[c].Value) + } + d.Consumes = consumes + } + if !document.Produces.IsEmpty() { + var produces []string + for p := range document.Produces.Value { + produces = append(produces, document.Produces.Value[p].Value) + } + d.Produces = produces + } + if !document.Paths.IsEmpty() { + d.Paths = NewPaths(document.Paths.Value) + } + if !document.Definitions.IsEmpty() { + d.Definitions = NewDefinitions(document.Definitions.Value) + } + if !document.Parameters.IsEmpty() { + d.Parameters = NewParametersDefinitions(document.Parameters.Value) + } + + if !document.Responses.IsEmpty() { + d.Responses = NewResponsesDefinitions(document.Responses.Value) + } + if !document.SecurityDefinitions.IsEmpty() { + d.SecurityDefinitions = NewSecurityDefinitions(document.SecurityDefinitions.Value) + } + if !document.Security.IsEmpty() { + var security []*base.SecurityRequirement + for s := range document.Security.Value { + security = append(security, base.NewSecurityRequirement(document.Security.Value[s].Value)) + } + d.Security = security + } + if !document.Tags.IsEmpty() { + var tags []*base.Tag + for t := range document.Tags.Value { + tags = append(tags, base.NewTag(document.Tags.Value[t].Value)) + } + d.Tags = tags + } + if !document.ExternalDocs.IsEmpty() { + d.ExternalDocs = base.NewExternalDoc(document.ExternalDocs.Value) + } + return d +} + +// GoLow returns the low-level Swagger instance that was used to create the high-level one. +func (s *Swagger) GoLow() *low.Swagger { + return s.low +} + +// everything is build async, this little gem holds the results. +type asyncResult[T any] struct { + key string + result T +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/high/v3/callback.go b/vendor/github.com/pb33f/libopenapi/datamodel/high/v3/callback.go new file mode 100644 index 0000000000..79363f09e0 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/high/v3/callback.go @@ -0,0 +1,112 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package v3 + +import ( + "github.com/pb33f/libopenapi/datamodel/high" + low "github.com/pb33f/libopenapi/datamodel/low/v3" + "github.com/pb33f/libopenapi/utils" + "gopkg.in/yaml.v3" + "sort" +) + +// Callback represents a high-level Callback object for OpenAPI 3+. +// +// A map of possible out-of band callbacks related to the parent operation. Each value in the map is a +// PathItem Object that describes a set of requests that may be initiated by the API provider and the expected +// responses. The key value used to identify the path item object is an expression, evaluated at runtime, +// that identifies a URL to use for the callback operation. +// - https://spec.openapis.org/oas/v3.1.0#callback-object +type Callback struct { + Expression map[string]*PathItem `json:"-" yaml:"-"` + Extensions map[string]any `json:"-" yaml:"-"` + low *low.Callback +} + +// NewCallback creates a new high-level callback from a low-level one. +func NewCallback(lowCallback *low.Callback) *Callback { + n := new(Callback) + n.low = lowCallback + n.Expression = make(map[string]*PathItem) + for i := range lowCallback.Expression.Value { + n.Expression[i.Value] = NewPathItem(lowCallback.Expression.Value[i].Value) + } + n.Extensions = make(map[string]any) + for k, v := range lowCallback.Extensions { + n.Extensions[k.Value] = v.Value + } + return n +} + +// GoLow returns the low-level Callback instance used to create the high-level one. +func (c *Callback) GoLow() *low.Callback { + return c.low +} + +// GoLowUntyped will return the low-level Callback instance that was used to create the high-level one, with no type +func (c *Callback) GoLowUntyped() any { + return c.low +} + +// Render will return a YAML representation of the Callback object as a byte slice. +func (c *Callback) Render() ([]byte, error) { + return yaml.Marshal(c) +} + +// MarshalYAML will create a ready to render YAML representation of the Callback object. +func (c *Callback) MarshalYAML() (interface{}, error) { + // map keys correctly. + m := utils.CreateEmptyMapNode() + type cbItem struct { + cb *PathItem + exp string + line int + ext *yaml.Node + } + var mapped []*cbItem + + for k, ex := range c.Expression { + ln := 999 // default to a high value to weight new content to the bottom. + if c.low != nil { + for lKey := range c.low.Expression.Value { + if lKey.Value == k { + ln = lKey.KeyNode.Line + } + } + } + mapped = append(mapped, &cbItem{ex, k, ln, nil}) + } + + // extract extensions + nb := high.NewNodeBuilder(c, c.low) + extNode := nb.Render() + if extNode != nil && extNode.Content != nil { + var label string + for u := range extNode.Content { + if u%2 == 0 { + label = extNode.Content[u].Value + continue + } + mapped = append(mapped, &cbItem{nil, label, + extNode.Content[u].Line, extNode.Content[u]}) + } + } + + sort.Slice(mapped, func(i, j int) bool { + return mapped[i].line < mapped[j].line + }) + for j := range mapped { + if mapped[j].cb != nil { + rendered, _ := mapped[j].cb.MarshalYAML() + m.Content = append(m.Content, utils.CreateStringNode(mapped[j].exp)) + m.Content = append(m.Content, rendered.(*yaml.Node)) + } + if mapped[j].ext != nil { + m.Content = append(m.Content, utils.CreateStringNode(mapped[j].exp)) + m.Content = append(m.Content, mapped[j].ext) + } + } + + return m, nil +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/high/v3/components.go b/vendor/github.com/pb33f/libopenapi/datamodel/high/v3/components.go new file mode 100644 index 0000000000..dbeec10b73 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/high/v3/components.go @@ -0,0 +1,190 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package v3 + +import ( + "github.com/pb33f/libopenapi/datamodel/high" + highbase "github.com/pb33f/libopenapi/datamodel/high/base" + lowmodel "github.com/pb33f/libopenapi/datamodel/low" + "github.com/pb33f/libopenapi/datamodel/low/base" + low "github.com/pb33f/libopenapi/datamodel/low/v3" + "gopkg.in/yaml.v3" +) + +// used for internal channel co-ordination for building out different component types. +const ( + responses = iota + parameters + examples + requestBodies + headers + securitySchemes + links + callbacks +) + +// Components represents a high-level OpenAPI 3+ Components Object, that is backed by a low-level one. +// +// Holds a set of reusable objects for different aspects of the OAS. All objects defined within the components object +// will have no effect on the API unless they are explicitly referenced from properties outside the components object. +// - https://spec.openapis.org/oas/v3.1.0#components-object +type Components struct { + Schemas map[string]*highbase.SchemaProxy `json:"schemas,omitempty" yaml:"schemas,omitempty"` + Responses map[string]*Response `json:"responses,omitempty" yaml:"responses,omitempty"` + Parameters map[string]*Parameter `json:"parameters,omitempty" yaml:"parameters,omitempty"` + Examples map[string]*highbase.Example `json:"examples,omitempty" yaml:"examples,omitempty"` + RequestBodies map[string]*RequestBody `json:"requestBodies,omitempty" yaml:"requestBodies,omitempty"` + Headers map[string]*Header `json:"headers,omitempty" yaml:"headers,omitempty"` + SecuritySchemes map[string]*SecurityScheme `json:"securitySchemes,omitempty" yaml:"securitySchemes,omitempty"` + Links map[string]*Link `json:"links,omitempty" yaml:"links,omitempty"` + Callbacks map[string]*Callback `json:"callbacks,omitempty" yaml:"callbacks,omitempty"` + Extensions map[string]any `json:"-" yaml:"-"` + low *low.Components +} + +// NewComponents will create new high-level instance of Components from a low-level one. Components can be considerable +// in scope, with a lot of different properties across different categories. All components are built asynchronously +// in order to keep things fast. +func NewComponents(comp *low.Components) *Components { + c := new(Components) + c.low = comp + if len(comp.Extensions) > 0 { + c.Extensions = high.ExtractExtensions(comp.Extensions) + } + cbMap := make(map[string]*Callback) + linkMap := make(map[string]*Link) + responseMap := make(map[string]*Response) + parameterMap := make(map[string]*Parameter) + exampleMap := make(map[string]*highbase.Example) + requestBodyMap := make(map[string]*RequestBody) + headerMap := make(map[string]*Header) + securitySchemeMap := make(map[string]*SecurityScheme) + schemas := make(map[string]*highbase.SchemaProxy) + schemaChan := make(chan componentResult[*highbase.SchemaProxy]) + cbChan := make(chan componentResult[*Callback]) + linkChan := make(chan componentResult[*Link]) + responseChan := make(chan componentResult[*Response]) + paramChan := make(chan componentResult[*Parameter]) + exampleChan := make(chan componentResult[*highbase.Example]) + requestBodyChan := make(chan componentResult[*RequestBody]) + headerChan := make(chan componentResult[*Header]) + securitySchemeChan := make(chan componentResult[*SecurityScheme]) + + // build all components asynchronously. + for k, v := range comp.Callbacks.Value { + go buildComponent[*Callback, *low.Callback](callbacks, k.Value, v.Value, cbChan, NewCallback) + } + for k, v := range comp.Links.Value { + go buildComponent[*Link, *low.Link](links, k.Value, v.Value, linkChan, NewLink) + } + for k, v := range comp.Responses.Value { + go buildComponent[*Response, *low.Response](responses, k.Value, v.Value, responseChan, NewResponse) + } + for k, v := range comp.Parameters.Value { + go buildComponent[*Parameter, *low.Parameter](parameters, k.Value, v.Value, paramChan, NewParameter) + } + for k, v := range comp.Examples.Value { + go buildComponent[*highbase.Example, *base.Example](examples, k.Value, v.Value, exampleChan, highbase.NewExample) + } + for k, v := range comp.RequestBodies.Value { + go buildComponent[*RequestBody, *low.RequestBody](requestBodies, k.Value, v.Value, + requestBodyChan, NewRequestBody) + } + for k, v := range comp.Headers.Value { + go buildComponent[*Header, *low.Header](headers, k.Value, v.Value, headerChan, NewHeader) + } + for k, v := range comp.SecuritySchemes.Value { + go buildComponent[*SecurityScheme, *low.SecurityScheme](securitySchemes, k.Value, v.Value, + securitySchemeChan, NewSecurityScheme) + } + for k, v := range comp.Schemas.Value { + go buildSchema(k, v, schemaChan) + } + + totalComponents := len(comp.Callbacks.Value) + len(comp.Links.Value) + len(comp.Responses.Value) + + len(comp.Parameters.Value) + len(comp.Examples.Value) + len(comp.RequestBodies.Value) + + len(comp.Headers.Value) + len(comp.SecuritySchemes.Value) + len(comp.Schemas.Value) + + processedComponents := 0 + for processedComponents < totalComponents { + select { + case sRes := <-schemaChan: + processedComponents++ + schemas[sRes.key] = sRes.res + case cbRes := <-cbChan: + processedComponents++ + cbMap[cbRes.key] = cbRes.res + case lRes := <-linkChan: + processedComponents++ + linkMap[lRes.key] = lRes.res + case respRes := <-responseChan: + processedComponents++ + responseMap[respRes.key] = respRes.res + case pRes := <-paramChan: + processedComponents++ + parameterMap[pRes.key] = pRes.res + case eRes := <-exampleChan: + processedComponents++ + exampleMap[eRes.key] = eRes.res + case rbRes := <-requestBodyChan: + processedComponents++ + requestBodyMap[rbRes.key] = rbRes.res + case hRes := <-headerChan: + processedComponents++ + headerMap[hRes.key] = hRes.res + case ssRes := <-securitySchemeChan: + processedComponents++ + securitySchemeMap[ssRes.key] = ssRes.res + } + } + c.Schemas = schemas + c.Callbacks = cbMap + c.Links = linkMap + c.Parameters = parameterMap + c.Headers = headerMap + c.Responses = responseMap + c.RequestBodies = requestBodyMap + c.Examples = exampleMap + c.SecuritySchemes = securitySchemeMap + return c +} + +// contains a component build result. +type componentResult[T any] struct { + res T + key string + comp int +} + +// build out a component. +func buildComponent[N any, O any](comp int, key string, orig O, c chan componentResult[N], f func(O) N) { + c <- componentResult[N]{comp: comp, res: f(orig), key: key} +} + +// build out a schema +func buildSchema(key lowmodel.KeyReference[string], orig lowmodel.ValueReference[*base.SchemaProxy], + c chan componentResult[*highbase.SchemaProxy]) { + var sch *highbase.SchemaProxy + sch = highbase.NewSchemaProxy(&lowmodel.NodeReference[*base.SchemaProxy]{ + Value: orig.Value, + ValueNode: orig.ValueNode, + }) + c <- componentResult[*highbase.SchemaProxy]{res: sch, key: key.Value} +} + +// GoLow returns the low-level Components instance used to create the high-level one. +func (c *Components) GoLow() *low.Components { + return c.low +} + +// Render will return a YAML representation of the Components object as a byte slice. +func (c *Components) Render() ([]byte, error) { + return yaml.Marshal(c) +} + +// MarshalYAML will create a ready to render YAML representation of the Response object. +func (c *Components) MarshalYAML() (interface{}, error) { + nb := high.NewNodeBuilder(c, c.low) + return nb.Render(), nil +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/high/v3/document.go b/vendor/github.com/pb33f/libopenapi/datamodel/high/v3/document.go new file mode 100644 index 0000000000..727821e205 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/high/v3/document.go @@ -0,0 +1,171 @@ +// Copyright 2022-2023 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +// Package v3 represents all OpenAPI 3+ high-level models. High-level models are easy to navigate +// and simple to extract what ever is required from an OpenAPI 3+ specification. +// +// High-level models are backed by low-level ones. There is a 'GoLow()' method available on every high level +// object. 'Going Low' allows engineers to transition from a high-level or 'porcelain' API, to a low-level 'plumbing' +// API, which provides fine grain detail to the underlying AST powering the data, lines, columns, raw nodes etc. +package v3 + +import ( + "github.com/pb33f/libopenapi/datamodel/high" + "github.com/pb33f/libopenapi/datamodel/high/base" + low "github.com/pb33f/libopenapi/datamodel/low/v3" + "github.com/pb33f/libopenapi/index" + "gopkg.in/yaml.v3" +) + +// Document represents a high-level OpenAPI 3 document (both 3.0 & 3.1). A Document is the root of the specification. +type Document struct { + + // Version is the version of OpenAPI being used, extracted from the 'openapi: x.x.x' definition. + // This is not a standard property of the OpenAPI model, it's a convenience mechanism only. + Version string `json:"openapi,omitempty" yaml:"openapi,omitempty"` + + // Info represents a specification Info definitions + // Provides metadata about the API. The metadata MAY be used by tooling as required. + // - https://spec.openapis.org/oas/v3.1.0#info-object + Info *base.Info `json:"info,omitempty" yaml:"info,omitempty"` + + // Servers is a slice of Server instances which provide connectivity information to a target server. If the servers + // property is not provided, or is an empty array, the default value would be a Server Object with an url value of /. + // - https://spec.openapis.org/oas/v3.1.0#server-object + Servers []*Server `json:"servers,omitempty" yaml:"servers,omitempty"` + + // Paths contains all the PathItem definitions for the specification. + // The available paths and operations for the API, The most important part of ths spec. + // - https://spec.openapis.org/oas/v3.1.0#paths-object + Paths *Paths `json:"paths,omitempty" yaml:"paths,omitempty"` + + // Components is an element to hold various schemas for the document. + // - https://spec.openapis.org/oas/v3.1.0#components-object + Components *Components `json:"components,omitempty" yaml:"components,omitempty"` + + // Security contains global security requirements/roles for the specification + // A declaration of which security mechanisms can be used across the API. The list of values includes alternative + // security requirement objects that can be used. Only one of the security requirement objects need to be satisfied + // to authorize a request. Individual operations can override this definition. To make security optional, + // an empty security requirement ({}) can be included in the array. + // - https://spec.openapis.org/oas/v3.1.0#security-requirement-object + Security []*base.SecurityRequirement `json:"security,omitempty" yaml:"security,omitempty"` + //Security []*base.SecurityRequirement `json:"-" yaml:"-"` + + // Tags is a slice of base.Tag instances defined by the specification + // A list of tags used by the document with additional metadata. The order of the tags can be used to reflect on + // their order by the parsing tools. Not all tags that are used by the Operation Object must be declared. + // The tags that are not declared MAY be organized randomly or based on the tools’ logic. + // Each tag name in the list MUST be unique. + // - https://spec.openapis.org/oas/v3.1.0#tag-object + Tags []*base.Tag `json:"tags,omitempty" yaml:"tags,omitempty"` + + // ExternalDocs is an instance of base.ExternalDoc for.. well, obvious really, innit. + // - https://spec.openapis.org/oas/v3.1.0#external-documentation-object + ExternalDocs *base.ExternalDoc `json:"externalDocs,omitempty" yaml:"externalDocs,omitempty"` + + // Extensions contains all custom extensions defined for the top-level document. + Extensions map[string]any `json:"-" yaml:"-"` + + // JsonSchemaDialect is a 3.1+ property that sets the dialect to use for validating *base.Schema definitions + // The default value for the $schema keyword within Schema Objects contained within this OAS document. + // This MUST be in the form of a URI. + // - https://spec.openapis.org/oas/v3.1.0#schema-object + JsonSchemaDialect string `json:"jsonSchemaDialect,omitempty" yaml:"jsonSchemaDialect,omitempty"` + + // Webhooks is a 3.1+ property that is similar to callbacks, except, this defines incoming webhooks. + // The incoming webhooks that MAY be received as part of this API and that the API consumer MAY choose to implement. + // Closely related to the callbacks feature, this section describes requests initiated other than by an API call, + // for example by an out-of-band registration. The key name is a unique string to refer to each webhook, + // while the (optionally referenced) Path Item Object describes a request that may be initiated by the API provider + // and the expected responses. An example is available. + Webhooks map[string]*PathItem `json:"webhooks,omitempty" yaml:"webhooks,omitempty"` + + // Index is a reference to the *index.SpecIndex that was created for the document and used + // as a guide when building out the Document. Ideal if further processing is required on the model and + // the original details are required to continue the work. + // + // This property is not a part of the OpenAPI schema, this is custom to libopenapi. + Index *index.SpecIndex `json:"-" yaml:"-"` + low *low.Document +} + +// NewDocument will create a new high-level Document from a low-level one. +func NewDocument(document *low.Document) *Document { + d := new(Document) + d.low = document + d.Index = document.Index + if !document.Info.IsEmpty() { + d.Info = base.NewInfo(document.Info.Value) + } + if !document.Version.IsEmpty() { + d.Version = document.Version.Value + } + var servers []*Server + for _, ser := range document.Servers.Value { + servers = append(servers, NewServer(ser.Value)) + } + d.Servers = servers + var tags []*base.Tag + for _, tag := range document.Tags.Value { + tags = append(tags, base.NewTag(tag.Value)) + } + d.Tags = tags + if !document.ExternalDocs.IsEmpty() { + d.ExternalDocs = base.NewExternalDoc(document.ExternalDocs.Value) + } + if len(document.Extensions) > 0 { + d.Extensions = high.ExtractExtensions(document.Extensions) + } + if !document.Components.IsEmpty() { + d.Components = NewComponents(document.Components.Value) + } + if !document.Paths.IsEmpty() { + d.Paths = NewPaths(document.Paths.Value) + } + if !document.JsonSchemaDialect.IsEmpty() { + d.JsonSchemaDialect = document.JsonSchemaDialect.Value + } + if !document.Webhooks.IsEmpty() { + hooks := make(map[string]*PathItem) + for h := range document.Webhooks.Value { + hooks[h.Value] = NewPathItem(document.Webhooks.Value[h].Value) + } + d.Webhooks = hooks + } + if !document.Security.IsEmpty() { + var security []*base.SecurityRequirement + for s := range document.Security.Value { + security = append(security, base.NewSecurityRequirement(document.Security.Value[s].Value)) + } + d.Security = security + } + return d +} + +// GoLow returns the low-level Document that was used to create the high level one. +func (d *Document) GoLow() *low.Document { + return d.low +} + +// Render will return a YAML representation of the Document object as a byte slice. +func (d *Document) Render() ([]byte, error) { + return yaml.Marshal(d) +} + +func (d *Document) RenderInline() ([]byte, error) { + di, _ := d.MarshalYAMLInline() + return yaml.Marshal(di) +} + +// MarshalYAML will create a ready to render YAML representation of the Document object. +func (d *Document) MarshalYAML() (interface{}, error) { + nb := high.NewNodeBuilder(d, d.low) + return nb.Render(), nil +} + +func (d *Document) MarshalYAMLInline() (interface{}, error) { + nb := high.NewNodeBuilder(d, d.low) + nb.Resolve = true + return nb.Render(), nil +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/high/v3/encoding.go b/vendor/github.com/pb33f/libopenapi/datamodel/high/v3/encoding.go new file mode 100644 index 0000000000..51aaf80c07 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/high/v3/encoding.go @@ -0,0 +1,64 @@ +// Copyright 2022-2023 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package v3 + +import ( + "github.com/pb33f/libopenapi/datamodel/high" + lowmodel "github.com/pb33f/libopenapi/datamodel/low" + low "github.com/pb33f/libopenapi/datamodel/low/v3" + "gopkg.in/yaml.v3" +) + +// Encoding represents an OpenAPI 3+ Encoding object +// - https://spec.openapis.org/oas/v3.1.0#encoding-object +type Encoding struct { + ContentType string `json:"contentType,omitempty" yaml:"contentType,omitempty"` + Headers map[string]*Header `json:"headers,omitempty" yaml:"headers,omitempty"` + Style string `json:"style,omitempty" yaml:"style,omitempty"` + Explode *bool `json:"explode,omitempty" yaml:"explode,omitempty"` + AllowReserved bool `json:"allowReserved,omitempty" yaml:"allowReserved,omitempty"` + low *low.Encoding +} + +// NewEncoding creates a new instance of Encoding from a low-level one. +func NewEncoding(encoding *low.Encoding) *Encoding { + e := new(Encoding) + e.low = encoding + e.ContentType = encoding.ContentType.Value + e.Style = encoding.Style.Value + e.Explode = &encoding.Explode.Value + e.AllowReserved = encoding.AllowReserved.Value + e.Headers = ExtractHeaders(encoding.Headers.Value) + return e +} + +// GoLow returns the low-level Encoding instance used to create the high-level one. +func (e *Encoding) GoLow() *low.Encoding { + return e.low +} + +// GoLowUntyped will return the low-level Encoding instance that was used to create the high-level one, with no type +func (e *Encoding) GoLowUntyped() any { + return e.low +} + +// Render will return a YAML representation of the Encoding object as a byte slice. +func (e *Encoding) Render() ([]byte, error) { + return yaml.Marshal(e) +} + +// MarshalYAML will create a ready to render YAML representation of the Encoding object. +func (e *Encoding) MarshalYAML() (interface{}, error) { + nb := high.NewNodeBuilder(e, e.low) + return nb.Render(), nil +} + +// ExtractEncoding converts hard to navigate low-level plumbing Encoding definitions, into a high-level simple map +func ExtractEncoding(elements map[lowmodel.KeyReference[string]]lowmodel.ValueReference[*low.Encoding]) map[string]*Encoding { + extracted := make(map[string]*Encoding) + for k, v := range elements { + extracted[k.Value] = NewEncoding(v.Value) + } + return extracted +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/high/v3/header.go b/vendor/github.com/pb33f/libopenapi/datamodel/high/v3/header.go new file mode 100644 index 0000000000..af4f8fcfca --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/high/v3/header.go @@ -0,0 +1,85 @@ +// Copyright 2022-2023 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package v3 + +import ( + "github.com/pb33f/libopenapi/datamodel/high" + highbase "github.com/pb33f/libopenapi/datamodel/high/base" + lowmodel "github.com/pb33f/libopenapi/datamodel/low" + "github.com/pb33f/libopenapi/datamodel/low/base" + low "github.com/pb33f/libopenapi/datamodel/low/v3" + "gopkg.in/yaml.v3" +) + +// Header represents a high-level OpenAPI 3+ Header object that is backed by a low-level one. +// - https://spec.openapis.org/oas/v3.1.0#header-object +type Header struct { + Description string `json:"description,omitempty" yaml:"description,omitempty"` + Required bool `json:"required,omitempty" yaml:"required,omitempty"` + Deprecated bool `json:"deprecated,omitempty" yaml:"deprecated,omitempty"` + AllowEmptyValue bool `json:"allowEmptyValue,omitempty" yaml:"allowEmptyValue,omitempty"` + Style string `json:"style,omitempty" yaml:"style,omitempty"` + Explode bool `json:"explode,omitempty" yaml:"explode,omitempty"` + AllowReserved bool `json:"allowReserved,omitempty" yaml:"allowReserved,omitempty"` + Schema *highbase.SchemaProxy `json:"schema,omitempty" yaml:"schema,omitempty"` + Example any `json:"example,omitempty" yaml:"example,omitempty"` + Examples map[string]*highbase.Example `json:"examples,omitempty" yaml:"examples,omitempty"` + Content map[string]*MediaType `json:"content,omitempty" yaml:"content,omitempty"` + Extensions map[string]any `json:"-" yaml:"-"` + low *low.Header +} + +// NewHeader creates a new high-level Header instance from a low-level one. +func NewHeader(header *low.Header) *Header { + h := new(Header) + h.low = header + h.Description = header.Description.Value + h.Required = header.Required.Value + h.Deprecated = header.Deprecated.Value + h.AllowEmptyValue = header.AllowEmptyValue.Value + h.Style = header.Style.Value + h.Explode = header.Explode.Value + h.AllowReserved = header.AllowReserved.Value + if !header.Schema.IsEmpty() { + h.Schema = highbase.NewSchemaProxy(&lowmodel.NodeReference[*base.SchemaProxy]{ + Value: header.Schema.Value, + KeyNode: header.Schema.KeyNode, + ValueNode: header.Schema.ValueNode, + }) + } + h.Content = ExtractContent(header.Content.Value) + h.Example = header.Example.Value + h.Examples = highbase.ExtractExamples(header.Examples.Value) + return h +} + +// GoLow returns the low-level Header instance used to create the high-level one. +func (h *Header) GoLow() *low.Header { + return h.low +} + +// GoLowUntyped will return the low-level Header instance that was used to create the high-level one, with no type +func (h *Header) GoLowUntyped() any { + return h.low +} + +// ExtractHeaders will extract a hard to navigate low-level Header map, into simple high-level one. +func ExtractHeaders(elements map[lowmodel.KeyReference[string]]lowmodel.ValueReference[*low.Header]) map[string]*Header { + extracted := make(map[string]*Header) + for k, v := range elements { + extracted[k.Value] = NewHeader(v.Value) + } + return extracted +} + +// Render will return a YAML representation of the Header object as a byte slice. +func (h *Header) Render() ([]byte, error) { + return yaml.Marshal(h) +} + +// MarshalYAML will create a ready to render YAML representation of the Header object. +func (h *Header) MarshalYAML() (interface{}, error) { + nb := high.NewNodeBuilder(h, h.low) + return nb.Render(), nil +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/high/v3/link.go b/vendor/github.com/pb33f/libopenapi/datamodel/high/v3/link.go new file mode 100644 index 0000000000..d4148722a9 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/high/v3/link.go @@ -0,0 +1,74 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package v3 + +import ( + "github.com/pb33f/libopenapi/datamodel/high" + low "github.com/pb33f/libopenapi/datamodel/low/v3" + "gopkg.in/yaml.v3" +) + +// Link represents a high-level OpenAPI 3+ Link object that is backed by a low-level one. +// +// The Link object represents a possible design-time link for a response. The presence of a link does not guarantee the +// caller’s ability to successfully invoke it, rather it provides a known relationship and traversal mechanism between +// responses and other operations. +// +// Unlike dynamic links (i.e. links provided in the response payload), the OAS linking mechanism does not require +// link information in the runtime response. +// +// For computing links, and providing instructions to execute them, a runtime expression is used for accessing values +// in an operation and using them as parameters while invoking the linked operation. +// - https://spec.openapis.org/oas/v3.1.0#link-object +type Link struct { + OperationRef string `json:"operationRef,omitempty" yaml:"operationRef,omitempty"` + OperationId string `json:"operationId,omitempty" yaml:"operationId,omitempty"` + Parameters map[string]string `json:"parameters,omitempty" yaml:"parameters,omitempty"` + RequestBody string `json:"requestBody,omitempty" yaml:"requestBody,omitempty"` + Description string `json:"description,omitempty" yaml:"description,omitempty"` + Server *Server `json:"server,omitempty" yaml:"server,omitempty"` + Extensions map[string]any `json:"-" yaml:"-"` + low *low.Link +} + +// NewLink will create a new high-level Link instance from a low-level one. +func NewLink(link *low.Link) *Link { + l := new(Link) + l.low = link + l.OperationRef = link.OperationRef.Value + l.OperationId = link.OperationId.Value + params := make(map[string]string) + for k, v := range link.Parameters.Value { + params[k.Value] = v.Value + } + l.Parameters = params + l.RequestBody = link.RequestBody.Value + l.Description = link.Description.Value + if link.Server.Value != nil { + l.Server = NewServer(link.Server.Value) + } + l.Extensions = high.ExtractExtensions(link.Extensions) + return l +} + +// GoLow will return the low-level Link instance used to create the high-level one. +func (l *Link) GoLow() *low.Link { + return l.low +} + +// GoLowUntyped will return the low-level Link instance that was used to create the high-level one, with no type +func (l *Link) GoLowUntyped() any { + return l.low +} + +// Render will return a YAML representation of the Link object as a byte slice. +func (l *Link) Render() ([]byte, error) { + return yaml.Marshal(l) +} + +// MarshalYAML will create a ready to render YAML representation of the Link object. +func (l *Link) MarshalYAML() (interface{}, error) { + nb := high.NewNodeBuilder(l, l.low) + return nb.Render(), nil +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/high/v3/media_type.go b/vendor/github.com/pb33f/libopenapi/datamodel/high/v3/media_type.go new file mode 100644 index 0000000000..2a45851f54 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/high/v3/media_type.go @@ -0,0 +1,102 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package v3 + +import ( + "sync" + + "github.com/pb33f/libopenapi/datamodel/high" + "github.com/pb33f/libopenapi/datamodel/high/base" + lowmodel "github.com/pb33f/libopenapi/datamodel/low" + low "github.com/pb33f/libopenapi/datamodel/low/v3" + "gopkg.in/yaml.v3" +) + +// MediaType represents a high-level OpenAPI MediaType object that is backed by a low-level one. +// +// Each Media Type Object provides schema and examples for the media type identified by its key. +// - https://spec.openapis.org/oas/v3.1.0#media-type-object +type MediaType struct { + Schema *base.SchemaProxy `json:"schema,omitempty" yaml:"schema,omitempty"` + Example any `json:"example,omitempty" yaml:"example,omitempty"` + Examples map[string]*base.Example `json:"examples,omitempty" yaml:"examples,omitempty"` + Encoding map[string]*Encoding `json:"encoding,omitempty" yaml:"encoding,omitempty"` + Extensions map[string]any `json:"-" yaml:"-"` + low *low.MediaType +} + +// NewMediaType will create a new high-level MediaType instance from a low-level one. +func NewMediaType(mediaType *low.MediaType) *MediaType { + m := new(MediaType) + m.low = mediaType + if !mediaType.Schema.IsEmpty() { + m.Schema = base.NewSchemaProxy(&mediaType.Schema) + } + m.Example = mediaType.Example.Value + m.Examples = base.ExtractExamples(mediaType.Examples.Value) + m.Extensions = high.ExtractExtensions(mediaType.Extensions) + m.Encoding = ExtractEncoding(mediaType.Encoding.Value) + return m +} + +// GoLow will return the low-level instance of MediaType used to create the high-level one. +func (m *MediaType) GoLow() *low.MediaType { + return m.low +} + +// GoLowUntyped will return the low-level MediaType instance that was used to create the high-level one, with no type +func (m *MediaType) GoLowUntyped() any { + return m.low +} + +// Render will return a YAML representation of the MediaType object as a byte slice. +func (m *MediaType) Render() ([]byte, error) { + return yaml.Marshal(m) +} + +func (m *MediaType) RenderInline() ([]byte, error) { + d, _ := m.MarshalYAMLInline() + return yaml.Marshal(d) +} + +// MarshalYAML will create a ready to render YAML representation of the MediaType object. +func (m *MediaType) MarshalYAML() (interface{}, error) { + nb := high.NewNodeBuilder(m, m.low) + return nb.Render(), nil +} + +func (m *MediaType) MarshalYAMLInline() (interface{}, error) { + nb := high.NewNodeBuilder(m, m.low) + nb.Resolve = true + return nb.Render(), nil +} + +// ExtractContent takes in a complex and hard to navigate low-level content map, and converts it in to a much simpler +// and easier to navigate high-level one. +func ExtractContent(elements map[lowmodel.KeyReference[string]]lowmodel.ValueReference[*low.MediaType]) map[string]*MediaType { + // extract everything async + doneChan := make(chan bool) + + var extLock sync.RWMutex + extractContentItem := func(k lowmodel.KeyReference[string], + v lowmodel.ValueReference[*low.MediaType], c chan bool, e map[string]*MediaType) { + extLock.Lock() + e[k.Value] = NewMediaType(v.Value) + extLock.Unlock() + c <- true + + } + extracted := make(map[string]*MediaType) + for k, v := range elements { + go extractContentItem(k, v, doneChan, extracted) + } + n := 0 + for n < len(elements) { + select { + case <-doneChan: + n++ + } + } + return extracted +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/high/v3/oauth_flow.go b/vendor/github.com/pb33f/libopenapi/datamodel/high/v3/oauth_flow.go new file mode 100644 index 0000000000..e0174cdbe2 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/high/v3/oauth_flow.go @@ -0,0 +1,58 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package v3 + +import ( + "github.com/pb33f/libopenapi/datamodel/high" + low "github.com/pb33f/libopenapi/datamodel/low/v3" + "gopkg.in/yaml.v3" +) + +// OAuthFlow represents a high-level OpenAPI 3+ OAuthFlow object that is backed by a low-level one. +// - https://spec.openapis.org/oas/v3.1.0#oauth-flow-object +type OAuthFlow struct { + AuthorizationUrl string `json:"authorizationUrl,omitempty" yaml:"authorizationUrl,omitempty"` + TokenUrl string `json:"tokenUrl,omitempty" yaml:"tokenUrl,omitempty"` + RefreshUrl string `json:"refreshUrl,omitempty" yaml:"refreshUrl,omitempty"` + Scopes map[string]string `json:"scopes,omitempty" yaml:"scopes,omitempty"` + Extensions map[string]any `json:"-" yaml:"-"` + low *low.OAuthFlow +} + +// NewOAuthFlow creates a new high-level OAuthFlow instance from a low-level one. +func NewOAuthFlow(flow *low.OAuthFlow) *OAuthFlow { + o := new(OAuthFlow) + o.low = flow + o.TokenUrl = flow.TokenUrl.Value + o.AuthorizationUrl = flow.AuthorizationUrl.Value + o.RefreshUrl = flow.RefreshUrl.Value + scopes := make(map[string]string) + for k, v := range flow.Scopes.Value { + scopes[k.Value] = v.Value + } + o.Scopes = scopes + o.Extensions = high.ExtractExtensions(flow.Extensions) + return o +} + +// GoLow returns the low-level OAuthFlow instance used to create the high-level one. +func (o *OAuthFlow) GoLow() *low.OAuthFlow { + return o.low +} + +// GoLowUntyped will return the low-level Discriminator instance that was used to create the high-level one, with no type +func (o *OAuthFlow) GoLowUntyped() any { + return o.low +} + +// Render will return a YAML representation of the OAuthFlow object as a byte slice. +func (o *OAuthFlow) Render() ([]byte, error) { + return yaml.Marshal(o) +} + +// MarshalYAML will create a ready to render YAML representation of the OAuthFlow object. +func (o *OAuthFlow) MarshalYAML() (interface{}, error) { + nb := high.NewNodeBuilder(o, o.low) + return nb.Render(), nil +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/high/v3/oauth_flows.go b/vendor/github.com/pb33f/libopenapi/datamodel/high/v3/oauth_flows.go new file mode 100644 index 0000000000..16b6819d6c --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/high/v3/oauth_flows.go @@ -0,0 +1,66 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package v3 + +import ( + "github.com/pb33f/libopenapi/datamodel/high" + low "github.com/pb33f/libopenapi/datamodel/low/v3" + "gopkg.in/yaml.v3" +) + +// OAuthFlows represents a high-level OpenAPI 3+ OAuthFlows object that is backed by a low-level one. +// - https://spec.openapis.org/oas/v3.1.0#oauth-flows-object +type OAuthFlows struct { + Implicit *OAuthFlow `json:"implicit,omitempty" yaml:"implicit,omitempty"` + Password *OAuthFlow `json:"password,omitempty" yaml:"password,omitempty"` + ClientCredentials *OAuthFlow `json:"clientCredentials,omitempty" yaml:"clientCredentials,omitempty"` + AuthorizationCode *OAuthFlow `json:"authorizationCode,omitempty" yaml:"authorizationCode,omitempty"` + Extensions map[string]any `json:"-" yaml:"-"` + low *low.OAuthFlows +} + +// NewOAuthFlows creates a new high-level OAuthFlows instance from a low-level one. +func NewOAuthFlows(flows *low.OAuthFlows) *OAuthFlows { + o := new(OAuthFlows) + o.low = flows + if !flows.Implicit.IsEmpty() { + o.Implicit = NewOAuthFlow(flows.Implicit.Value) + } + if !flows.Password.IsEmpty() { + o.Password = NewOAuthFlow(flows.Password.Value) + } + if !flows.ClientCredentials.IsEmpty() { + o.ClientCredentials = NewOAuthFlow(flows.ClientCredentials.Value) + } + if !flows.AuthorizationCode.IsEmpty() { + o.AuthorizationCode = NewOAuthFlow(flows.AuthorizationCode.Value) + } + if !flows.Implicit.IsEmpty() { + o.Implicit = NewOAuthFlow(flows.Implicit.Value) + } + o.Extensions = high.ExtractExtensions(flows.Extensions) + return o +} + +// GoLow returns the low-level OAuthFlows instance used to create the high-level one. +func (o *OAuthFlows) GoLow() *low.OAuthFlows { + return o.low +} + +// GoLowUntyped will return the low-level OAuthFlows instance that was used to create the high-level one, with no type +func (o *OAuthFlows) GoLowUntyped() any { + return o.low +} + +// Render will return a YAML representation of the OAuthFlows object as a byte slice. +func (o *OAuthFlows) Render() ([]byte, error) { + return yaml.Marshal(o) +} + +// MarshalYAML will create a ready to render YAML representation of the OAuthFlows object. +func (o *OAuthFlows) MarshalYAML() (interface{}, error) { + nb := high.NewNodeBuilder(o, o.low) + return nb.Render(), nil +} + diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/high/v3/operation.go b/vendor/github.com/pb33f/libopenapi/datamodel/high/v3/operation.go new file mode 100644 index 0000000000..a338ed9cd2 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/high/v3/operation.go @@ -0,0 +1,119 @@ +// Copyright 2022-2023 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package v3 + +import ( + "github.com/pb33f/libopenapi/datamodel/high" + "github.com/pb33f/libopenapi/datamodel/high/base" + low "github.com/pb33f/libopenapi/datamodel/low/v3" + "gopkg.in/yaml.v3" +) + +// Operation is a high-level representation of an OpenAPI 3+ Operation object, backed by a low-level one. +// +// An Operation is perhaps the most important object of the entire specification. Everything of value +// happens here. The entire being for existence of this library and the specification, is this Operation. +// - https://spec.openapis.org/oas/v3.1.0#operation-object +type Operation struct { + Tags []string `json:"tags,omitempty" yaml:"tags,omitempty"` + Summary string `json:"summary,omitempty" yaml:"summary,omitempty"` + Description string `json:"description,omitempty" yaml:"description,omitempty"` + ExternalDocs *base.ExternalDoc `json:"externalDocs,omitempty" yaml:"externalDocs,omitempty"` + OperationId string `json:"operationId,omitempty" yaml:"operationId,omitempty"` + Parameters []*Parameter `json:"parameters,omitempty" yaml:"parameters,omitempty"` + RequestBody *RequestBody `json:"requestBody,omitempty" yaml:"requestBody,omitempty"` + Responses *Responses `json:"responses,omitempty" yaml:"responses,omitempty"` + Callbacks map[string]*Callback `json:"callbacks,omitempty" yaml:"callbacks,omitempty"` + Deprecated *bool `json:"deprecated,omitempty" yaml:"deprecated,omitempty"` + Security []*base.SecurityRequirement `json:"security,omitempty" yaml:"security,omitempty"` + Servers []*Server `json:"servers,omitempty" yaml:"servers,omitempty"` + Extensions map[string]any `json:"-" yaml:"-"` + low *low.Operation +} + +// NewOperation will create a new Operation instance from a low-level one. +func NewOperation(operation *low.Operation) *Operation { + o := new(Operation) + o.low = operation + var tags []string + if !operation.Tags.IsEmpty() { + for i := range operation.Tags.Value { + tags = append(tags, operation.Tags.Value[i].Value) + } + } + o.Tags = tags + o.Summary = operation.Summary.Value + o.Deprecated = &operation.Deprecated.Value + o.Description = operation.Description.Value + if !operation.ExternalDocs.IsEmpty() { + o.ExternalDocs = base.NewExternalDoc(operation.ExternalDocs.Value) + } + o.OperationId = operation.OperationId.Value + if !operation.Parameters.IsEmpty() { + params := make([]*Parameter, len(operation.Parameters.Value)) + for i := range operation.Parameters.Value { + params[i] = NewParameter(operation.Parameters.Value[i].Value) + } + o.Parameters = params + } + if !operation.RequestBody.IsEmpty() { + o.RequestBody = NewRequestBody(operation.RequestBody.Value) + } + if !operation.Responses.IsEmpty() { + o.Responses = NewResponses(operation.Responses.Value) + } + if !operation.Security.IsEmpty() { + var sec []*base.SecurityRequirement + for s := range operation.Security.Value { + sec = append(sec, base.NewSecurityRequirement(operation.Security.Value[s].Value)) + } + o.Security = sec + } + var servers []*Server + for i := range operation.Servers.Value { + servers = append(servers, NewServer(operation.Servers.Value[i].Value)) + } + o.Servers = servers + o.Extensions = high.ExtractExtensions(operation.Extensions) + if !operation.Callbacks.IsEmpty() { + cbs := make(map[string]*Callback) + for k, v := range operation.Callbacks.Value { + cbs[k.Value] = NewCallback(v.Value) + } + o.Callbacks = cbs + } + return o +} + +// GoLow will return the low-level Operation instance that was used to create the high-level one. +func (o *Operation) GoLow() *low.Operation { + return o.low +} + +// GoLowUntyped will return the low-level Discriminator instance that was used to create the high-level one, with no type +func (o *Operation) GoLowUntyped() any { + return o.low +} + +// Render will return a YAML representation of the Operation object as a byte slice. +func (o *Operation) Render() ([]byte, error) { + return yaml.Marshal(o) +} + +func (o *Operation) RenderInline() ([]byte, error) { + d, _ := o.MarshalYAMLInline() + return yaml.Marshal(d) +} + +// MarshalYAML will create a ready to render YAML representation of the Operation object. +func (o *Operation) MarshalYAML() (interface{}, error) { + nb := high.NewNodeBuilder(o, o.low) + return nb.Render(), nil +} + +func (o *Operation) MarshalYAMLInline() (interface{}, error) { + nb := high.NewNodeBuilder(o, o.low) + nb.Resolve = true + return nb.Render(), nil +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/high/v3/parameter.go b/vendor/github.com/pb33f/libopenapi/datamodel/high/v3/parameter.go new file mode 100644 index 0000000000..57313f2c13 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/high/v3/parameter.go @@ -0,0 +1,128 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package v3 + +import ( + "github.com/pb33f/libopenapi/datamodel/high" + "github.com/pb33f/libopenapi/datamodel/high/base" + low "github.com/pb33f/libopenapi/datamodel/low/v3" + "gopkg.in/yaml.v3" +) + +// Parameter represents a high-level OpenAPI 3+ Parameter object, that is backed by a low-level one. +// +// A unique parameter is defined by a combination of a name and location. +// - https://spec.openapis.org/oas/v3.1.0#parameter-object +type Parameter struct { + Name string `json:"name,omitempty" yaml:"name,omitempty"` + In string `json:"in,omitempty" yaml:"in,omitempty"` + Description string `json:"description,omitempty" yaml:"description,omitempty"` + Required bool `json:"required,omitempty" yaml:"required,omitempty"` + Deprecated bool `json:"deprecated,omitempty" yaml:"deprecated,omitempty"` + AllowEmptyValue bool `json:"allowEmptyValue,omitempty" yaml:"allowEmptyValue,omitempty"` + Style string `json:"style,omitempty" yaml:"style,omitempty"` + Explode *bool `json:"explode,omitempty" yaml:"explode,omitempty"` + AllowReserved bool `json:"allowReserved,omitempty" yaml:"allowReserved,omitempty"` + Schema *base.SchemaProxy `json:"schema,omitempty" yaml:"schema,omitempty"` + Example any `json:"example,omitempty" yaml:"example,omitempty"` + Examples map[string]*base.Example `json:"examples,omitempty" yaml:"examples,omitempty"` + Content map[string]*MediaType `json:"content,omitempty" yaml:"content,omitempty"` + Extensions map[string]any `json:"-" yaml:"-"` + low *low.Parameter +} + +// NewParameter will create a new high-level instance of a Parameter, using a low-level one. +func NewParameter(param *low.Parameter) *Parameter { + p := new(Parameter) + p.low = param + p.Name = param.Name.Value + p.In = param.In.Value + p.Description = param.Description.Value + p.Deprecated = param.Deprecated.Value + p.AllowEmptyValue = param.AllowEmptyValue.Value + p.Style = param.Style.Value + if !param.Explode.IsEmpty() { + p.Explode = ¶m.Explode.Value + } + p.AllowReserved = param.AllowReserved.Value + if !param.Schema.IsEmpty() { + p.Schema = base.NewSchemaProxy(¶m.Schema) + } + p.Required = param.Required.Value + p.Example = param.Example.Value + p.Examples = base.ExtractExamples(param.Examples.Value) + p.Content = ExtractContent(param.Content.Value) + p.Extensions = high.ExtractExtensions(param.Extensions) + return p +} + +// GoLow returns the low-level Parameter used to create the high-level one. +func (p *Parameter) GoLow() *low.Parameter { + return p.low +} + +// GoLowUntyped will return the low-level Discriminator instance that was used to create the high-level one, with no type +func (p *Parameter) GoLowUntyped() any { + return p.low +} + +// Render will return a YAML representation of the Encoding object as a byte slice. +func (p *Parameter) Render() ([]byte, error) { + return yaml.Marshal(p) +} + +func (p *Parameter) RenderInline() ([]byte, error) { + d, _ := p.MarshalYAMLInline() + return yaml.Marshal(d) +} + +// MarshalYAML will create a ready to render YAML representation of the Encoding object. +func (p *Parameter) MarshalYAML() (interface{}, error) { + nb := high.NewNodeBuilder(p, p.low) + return nb.Render(), nil +} + +func (p *Parameter) MarshalYAMLInline() (interface{}, error) { + nb := high.NewNodeBuilder(p, p.low) + nb.Resolve = true + return nb.Render(), nil +} + +// IsExploded will return true if the parameter is exploded, false otherwise. +func (p *Parameter) IsExploded() bool { + if p.Explode == nil { + return false + } + return *p.Explode +} + +// IsDefaultFormEncoding will return true if the parameter has no exploded value, or has exploded set to true, and no style +// or a style set to form. This combination is the default encoding/serialization style for parameters for OpenAPI 3+ +func (p *Parameter) IsDefaultFormEncoding() bool { + if p.Explode == nil && (p.Style == "" || p.Style == "form") { + return true + } + if p.Explode != nil && *p.Explode && (p.Style == "" || p.Style == "form") { + return true + } + return false +} + +// IsDefaultHeaderEncoding will return true if the parameter has no exploded value, or has exploded set to false, and no style +// or a style set to simple. This combination is the default encoding/serialization style for header parameters for OpenAPI 3+ +func (p *Parameter) IsDefaultHeaderEncoding() bool { + if p.Explode == nil && (p.Style == "" || p.Style == "simple") { + return true + } + if p.Explode != nil && !*p.Explode && (p.Style == "" || p.Style == "simple") { + return true + } + return false +} + +// IsDefaultPathEncoding will return true if the parameter has no exploded value, or has exploded set to false, and no style +// or a style set to simple. This combination is the default encoding/serialization style for path parameters for OpenAPI 3+ +func (p *Parameter) IsDefaultPathEncoding() bool { + return p.IsDefaultHeaderEncoding() // header default encoding and path default encoding are the same +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/high/v3/path_item.go b/vendor/github.com/pb33f/libopenapi/datamodel/high/v3/path_item.go new file mode 100644 index 0000000000..bd51cae584 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/high/v3/path_item.go @@ -0,0 +1,183 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package v3 + +import ( + "github.com/pb33f/libopenapi/datamodel/high" + low "github.com/pb33f/libopenapi/datamodel/low/v3" + "gopkg.in/yaml.v3" +) + +const ( + get = iota + put + post + del + options + head + patch + trace +) + +// PathItem represents a high-level OpenAPI 3+ PathItem object backed by a low-level one. +// +// Describes the operations available on a single path. A Path Item MAY be empty, due to ACL constraints. +// The path itself is still exposed to the documentation viewer but they will not know which operations and parameters +// are available. +// - https://spec.openapis.org/oas/v3.1.0#path-item-object +type PathItem struct { + Description string `json:"description,omitempty" yaml:"description,omitempty"` + Summary string `json:"summary,omitempty" yaml:"summary,omitempty"` + Get *Operation `json:"get,omitempty" yaml:"get,omitempty"` + Put *Operation `json:"put,omitempty" yaml:"put,omitempty"` + Post *Operation `json:"post,omitempty" yaml:"post,omitempty"` + Delete *Operation `json:"delete,omitempty" yaml:"delete,omitempty"` + Options *Operation `json:"options,omitempty" yaml:"options,omitempty"` + Head *Operation `json:"head,omitempty" yaml:"head,omitempty"` + Patch *Operation `json:"patch,omitempty" yaml:"patch,omitempty"` + Trace *Operation `json:"trace,omitempty" yaml:"trace,omitempty"` + Servers []*Server `json:"servers,omitempty" yaml:"servers,omitempty"` + Parameters []*Parameter `json:"parameters,omitempty" yaml:"parameters,omitempty"` + Extensions map[string]any `json:"-" yaml:"-"` + low *low.PathItem +} + +// NewPathItem creates a new high-level PathItem instance from a low-level one. +func NewPathItem(pathItem *low.PathItem) *PathItem { + pi := new(PathItem) + pi.low = pathItem + pi.Description = pathItem.Description.Value + pi.Summary = pathItem.Summary.Value + pi.Extensions = high.ExtractExtensions(pathItem.Extensions) + var servers []*Server + for _, ser := range pathItem.Servers.Value { + servers = append(servers, NewServer(ser.Value)) + } + pi.Servers = servers + + // build operation async + type opResult struct { + method int + op *Operation + } + opChan := make(chan opResult) + var buildOperation = func(method int, op *low.Operation, c chan opResult) { + if op == nil { + c <- opResult{method: method, op: nil} + return + } + c <- opResult{method: method, op: NewOperation(op)} + } + // build out operations async. + go buildOperation(get, pathItem.Get.Value, opChan) + go buildOperation(put, pathItem.Put.Value, opChan) + go buildOperation(post, pathItem.Post.Value, opChan) + go buildOperation(del, pathItem.Delete.Value, opChan) + go buildOperation(options, pathItem.Options.Value, opChan) + go buildOperation(head, pathItem.Head.Value, opChan) + go buildOperation(patch, pathItem.Patch.Value, opChan) + go buildOperation(trace, pathItem.Trace.Value, opChan) + + if !pathItem.Parameters.IsEmpty() { + params := make([]*Parameter, len(pathItem.Parameters.Value)) + for i := range pathItem.Parameters.Value { + params[i] = NewParameter(pathItem.Parameters.Value[i].Value) + } + pi.Parameters = params + } + + complete := false + opCount := 0 + for !complete { + select { + case opRes := <-opChan: + switch opRes.method { + case get: + pi.Get = opRes.op + case put: + pi.Put = opRes.op + case post: + pi.Post = opRes.op + case del: + pi.Delete = opRes.op + case options: + pi.Options = opRes.op + case head: + pi.Head = opRes.op + case patch: + pi.Patch = opRes.op + case trace: + pi.Trace = opRes.op + } + } + opCount++ + if opCount == 8 { + complete = true + } + } + return pi +} + +// GoLow returns the low level instance of PathItem, used to build the high-level one. +func (p *PathItem) GoLow() *low.PathItem { + return p.low +} + +// GoLowUntyped will return the low-level PathItem instance that was used to create the high-level one, with no type +func (p *PathItem) GoLowUntyped() any { + return p.low +} + +func (p *PathItem) GetOperations() map[string]*Operation { + o := make(map[string]*Operation) + if p.Get != nil { + o[low.GetLabel] = p.Get + } + if p.Put != nil { + o[low.PutLabel] = p.Put + } + if p.Post != nil { + o[low.PostLabel] = p.Post + } + if p.Delete != nil { + o[low.DeleteLabel] = p.Delete + } + if p.Options != nil { + o[low.OptionsLabel] = p.Options + } + if p.Head != nil { + o[low.HeadLabel] = p.Head + } + if p.Patch != nil { + o[low.PatchLabel] = p.Patch + } + if p.Trace != nil { + o[low.TraceLabel] = p.Trace + } + return o +} + +// Render will return a YAML representation of the PathItem object as a byte slice. +func (p *PathItem) Render() ([]byte, error) { + return yaml.Marshal(p) +} + +func (p *PathItem) RenderInline() ([]byte, error) { + d, _ := p.MarshalYAMLInline() + return yaml.Marshal(d) +} + +// MarshalYAML will create a ready to render YAML representation of the PathItem object. +func (p *PathItem) MarshalYAML() (interface{}, error) { + nb := high.NewNodeBuilder(p, p.low) + return nb.Render(), nil +} + +func (p *PathItem) MarshalYAMLInline() (interface{}, error) { + nb := high.NewNodeBuilder(p, p.low) + + nb.Resolve = true + + return nb.Render(), nil +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/high/v3/paths.go b/vendor/github.com/pb33f/libopenapi/datamodel/high/v3/paths.go new file mode 100644 index 0000000000..7927049d00 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/high/v3/paths.go @@ -0,0 +1,186 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package v3 + +import ( + "sort" + + "github.com/pb33f/libopenapi/datamodel/high" + low "github.com/pb33f/libopenapi/datamodel/low/v3" + "github.com/pb33f/libopenapi/utils" + "gopkg.in/yaml.v3" +) + +// Paths represents a high-level OpenAPI 3+ Paths object, that is backed by a low-level one. +// +// Holds the relative paths to the individual endpoints and their operations. The path is appended to the URL from the +// Server Object in order to construct the full URL. The Paths MAY be empty, due to Access Control List (ACL) +// constraints. +// - https://spec.openapis.org/oas/v3.1.0#paths-object +type Paths struct { + PathItems map[string]*PathItem `json:"-" yaml:"-"` + Extensions map[string]any `json:"-" yaml:"-"` + low *low.Paths +} + +// NewPaths creates a new high-level instance of Paths from a low-level one. +func NewPaths(paths *low.Paths) *Paths { + p := new(Paths) + p.low = paths + p.Extensions = high.ExtractExtensions(paths.Extensions) + items := make(map[string]*PathItem) + + // build paths async for speed. + type pRes struct { + k string + v *PathItem + } + var buildPathItem = func(key string, item *low.PathItem, c chan<- pRes) { + c <- pRes{key, NewPathItem(item)} + } + rChan := make(chan pRes) + for k := range paths.PathItems { + go buildPathItem(k.Value, paths.PathItems[k].Value, rChan) + } + pathsBuilt := 0 + for pathsBuilt < len(paths.PathItems) { + select { + case r := <-rChan: + pathsBuilt++ + items[r.k] = r.v + } + } + p.PathItems = items + return p +} + +// GoLow returns the low-level Paths instance used to create the high-level one. +func (p *Paths) GoLow() *low.Paths { + return p.low +} + +// GoLowUntyped will return the low-level Paths instance that was used to create the high-level one, with no type +func (p *Paths) GoLowUntyped() any { + return p.low +} + +// Render will return a YAML representation of the Paths object as a byte slice. +func (p *Paths) Render() ([]byte, error) { + return yaml.Marshal(p) +} + +func (p *Paths) RenderInline() ([]byte, error) { + d, _ := p.MarshalYAMLInline() + return yaml.Marshal(d) +} + +// MarshalYAML will create a ready to render YAML representation of the Paths object. +func (p *Paths) MarshalYAML() (interface{}, error) { + // map keys correctly. + m := utils.CreateEmptyMapNode() + type pathItem struct { + pi *PathItem + path string + line int + rendered *yaml.Node + } + var mapped []*pathItem + + for k, pi := range p.PathItems { + ln := 9999 // default to a high value to weight new content to the bottom. + if p.low != nil { + lpi := p.low.FindPath(k) + if lpi != nil { + ln = lpi.ValueNode.Line + } + } + mapped = append(mapped, &pathItem{pi, k, ln, nil}) + } + + nb := high.NewNodeBuilder(p, p.low) + extNode := nb.Render() + if extNode != nil && extNode.Content != nil { + var label string + for u := range extNode.Content { + if u%2 == 0 { + label = extNode.Content[u].Value + continue + } + mapped = append(mapped, &pathItem{nil, label, + extNode.Content[u].Line, extNode.Content[u]}) + } + } + + sort.Slice(mapped, func(i, j int) bool { + return mapped[i].line < mapped[j].line + }) + for j := range mapped { + if mapped[j].pi != nil { + rendered, _ := mapped[j].pi.MarshalYAML() + m.Content = append(m.Content, utils.CreateStringNode(mapped[j].path)) + m.Content = append(m.Content, rendered.(*yaml.Node)) + } + if mapped[j].rendered != nil { + m.Content = append(m.Content, utils.CreateStringNode(mapped[j].path)) + m.Content = append(m.Content, mapped[j].rendered) + } + } + + return m, nil +} + +func (p *Paths) MarshalYAMLInline() (interface{}, error) { + // map keys correctly. + m := utils.CreateEmptyMapNode() + type pathItem struct { + pi *PathItem + path string + line int + rendered *yaml.Node + } + var mapped []*pathItem + + for k, pi := range p.PathItems { + ln := 9999 // default to a high value to weight new content to the bottom. + if p.low != nil { + lpi := p.low.FindPath(k) + if lpi != nil { + ln = lpi.ValueNode.Line + } + } + mapped = append(mapped, &pathItem{pi, k, ln, nil}) + } + + nb := high.NewNodeBuilder(p, p.low) + nb.Resolve = true + extNode := nb.Render() + if extNode != nil && extNode.Content != nil { + var label string + for u := range extNode.Content { + if u%2 == 0 { + label = extNode.Content[u].Value + continue + } + mapped = append(mapped, &pathItem{nil, label, + extNode.Content[u].Line, extNode.Content[u]}) + } + } + + sort.Slice(mapped, func(i, j int) bool { + return mapped[i].line < mapped[j].line + }) + for j := range mapped { + if mapped[j].pi != nil { + rendered, _ := mapped[j].pi.MarshalYAMLInline() + m.Content = append(m.Content, utils.CreateStringNode(mapped[j].path)) + m.Content = append(m.Content, rendered.(*yaml.Node)) + } + if mapped[j].rendered != nil { + m.Content = append(m.Content, utils.CreateStringNode(mapped[j].path)) + m.Content = append(m.Content, mapped[j].rendered) + } + } + + return m, nil +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/high/v3/request_body.go b/vendor/github.com/pb33f/libopenapi/datamodel/high/v3/request_body.go new file mode 100644 index 0000000000..8fee1ad1ae --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/high/v3/request_body.go @@ -0,0 +1,65 @@ +// Copyright 2022-2023 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package v3 + +import ( + "github.com/pb33f/libopenapi/datamodel/high" + low "github.com/pb33f/libopenapi/datamodel/low/v3" + "gopkg.in/yaml.v3" +) + +// RequestBody represents a high-level OpenAPI 3+ RequestBody object, backed by a low-level one. +// - https://spec.openapis.org/oas/v3.1.0#request-body-object +type RequestBody struct { + Description string `json:"description,omitempty" yaml:"description,omitempty"` + Content map[string]*MediaType `json:"content,omitempty" yaml:"content,omitempty"` + Required *bool `json:"required,omitempty" yaml:"required,renderZero,omitempty"` + Extensions map[string]any `json:"-" yaml:"-"` + low *low.RequestBody +} + +// NewRequestBody will create a new high-level RequestBody instance, from a low-level one. +func NewRequestBody(rb *low.RequestBody) *RequestBody { + r := new(RequestBody) + r.low = rb + r.Description = rb.Description.Value + if rb.Required.ValueNode != nil { + r.Required = &rb.Required.Value + } + r.Extensions = high.ExtractExtensions(rb.Extensions) + r.Content = ExtractContent(rb.Content.Value) + return r +} + +// GoLow returns the low-level RequestBody instance used to create the high-level one. +func (r *RequestBody) GoLow() *low.RequestBody { + return r.low +} + +// GoLowUntyped will return the low-level RequestBody instance that was used to create the high-level one, with no type +func (r *RequestBody) GoLowUntyped() any { + return r.low +} + +// Render will return a YAML representation of the RequestBody object as a byte slice. +func (r *RequestBody) Render() ([]byte, error) { + return yaml.Marshal(r) +} + +func (r *RequestBody) RenderInline() ([]byte, error) { + d, _ := r.MarshalYAMLInline() + return yaml.Marshal(d) +} + +// MarshalYAML will create a ready to render YAML representation of the RequestBody object. +func (r *RequestBody) MarshalYAML() (interface{}, error) { + nb := high.NewNodeBuilder(r, r.low) + return nb.Render(), nil +} + +func (r *RequestBody) MarshalYAMLInline() (interface{}, error) { + nb := high.NewNodeBuilder(r, r.low) + nb.Resolve = true + return nb.Render(), nil +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/high/v3/response.go b/vendor/github.com/pb33f/libopenapi/datamodel/high/v3/response.go new file mode 100644 index 0000000000..c2866caf2f --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/high/v3/response.go @@ -0,0 +1,78 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package v3 + +import ( + "github.com/pb33f/libopenapi/datamodel/high" + low "github.com/pb33f/libopenapi/datamodel/low/v3" + "gopkg.in/yaml.v3" +) + +// Response represents a high-level OpenAPI 3+ Response object that is backed by a low-level one. +// +// Describes a single response from an API Operation, including design-time, static links to +// operations based on the response. +// - https://spec.openapis.org/oas/v3.1.0#response-object +type Response struct { + Description string `json:"description,omitempty" yaml:"description,omitempty"` + Headers map[string]*Header `json:"headers,omitempty" yaml:"headers,omitempty"` + Content map[string]*MediaType `json:"content,omitempty" yaml:"content,omitempty"` + Links map[string]*Link `json:"links,omitempty" yaml:"links,omitempty"` + Extensions map[string]any `json:"-" yaml:"-"` + low *low.Response +} + +// NewResponse creates a new high-level Response object that is backed by a low-level one. +func NewResponse(response *low.Response) *Response { + r := new(Response) + r.low = response + r.Description = response.Description.Value + if !response.Headers.IsEmpty() { + r.Headers = ExtractHeaders(response.Headers.Value) + } + r.Extensions = high.ExtractExtensions(response.Extensions) + if !response.Content.IsEmpty() { + r.Content = ExtractContent(response.Content.Value) + } + if !response.Links.IsEmpty() { + responseLinks := make(map[string]*Link) + for k, v := range response.Links.Value { + responseLinks[k.Value] = NewLink(v.Value) + } + r.Links = responseLinks + } + return r +} + +// GoLow returns the low-level Response object that was used to create the high-level one. +func (r *Response) GoLow() *low.Response { + return r.low +} + +// GoLowUntyped will return the low-level Response instance that was used to create the high-level one, with no type +func (r *Response) GoLowUntyped() any { + return r.low +} + +// Render will return a YAML representation of the Response object as a byte slice. +func (r *Response) Render() ([]byte, error) { + return yaml.Marshal(r) +} + +func (r *Response) RenderInline() ([]byte, error) { + d, _ := r.MarshalYAMLInline() + return yaml.Marshal(d) +} + +// MarshalYAML will create a ready to render YAML representation of the Response object. +func (r *Response) MarshalYAML() (interface{}, error) { + nb := high.NewNodeBuilder(r, r.low) + return nb.Render(), nil +} + +func (r *Response) MarshalYAMLInline() (interface{}, error) { + nb := high.NewNodeBuilder(r, r.low) + nb.Resolve = true + return nb.Render(), nil +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/high/v3/responses.go b/vendor/github.com/pb33f/libopenapi/datamodel/high/v3/responses.go new file mode 100644 index 0000000000..1a86d079a9 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/high/v3/responses.go @@ -0,0 +1,213 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package v3 + +import ( + "fmt" + "sort" + + "github.com/pb33f/libopenapi/datamodel/high" + low "github.com/pb33f/libopenapi/datamodel/low/v3" + "github.com/pb33f/libopenapi/utils" + "gopkg.in/yaml.v3" +) + +// Responses represents a high-level OpenAPI 3+ Responses object that is backed by a low-level one. +// +// It's a container for the expected responses of an operation. The container maps a HTTP response code to the +// expected response. +// +// The specification is not necessarily expected to cover all possible HTTP response codes because they may not be +// known in advance. However, documentation is expected to cover a successful operation response and any known errors. +// +// The default MAY be used as a default response object for all HTTP codes that are not covered individually by +// the Responses Object. +// +// The Responses Object MUST contain at least one response code, and if only one response code is provided it SHOULD +// be the response for a successful operation call. +// - https://spec.openapis.org/oas/v3.1.0#responses-object +type Responses struct { + Codes map[string]*Response `json:"-" yaml:"-"` + Default *Response `json:"default,omitempty" yaml:"default,omitempty"` + Extensions map[string]any `json:"-" yaml:"-"` + low *low.Responses +} + +// NewResponses will create a new high-level Responses instance from a low-level one. It operates asynchronously +// internally, as each response may be considerable in complexity. +func NewResponses(responses *low.Responses) *Responses { + r := new(Responses) + r.low = responses + r.Extensions = high.ExtractExtensions(responses.Extensions) + if !responses.Default.IsEmpty() { + r.Default = NewResponse(responses.Default.Value) + } + codes := make(map[string]*Response) + + // struct to hold response and code sent over chan. + type respRes struct { + code string + resp *Response + } + + // build each response async for speed + rChan := make(chan respRes) + var buildResponse = func(code string, resp *low.Response, c chan respRes) { + c <- respRes{code: code, resp: NewResponse(resp)} + } + for k, v := range responses.Codes { + go buildResponse(k.Value, v.Value, rChan) + } + totalCodes := len(responses.Codes) + codesParsed := 0 + for codesParsed < totalCodes { + select { + case re := <-rChan: + codesParsed++ + codes[re.code] = re.resp + } + } + r.Codes = codes + return r +} + +// FindResponseByCode is a shortcut for looking up code by an integer vs. a string +func (r *Responses) FindResponseByCode(code int) *Response { + return r.Codes[fmt.Sprintf("%d", code)] +} + +// GoLow returns the low-level Response object used to create the high-level one. +func (r *Responses) GoLow() *low.Responses { + return r.low +} + +// GoLowUntyped will return the low-level Responses instance that was used to create the high-level one, with no type +func (r *Responses) GoLowUntyped() any { + return r.low +} + +// Render will return a YAML representation of the Responses object as a byte slice. +func (r *Responses) Render() ([]byte, error) { + return yaml.Marshal(r) +} + +func (r *Responses) RenderInline() ([]byte, error) { + d, _ := r.MarshalYAMLInline() + return yaml.Marshal(d) +} + +// MarshalYAML will create a ready to render YAML representation of the Responses object. +func (r *Responses) MarshalYAML() (interface{}, error) { + // map keys correctly. + m := utils.CreateEmptyMapNode() + type responseItem struct { + resp *Response + code string + line int + ext *yaml.Node + } + var mapped []*responseItem + + for k, re := range r.Codes { + ln := 9999 // default to a high value to weight new content to the bottom. + if r.low != nil { + for lKey := range r.low.Codes { + if lKey.Value == k { + ln = lKey.KeyNode.Line + } + } + } + mapped = append(mapped, &responseItem{re, k, ln, nil}) + } + + // extract extensions + nb := high.NewNodeBuilder(r, r.low) + extNode := nb.Render() + if extNode != nil && extNode.Content != nil { + var label string + for u := range extNode.Content { + if u%2 == 0 { + label = extNode.Content[u].Value + continue + } + mapped = append(mapped, &responseItem{nil, label, + extNode.Content[u].Line, extNode.Content[u]}) + } + } + + sort.Slice(mapped, func(i, j int) bool { + return mapped[i].line < mapped[j].line + }) + for j := range mapped { + if mapped[j].resp != nil { + rendered, _ := mapped[j].resp.MarshalYAML() + m.Content = append(m.Content, utils.CreateStringNode(mapped[j].code)) + m.Content = append(m.Content, rendered.(*yaml.Node)) + } + if mapped[j].ext != nil { + m.Content = append(m.Content, utils.CreateStringNode(mapped[j].code)) + m.Content = append(m.Content, mapped[j].ext) + } + + } + return m, nil +} + +func (r *Responses) MarshalYAMLInline() (interface{}, error) { + // map keys correctly. + m := utils.CreateEmptyMapNode() + type responseItem struct { + resp *Response + code string + line int + ext *yaml.Node + } + var mapped []*responseItem + + for k, re := range r.Codes { + ln := 9999 // default to a high value to weight new content to the bottom. + if r.low != nil { + for lKey := range r.low.Codes { + if lKey.Value == k { + ln = lKey.KeyNode.Line + } + } + } + mapped = append(mapped, &responseItem{re, k, ln, nil}) + } + + // extract extensions + nb := high.NewNodeBuilder(r, r.low) + nb.Resolve = true + extNode := nb.Render() + if extNode != nil && extNode.Content != nil { + var label string + for u := range extNode.Content { + if u%2 == 0 { + label = extNode.Content[u].Value + continue + } + mapped = append(mapped, &responseItem{nil, label, + extNode.Content[u].Line, extNode.Content[u]}) + } + } + + sort.Slice(mapped, func(i, j int) bool { + return mapped[i].line < mapped[j].line + }) + for j := range mapped { + if mapped[j].resp != nil { + rendered, _ := mapped[j].resp.MarshalYAMLInline() + m.Content = append(m.Content, utils.CreateStringNode(mapped[j].code)) + m.Content = append(m.Content, rendered.(*yaml.Node)) + + } + if mapped[j].ext != nil { + m.Content = append(m.Content, utils.CreateStringNode(mapped[j].code)) + m.Content = append(m.Content, mapped[j].ext) + } + + } + return m, nil +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/high/v3/security_scheme.go b/vendor/github.com/pb33f/libopenapi/datamodel/high/v3/security_scheme.go new file mode 100644 index 0000000000..3b0597f17f --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/high/v3/security_scheme.go @@ -0,0 +1,72 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package v3 + +import ( + "github.com/pb33f/libopenapi/datamodel/high" + low "github.com/pb33f/libopenapi/datamodel/low/v3" + "gopkg.in/yaml.v3" +) + +// SecurityScheme represents a high-level OpenAPI 3+ SecurityScheme object that is backed by a low-level one. +// +// Defines a security scheme that can be used by the operations. +// +// Supported schemes are HTTP authentication, an API key (either as a header, a cookie parameter or as a query parameter), +// mutual TLS (use of a client certificate), OAuth2’s common flows (implicit, password, client credentials and +// authorization code) as defined in RFC6749 (https://www.rfc-editor.org/rfc/rfc6749), and OpenID Connect Discovery. +// Please note that as of 2020, the implicit flow is about to be deprecated by OAuth 2.0 Security Best Current Practice. +// Recommended for most use case is Authorization Code Grant flow with PKCE. +// - https://spec.openapis.org/oas/v3.1.0#security-scheme-object +type SecurityScheme struct { + Type string `json:"type,omitempty" yaml:"type,omitempty"` + Description string `json:"description,omitempty" yaml:"description,omitempty"` + Name string `json:"name,omitempty" yaml:"name,omitempty"` + In string `json:"in,omitempty" yaml:"in,omitempty"` + Scheme string `json:"scheme,omitempty" yaml:"scheme,omitempty"` + BearerFormat string `json:"bearerFormat,omitempty" yaml:"bearerFormat,omitempty"` + Flows *OAuthFlows `json:"flows,omitempty" yaml:"flows,omitempty"` + OpenIdConnectUrl string `json:"openIdConnectUrl,omitempty" yaml:"openIdConnectUrl,omitempty"` + Extensions map[string]any `json:"-" yaml:"-"` + low *low.SecurityScheme +} + +// NewSecurityScheme creates a new high-level SecurityScheme from a low-level one. +func NewSecurityScheme(ss *low.SecurityScheme) *SecurityScheme { + s := new(SecurityScheme) + s.low = ss + s.Type = ss.Type.Value + s.Description = ss.Description.Value + s.Name = ss.Name.Value + s.Scheme = ss.Scheme.Value + s.In = ss.In.Value + s.BearerFormat = ss.BearerFormat.Value + s.OpenIdConnectUrl = ss.OpenIdConnectUrl.Value + s.Extensions = high.ExtractExtensions(ss.Extensions) + if !ss.Flows.IsEmpty() { + s.Flows = NewOAuthFlows(ss.Flows.Value) + } + return s +} + +// GoLow returns the low-level SecurityScheme that was used to create the high-level one. +func (s *SecurityScheme) GoLow() *low.SecurityScheme { + return s.low +} + +// GoLowUntyped will return the low-level SecurityScheme instance that was used to create the high-level one, with no type +func (s *SecurityScheme) GoLowUntyped() any { + return s.low +} + +// Render will return a YAML representation of the SecurityScheme object as a byte slice. +func (s *SecurityScheme) Render() ([]byte, error) { + return yaml.Marshal(s) +} + +// MarshalYAML will create a ready to render YAML representation of the Response object. +func (s *SecurityScheme) MarshalYAML() (interface{}, error) { + nb := high.NewNodeBuilder(s, s.low) + return nb.Render(), nil +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/high/v3/server.go b/vendor/github.com/pb33f/libopenapi/datamodel/high/v3/server.go new file mode 100644 index 0000000000..0f9d63e3fe --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/high/v3/server.go @@ -0,0 +1,56 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package v3 + +import ( + "github.com/pb33f/libopenapi/datamodel/high" + low "github.com/pb33f/libopenapi/datamodel/low/v3" + "gopkg.in/yaml.v3" +) + +// Server represents a high-level OpenAPI 3+ Server object, that is backed by a low level one. +// - https://spec.openapis.org/oas/v3.1.0#server-object +type Server struct { + URL string `json:"url,omitempty" yaml:"url,omitempty"` + Description string `json:"description,omitempty" yaml:"description,omitempty"` + Variables map[string]*ServerVariable `json:"variables,omitempty" yaml:"variables,omitempty"` + Extensions map[string]any `json:"-" yaml:"-"` + low *low.Server +} + +// NewServer will create a new high-level Server instance from a low-level one. +func NewServer(server *low.Server) *Server { + s := new(Server) + s.low = server + s.Description = server.Description.Value + s.URL = server.URL.Value + vars := make(map[string]*ServerVariable) + for k, val := range server.Variables.Value { + vars[k.Value] = NewServerVariable(val.Value) + } + s.Variables = vars + s.Extensions = high.ExtractExtensions(server.Extensions) + return s +} + +// GoLow returns the low-level Server instance that was used to create the high-level one +func (s *Server) GoLow() *low.Server { + return s.low +} + +// GoLowUntyped will return the low-level Server instance that was used to create the high-level one, with no type +func (s *Server) GoLowUntyped() any { + return s.low +} + +// Render will return a YAML representation of the Server object as a byte slice. +func (s *Server) Render() ([]byte, error) { + return yaml.Marshal(s) +} + +// MarshalYAML will create a ready to render YAML representation of the Server object. +func (s *Server) MarshalYAML() (interface{}, error) { + nb := high.NewNodeBuilder(s, s.low) + return nb.Render(), nil +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/high/v3/server_variable.go b/vendor/github.com/pb33f/libopenapi/datamodel/high/v3/server_variable.go new file mode 100644 index 0000000000..160fb462ed --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/high/v3/server_variable.go @@ -0,0 +1,58 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package v3 + +import ( + "github.com/pb33f/libopenapi/datamodel/high" + low "github.com/pb33f/libopenapi/datamodel/low/v3" + "gopkg.in/yaml.v3" +) + +// ServerVariable represents a high-level OpenAPI 3+ ServerVariable object, that is backed by a low-level one. +// +// ServerVariable is an object representing a Server Variable for server URL template substitution. +// - https://spec.openapis.org/oas/v3.1.0#server-variable-object +type ServerVariable struct { + Enum []string `json:"enum,omitempty" yaml:"enum,omitempty"` + Default string `json:"default,omitempty" yaml:"default,omitempty"` + Description string `json:"description,omitempty" yaml:"description,omitempty"` + low *low.ServerVariable +} + +// NewServerVariable will return a new high-level instance of a ServerVariable from a low-level one. +func NewServerVariable(variable *low.ServerVariable) *ServerVariable { + v := new(ServerVariable) + v.low = variable + var enums []string + for _, enum := range variable.Enum { + if enum.Value != "" { + enums = append(enums, enum.Value) + } + } + v.Default = variable.Default.Value + v.Description = variable.Description.Value + v.Enum = enums + return v +} + +// GoLow returns the low-level ServerVariable used to create the high\-level one. +func (s *ServerVariable) GoLow() *low.ServerVariable { + return s.low +} + +// GoLowUntyped will return the low-level ServerVariable instance that was used to create the high-level one, with no type +func (s *ServerVariable) GoLowUntyped() any { + return s.low +} + +// Render will return a YAML representation of the ServerVariable object as a byte slice. +func (s *ServerVariable) Render() ([]byte, error) { + return yaml.Marshal(s) +} + +// MarshalYAML will create a ready to render YAML representation of the ServerVariable object. +func (s *ServerVariable) MarshalYAML() (interface{}, error) { + nb := high.NewNodeBuilder(s, s.low) + return nb.Render(), nil +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/low/base/base.go b/vendor/github.com/pb33f/libopenapi/datamodel/low/base/base.go new file mode 100644 index 0000000000..1fa6287b9c --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/low/base/base.go @@ -0,0 +1,12 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +// Package base contains shared low-level models that are used between both versions 2 and 3 of OpenAPI. +// These models are consistent across both specifications, except for the Schema. +// +// OpenAPI 3 contains all the same properties that an OpenAPI 2 specification does, and more. The choice +// to not duplicate the schemas is to allow a graceful degradation pattern to be used. Schemas are the most complex +// beats, particularly when polymorphism is used. By re-using the same superset Schema across versions, we can ensure +// that all the latest features are collected, without damaging backwards compatibility. +package base + diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/low/base/constants.go b/vendor/github.com/pb33f/libopenapi/datamodel/low/base/constants.go new file mode 100644 index 0000000000..dd48f401ce --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/low/base/constants.go @@ -0,0 +1,54 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package base + +// Constants for labels used to look up values within OpenAPI specifications. +const ( + VersionLabel = "version" + TermsOfServiceLabel = "termsOfService" + DescriptionLabel = "description" + TitleLabel = "title" + EmailLabel = "email" + NameLabel = "name" + URLLabel = "url" + TagsLabel = "tags" + ExternalDocsLabel = "externalDocs" + ExamplesLabel = "examples" + ExampleLabel = "example" + ValueLabel = "value" + InfoLabel = "info" + ContactLabel = "contact" + LicenseLabel = "license" + PropertiesLabel = "properties" + DependentSchemasLabel = "dependentSchemas" + PatternPropertiesLabel = "patternProperties" + IfLabel = "if" + ElseLabel = "else" + ThenLabel = "then" + PropertyNamesLabel = "propertyNames" + UnevaluatedItemsLabel = "unevaluatedItems" + UnevaluatedPropertiesLabel = "unevaluatedProperties" + AdditionalPropertiesLabel = "additionalProperties" + XMLLabel = "xml" + ItemsLabel = "items" + PrefixItemsLabel = "prefixItems" + ContainsLabel = "contains" + AllOfLabel = "allOf" + AnyOfLabel = "anyOf" + OneOfLabel = "oneOf" + NotLabel = "not" + TypeLabel = "type" + DiscriminatorLabel = "discriminator" + ExclusiveMinimumLabel = "exclusiveMinimum" + ExclusiveMaximumLabel = "exclusiveMaximum" + SchemaLabel = "schema" + SchemaTypeLabel = "$schema" + AnchorLabel = "$anchor" +) + +/* +PropertyNames low.NodeReference[*SchemaProxy] + UnevaluatedItems low.NodeReference[*SchemaProxy] + UnevaluatedProperties low.NodeReference[*SchemaProxy] +*/ diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/low/base/contact.go b/vendor/github.com/pb33f/libopenapi/datamodel/low/base/contact.go new file mode 100644 index 0000000000..f232678814 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/low/base/contact.go @@ -0,0 +1,45 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package base + +import ( + "crypto/sha256" + "github.com/pb33f/libopenapi/datamodel/low" + "github.com/pb33f/libopenapi/index" + "gopkg.in/yaml.v3" + "strings" +) + +// Contact represents a low-level representation of the Contact definitions found at +// v2 - https://swagger.io/specification/v2/#contactObject +// v3 - https://spec.openapis.org/oas/v3.1.0#contact-object +type Contact struct { + Name low.NodeReference[string] + URL low.NodeReference[string] + Email low.NodeReference[string] + *low.Reference +} + +// Build is not implemented for Contact (there is nothing to build). +func (c *Contact) Build(root *yaml.Node, idx *index.SpecIndex) error { + c.Reference = new(low.Reference) + // not implemented. + return nil +} + +// Hash will return a consistent SHA256 Hash of the Contact object +func (c *Contact) Hash() [32]byte { + var f []string + if !c.Name.IsEmpty() { + f = append(f, c.Name.Value) + } + if !c.URL.IsEmpty() { + f = append(f, c.URL.Value) + } + if !c.Email.IsEmpty() { + f = append(f, c.Email.Value) + } + return sha256.Sum256([]byte(strings.Join(f, "|"))) +} + diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/low/base/discriminator.go b/vendor/github.com/pb33f/libopenapi/datamodel/low/base/discriminator.go new file mode 100644 index 0000000000..09c428c0c1 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/low/base/discriminator.go @@ -0,0 +1,55 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package base + +import ( + "crypto/sha256" + "github.com/pb33f/libopenapi/datamodel/low" + "sort" + "strings" +) + +// Discriminator is only used by OpenAPI 3+ documents, it represents a polymorphic discriminator used for schemas +// +// When request bodies or response payloads may be one of a number of different schemas, a discriminator object can be +// used to aid in serialization, deserialization, and validation. The discriminator is a specific object in a schema +// which is used to inform the consumer of the document of an alternative schema based on the value associated with it. +// +// When using the discriminator, inline schemas will not be considered. +// v3 - https://spec.openapis.org/oas/v3.1.0#discriminator-object +type Discriminator struct { + PropertyName low.NodeReference[string] + Mapping low.NodeReference[map[low.KeyReference[string]]low.ValueReference[string]] + low.Reference +} + +// FindMappingValue will return a ValueReference containing the string mapping value +func (d *Discriminator) FindMappingValue(key string) *low.ValueReference[string] { + for k, v := range d.Mapping.Value { + if k.Value == key { + return &v + } + } + return nil +} + +// Hash will return a consistent SHA256 Hash of the Discriminator object +func (d *Discriminator) Hash() [32]byte { + + // calculate a hash from every property. + var f []string + if d.PropertyName.Value != "" { + f = append(f, d.PropertyName.Value) + } + propertyKeys := make([]string, 0, len(d.Mapping.Value)) + for i := range d.Mapping.Value { + propertyKeys = append(propertyKeys, i.Value) + } + sort.Strings(propertyKeys) + for k := range propertyKeys { + prop := d.FindMappingValue(propertyKeys[k]) + f = append(f, prop.Value) + } + return sha256.Sum256([]byte(strings.Join(f, "|"))) +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/low/base/example.go b/vendor/github.com/pb33f/libopenapi/datamodel/low/base/example.go new file mode 100644 index 0000000000..73571fa7aa --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/low/base/example.go @@ -0,0 +1,132 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package base + +import ( + "crypto/sha256" + "fmt" + "github.com/pb33f/libopenapi/datamodel/low" + "github.com/pb33f/libopenapi/index" + "github.com/pb33f/libopenapi/utils" + "gopkg.in/yaml.v3" + "sort" + "strconv" + "strings" +) + +// Example represents a low-level Example object as defined by OpenAPI 3+ +// v3 - https://spec.openapis.org/oas/v3.1.0#example-object +type Example struct { + Summary low.NodeReference[string] + Description low.NodeReference[string] + Value low.NodeReference[any] + ExternalValue low.NodeReference[string] + Extensions map[low.KeyReference[string]]low.ValueReference[any] + *low.Reference +} + +// FindExtension returns a ValueReference containing the extension value, if found. +func (ex *Example) FindExtension(ext string) *low.ValueReference[any] { + return low.FindItemInMap[any](ext, ex.Extensions) +} + +// Hash will return a consistent SHA256 Hash of the Discriminator object +func (ex *Example) Hash() [32]byte { + var f []string + if ex.Summary.Value != "" { + f = append(f, ex.Summary.Value) + } + if ex.Description.Value != "" { + f = append(f, ex.Description.Value) + } + if ex.Value.Value != "" { + // this could be anything! + f = append(f, fmt.Sprintf("%x", sha256.Sum256([]byte(fmt.Sprint(ex.Value.Value))))) + } + if ex.ExternalValue.Value != "" { + f = append(f, ex.ExternalValue.Value) + } + keys := make([]string, len(ex.Extensions)) + z := 0 + for k := range ex.Extensions { + keys[z] = fmt.Sprintf("%s-%x", k.Value, sha256.Sum256([]byte(fmt.Sprint(ex.Extensions[k].Value)))) + z++ + } + sort.Strings(keys) + f = append(f, keys...) + return sha256.Sum256([]byte(strings.Join(f, "|"))) +} + +// Build extracts extensions and example value +func (ex *Example) Build(root *yaml.Node, idx *index.SpecIndex) error { + ex.Reference = new(low.Reference) + ex.Extensions = low.ExtractExtensions(root) + _, ln, vn := utils.FindKeyNodeFull(ValueLabel, root.Content) + + if vn != nil { + var n map[string]interface{} + err := vn.Decode(&n) + if err != nil { + // if not a map, then try an array + var k []interface{} + err = vn.Decode(&k) + if err != nil { + // lets just default to interface + var j interface{} + _ = vn.Decode(&j) + ex.Value = low.NodeReference[any]{ + Value: j, + KeyNode: ln, + ValueNode: vn, + } + return nil + } + ex.Value = low.NodeReference[any]{ + Value: k, + KeyNode: ln, + ValueNode: vn, + } + return nil + } + ex.Value = low.NodeReference[any]{ + Value: n, + KeyNode: ln, + ValueNode: vn, + } + return nil + } + return nil +} + +// GetExtensions will return Example extensions to satisfy the HasExtensions interface. +func (ex *Example) GetExtensions() map[low.KeyReference[string]]low.ValueReference[any] { + return ex.Extensions +} + +// ExtractExampleValue will extract a primitive example value (if possible), or just the raw Value property if not. +func ExtractExampleValue(exp *yaml.Node) any { + if utils.IsNodeBoolValue(exp) { + v, _ := strconv.ParseBool(exp.Value) + return v + } + if utils.IsNodeIntValue(exp) { + v, _ := strconv.ParseInt(exp.Value, 10, 64) + return v + } + if utils.IsNodeFloatValue(exp) { + v, _ := strconv.ParseFloat(exp.Value, 64) + return v + } + if utils.IsNodeMap(exp) { + var m map[string]interface{} + _ = exp.Decode(&m) + return m + } + if utils.IsNodeArray(exp) { + var m []interface{} + _ = exp.Decode(&m) + return m + } + return exp.Value +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/low/base/external_doc.go b/vendor/github.com/pb33f/libopenapi/datamodel/low/base/external_doc.go new file mode 100644 index 0000000000..1acfeebd96 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/low/base/external_doc.go @@ -0,0 +1,60 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package base + +import ( + "crypto/sha256" + "fmt" + "github.com/pb33f/libopenapi/datamodel/low" + "github.com/pb33f/libopenapi/index" + "gopkg.in/yaml.v3" + "sort" + "strings" +) + +// ExternalDoc represents a low-level External Documentation object as defined by OpenAPI 2 and 3 +// +// Allows referencing an external resource for extended documentation. +// v2 - https://swagger.io/specification/v2/#externalDocumentationObject +// v3 - https://spec.openapis.org/oas/v3.1.0#external-documentation-object +type ExternalDoc struct { + Description low.NodeReference[string] + URL low.NodeReference[string] + Extensions map[low.KeyReference[string]]low.ValueReference[any] + *low.Reference +} + +// FindExtension returns a ValueReference containing the extension value, if found. +func (ex *ExternalDoc) FindExtension(ext string) *low.ValueReference[any] { + return low.FindItemInMap[any](ext, ex.Extensions) +} + +// Build will extract extensions from the ExternalDoc instance. +func (ex *ExternalDoc) Build(root *yaml.Node, idx *index.SpecIndex) error { + ex.Reference = new(low.Reference) + ex.Extensions = low.ExtractExtensions(root) + return nil +} + +// GetExtensions returns all ExternalDoc extensions and satisfies the low.HasExtensions interface. +func (ex *ExternalDoc) GetExtensions() map[low.KeyReference[string]]low.ValueReference[any] { + return ex.Extensions +} + +func (ex *ExternalDoc) Hash() [32]byte { + // calculate a hash from every property. + f := []string{ + ex.Description.Value, + ex.URL.Value, + } + keys := make([]string, len(ex.Extensions)) + z := 0 + for k := range ex.Extensions { + keys[z] = fmt.Sprintf("%s-%x", k.Value, sha256.Sum256([]byte(fmt.Sprint(ex.Extensions[k].Value)))) + z++ + } + sort.Strings(keys) + f = append(f, keys...) + return sha256.Sum256([]byte(strings.Join(f, "|"))) +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/low/base/info.go b/vendor/github.com/pb33f/libopenapi/datamodel/low/base/info.go new file mode 100644 index 0000000000..e7c126e998 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/low/base/info.go @@ -0,0 +1,95 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package base + +import ( + "crypto/sha256" + "fmt" + "sort" + "strings" + + "github.com/pb33f/libopenapi/datamodel/low" + "github.com/pb33f/libopenapi/index" + "gopkg.in/yaml.v3" +) + +// Info represents a low-level Info object as defined by both OpenAPI 2 and OpenAPI 3. +// +// The object provides metadata about the API. The metadata MAY be used by the clients if needed, and MAY be presented +// in editing or documentation generation tools for convenience. +// +// v2 - https://swagger.io/specification/v2/#infoObject +// v3 - https://spec.openapis.org/oas/v3.1.0#info-object +type Info struct { + Title low.NodeReference[string] + Summary low.NodeReference[string] + Description low.NodeReference[string] + TermsOfService low.NodeReference[string] + Contact low.NodeReference[*Contact] + License low.NodeReference[*License] + Version low.NodeReference[string] + Extensions map[low.KeyReference[string]]low.ValueReference[any] + *low.Reference +} + +// FindExtension attempts to locate an extension with the supplied key +func (i *Info) FindExtension(ext string) *low.ValueReference[any] { + return low.FindItemInMap(ext, i.Extensions) +} + +// GetExtensions returns all extensions for Info +func (i *Info) GetExtensions() map[low.KeyReference[string]]low.ValueReference[any] { + return i.Extensions +} + +// Build will extract out the Contact and Info objects from the supplied root node. +func (i *Info) Build(root *yaml.Node, idx *index.SpecIndex) error { + i.Reference = new(low.Reference) + i.Extensions = low.ExtractExtensions(root) + + // extract contact + contact, _ := low.ExtractObject[*Contact](ContactLabel, root, idx) + i.Contact = contact + + // extract license + lic, _ := low.ExtractObject[*License](LicenseLabel, root, idx) + i.License = lic + return nil +} + +// Hash will return a consistent SHA256 Hash of the Info object +func (i *Info) Hash() [32]byte { + var f []string + + if !i.Title.IsEmpty() { + f = append(f, i.Title.Value) + } + if !i.Summary.IsEmpty() { + f = append(f, i.Summary.Value) + } + if !i.Description.IsEmpty() { + f = append(f, i.Description.Value) + } + if !i.TermsOfService.IsEmpty() { + f = append(f, i.TermsOfService.Value) + } + if !i.Contact.IsEmpty() { + f = append(f, low.GenerateHashString(i.Contact.Value)) + } + if !i.License.IsEmpty() { + f = append(f, low.GenerateHashString(i.License.Value)) + } + if !i.Version.IsEmpty() { + f = append(f, i.Version.Value) + } + keys := make([]string, len(i.Extensions)) + z := 0 + for k := range i.Extensions { + keys[z] = fmt.Sprintf("%s-%x", k.Value, sha256.Sum256([]byte(fmt.Sprint(i.Extensions[k].Value)))) + z++ + } + sort.Strings(keys) + f = append(f, keys...) + return sha256.Sum256([]byte(strings.Join(f, "|"))) +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/low/base/license.go b/vendor/github.com/pb33f/libopenapi/datamodel/low/base/license.go new file mode 100644 index 0000000000..96b54c8b82 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/low/base/license.go @@ -0,0 +1,39 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package base + +import ( + "crypto/sha256" + "github.com/pb33f/libopenapi/datamodel/low" + "github.com/pb33f/libopenapi/index" + "gopkg.in/yaml.v3" + "strings" +) + +// License is a low-level representation of a License object as defined by OpenAPI 2 and OpenAPI 3 +// v2 - https://swagger.io/specification/v2/#licenseObject +// v3 - https://spec.openapis.org/oas/v3.1.0#license-object +type License struct { + Name low.NodeReference[string] + URL low.NodeReference[string] + *low.Reference +} + +// Build is not implemented for License (there is nothing to build) +func (l *License) Build(root *yaml.Node, idx *index.SpecIndex) error { + l.Reference = new(low.Reference) + return nil +} + +// Hash will return a consistent SHA256 Hash of the License object +func (l *License) Hash() [32]byte { + var f []string + if !l.Name.IsEmpty() { + f = append(f, l.Name.Value) + } + if !l.URL.IsEmpty() { + f = append(f, l.URL.Value) + } + return sha256.Sum256([]byte(strings.Join(f, "|"))) +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/low/base/schema.go b/vendor/github.com/pb33f/libopenapi/datamodel/low/base/schema.go new file mode 100644 index 0000000000..4d78033f4d --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/low/base/schema.go @@ -0,0 +1,1275 @@ +package base + +import ( + "crypto/sha256" + "fmt" + "reflect" + "sort" + "strconv" + "strings" + + "github.com/pb33f/libopenapi/datamodel/low" + "github.com/pb33f/libopenapi/index" + "github.com/pb33f/libopenapi/utils" + "gopkg.in/yaml.v3" +) + +// SchemaDynamicValue is used to hold multiple possible values for a schema property. There are two values, a left +// value (A) and a right value (B). The left value (A) is a 3.0 schema property value, the right value (B) is a 3.1 +// schema value. +// +// OpenAPI 3.1 treats a Schema as a real JSON schema, which means some properties become incompatible, or others +// now support more than one primitive type or structure. +// The N value is a bit to make it each to know which value (A or B) is used, this prevents having to +// if/else on the value to determine which one is set. +type SchemaDynamicValue[A any, B any] struct { + N int // 0 == A, 1 == B + A A + B B +} + +// IsA will return true if the 'A' or left value is set. (OpenAPI 3) +func (s SchemaDynamicValue[A, B]) IsA() bool { + return s.N == 0 +} + +// IsB will return true if the 'B' or right value is set (OpenAPI 3.1) +func (s SchemaDynamicValue[A, B]) IsB() bool { + return s.N == 1 +} + +// Schema represents a JSON Schema that support Swagger, OpenAPI 3 and OpenAPI 3.1 +// +// Until 3.1 OpenAPI had a strange relationship with JSON Schema. It's been a super-set/sub-set +// mix, which has been confusing. So, instead of building a bunch of different models, we have compressed +// all variations into a single model that makes it easy to support multiple spec types. +// +// - v2 schema: https://swagger.io/specification/v2/#schemaObject +// - v3 schema: https://swagger.io/specification/#schema-object +// - v3.1 schema: https://spec.openapis.org/oas/v3.1.0#schema-object +type Schema struct { + // Reference to the '$schema' dialect setting (3.1 only) + SchemaTypeRef low.NodeReference[string] + + // In versions 2 and 3.0, this ExclusiveMaximum can only be a boolean. + ExclusiveMaximum low.NodeReference[*SchemaDynamicValue[bool, int64]] + + // In versions 2 and 3.0, this ExclusiveMinimum can only be a boolean. + ExclusiveMinimum low.NodeReference[*SchemaDynamicValue[bool, int64]] + + // In versions 2 and 3.0, this Type is a single value, so array will only ever have one value + // in version 3.1, Type can be multiple values + Type low.NodeReference[SchemaDynamicValue[string, []low.ValueReference[string]]] + + // Schemas are resolved on demand using a SchemaProxy + AllOf low.NodeReference[[]low.ValueReference[*SchemaProxy]] + + // Polymorphic Schemas are only available in version 3+ + OneOf low.NodeReference[[]low.ValueReference[*SchemaProxy]] + AnyOf low.NodeReference[[]low.ValueReference[*SchemaProxy]] + Discriminator low.NodeReference[*Discriminator] + + // in 3.1 examples can be an array (which is recommended) + Examples low.NodeReference[[]low.ValueReference[any]] + // in 3.1 PrefixItems provides tuple validation using prefixItems. + PrefixItems low.NodeReference[[]low.ValueReference[*SchemaProxy]] + // in 3.1 Contains is used by arrays and points to a Schema. + Contains low.NodeReference[*SchemaProxy] + MinContains low.NodeReference[int64] + MaxContains low.NodeReference[int64] + + // items can be a schema in 2.0, 3.0 and 3.1 or a bool in 3.1 + Items low.NodeReference[*SchemaDynamicValue[*SchemaProxy, bool]] + + // 3.1 only + If low.NodeReference[*SchemaProxy] + Else low.NodeReference[*SchemaProxy] + Then low.NodeReference[*SchemaProxy] + DependentSchemas low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*SchemaProxy]] + PatternProperties low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*SchemaProxy]] + PropertyNames low.NodeReference[*SchemaProxy] + UnevaluatedItems low.NodeReference[*SchemaProxy] + UnevaluatedProperties low.NodeReference[*SchemaProxy] + Anchor low.NodeReference[string] + + // Compatible with all versions + Title low.NodeReference[string] + MultipleOf low.NodeReference[int64] + Maximum low.NodeReference[int64] + Minimum low.NodeReference[int64] + MaxLength low.NodeReference[int64] + MinLength low.NodeReference[int64] + Pattern low.NodeReference[string] + Format low.NodeReference[string] + MaxItems low.NodeReference[int64] + MinItems low.NodeReference[int64] + UniqueItems low.NodeReference[bool] + MaxProperties low.NodeReference[int64] + MinProperties low.NodeReference[int64] + Required low.NodeReference[[]low.ValueReference[string]] + Enum low.NodeReference[[]low.ValueReference[any]] + Not low.NodeReference[*SchemaProxy] + Properties low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*SchemaProxy]] + AdditionalProperties low.NodeReference[any] + Description low.NodeReference[string] + ContentEncoding low.NodeReference[string] + ContentMediaType low.NodeReference[string] + Default low.NodeReference[any] + Nullable low.NodeReference[bool] + ReadOnly low.NodeReference[bool] + WriteOnly low.NodeReference[bool] + XML low.NodeReference[*XML] + ExternalDocs low.NodeReference[*ExternalDoc] + Example low.NodeReference[any] + Deprecated low.NodeReference[bool] + Extensions map[low.KeyReference[string]]low.ValueReference[any] + + // Parent Proxy refers back to the low level SchemaProxy that is proxying this schema. + ParentProxy *SchemaProxy + *low.Reference +} + +// Hash will calculate a SHA256 hash from the values of the schema, This allows equality checking against +// Schemas defined inside an OpenAPI document. The only way to know if a schema has changed, is to hash it. +func (s *Schema) Hash() [32]byte { + // calculate a hash from every property in the schema. + var d []string + if !s.SchemaTypeRef.IsEmpty() { + d = append(d, fmt.Sprint(s.SchemaTypeRef.Value)) + } + if !s.Title.IsEmpty() { + d = append(d, fmt.Sprint(s.Title.Value)) + } + if !s.MultipleOf.IsEmpty() { + d = append(d, fmt.Sprint(s.MultipleOf.Value)) + } + if !s.Maximum.IsEmpty() { + d = append(d, fmt.Sprint(s.Maximum.Value)) + } + if !s.Minimum.IsEmpty() { + d = append(d, fmt.Sprint(s.Minimum.Value)) + } + if !s.MaxLength.IsEmpty() { + d = append(d, fmt.Sprint(s.MaxLength.Value)) + } + if !s.MinLength.IsEmpty() { + d = append(d, fmt.Sprint(s.MinLength.Value)) + } + if !s.Pattern.IsEmpty() { + d = append(d, fmt.Sprint(s.Pattern.Value)) + } + if !s.Format.IsEmpty() { + d = append(d, fmt.Sprint(s.Format.Value)) + } + if !s.MaxItems.IsEmpty() { + d = append(d, fmt.Sprint(s.MaxItems.Value)) + } + if !s.MinItems.IsEmpty() { + d = append(d, fmt.Sprint(s.MinItems.Value)) + } + if !s.UniqueItems.IsEmpty() { + d = append(d, fmt.Sprint(s.UniqueItems.Value)) + } + if !s.MaxProperties.IsEmpty() { + d = append(d, fmt.Sprint(s.MaxProperties.Value)) + } + if !s.MinProperties.IsEmpty() { + d = append(d, fmt.Sprint(s.MinProperties.Value)) + } + if !s.AdditionalProperties.IsEmpty() { + + // check type of properties, if we have a low level map, we need to hash the values in a repeatable + // order. + to := reflect.TypeOf(s.AdditionalProperties.Value) + vo := reflect.ValueOf(s.AdditionalProperties.Value) + var values []string + switch to.Kind() { + case reflect.Slice: + for i := 0; i < vo.Len(); i++ { + vn := vo.Index(i).Interface() + + if jh, ok := vn.(low.HasValueUnTyped); ok { + vn = jh.GetValueUntyped() + fg := reflect.TypeOf(vn) + gf := reflect.ValueOf(vn) + + if fg.Kind() == reflect.Map { + for _, ky := range gf.MapKeys() { + hu := ky.Interface() + values = append(values, fmt.Sprintf("%s:%s", hu, low.GenerateHashString(gf.MapIndex(ky).Interface()))) + } + continue + } + values = append(values, fmt.Sprintf("%d:%s", i, low.GenerateHashString(vn))) + } + } + sort.Strings(values) + d = append(d, strings.Join(values, "||")) + + case reflect.Map: + for _, k := range vo.MapKeys() { + var x string + var l int + var v any + // extract key + if o, ok := k.Interface().(low.HasKeyNode); ok { + x = o.GetKeyNode().Value + l = o.GetKeyNode().Line + v = vo.MapIndex(k).Interface().(low.HasValueNodeUntyped).GetValueNode().Value + } + values = append(values, fmt.Sprintf("%d:%s:%s", l, x, low.GenerateHashString(v))) + } + sort.Strings(values) + d = append(d, strings.Join(values, "||")) + default: + d = append(d, low.GenerateHashString(s.AdditionalProperties.Value)) + } + } + if !s.Description.IsEmpty() { + d = append(d, fmt.Sprint(s.Description.Value)) + } + if !s.ContentEncoding.IsEmpty() { + d = append(d, fmt.Sprint(s.ContentEncoding.Value)) + } + if !s.ContentMediaType.IsEmpty() { + d = append(d, fmt.Sprint(s.ContentMediaType.Value)) + } + if !s.Default.IsEmpty() { + d = append(d, low.GenerateHashString(s.Default.Value)) + } + if !s.Nullable.IsEmpty() { + d = append(d, fmt.Sprint(s.Nullable.Value)) + } + if !s.ReadOnly.IsEmpty() { + d = append(d, fmt.Sprint(s.ReadOnly.Value)) + } + if !s.WriteOnly.IsEmpty() { + d = append(d, fmt.Sprint(s.WriteOnly.Value)) + } + if !s.Deprecated.IsEmpty() { + d = append(d, fmt.Sprint(s.Deprecated.Value)) + } + if !s.ExclusiveMaximum.IsEmpty() && s.ExclusiveMaximum.Value.IsA() { + d = append(d, fmt.Sprint(s.ExclusiveMaximum.Value.A)) + } + if !s.ExclusiveMaximum.IsEmpty() && s.ExclusiveMaximum.Value.IsB() { + d = append(d, fmt.Sprint(s.ExclusiveMaximum.Value.B)) + } + if !s.ExclusiveMinimum.IsEmpty() && s.ExclusiveMinimum.Value.IsA() { + d = append(d, fmt.Sprint(s.ExclusiveMinimum.Value.A)) + } + if !s.ExclusiveMinimum.IsEmpty() && s.ExclusiveMinimum.Value.IsB() { + d = append(d, fmt.Sprint(s.ExclusiveMinimum.Value.B)) + } + if !s.Type.IsEmpty() && s.Type.Value.IsA() { + d = append(d, fmt.Sprint(s.Type.Value.A)) + } + if !s.Type.IsEmpty() && s.Type.Value.IsB() { + j := make([]string, len(s.Type.Value.B)) + for h := range s.Type.Value.B { + j[h] = s.Type.Value.B[h].Value + } + sort.Strings(j) + d = append(d, strings.Join(j, "|")) + } + + keys := make([]string, len(s.Required.Value)) + for i := range s.Required.Value { + keys[i] = s.Required.Value[i].Value + } + sort.Strings(keys) + d = append(d, keys...) + + keys = make([]string, len(s.Enum.Value)) + for i := range s.Enum.Value { + keys[i] = fmt.Sprint(s.Enum.Value[i].Value) + } + sort.Strings(keys) + d = append(d, keys...) + + for i := range s.Enum.Value { + d = append(d, fmt.Sprint(s.Enum.Value[i].Value)) + } + propKeys := make([]string, len(s.Properties.Value)) + z := 0 + for i := range s.Properties.Value { + propKeys[z] = i.Value + z++ + } + sort.Strings(propKeys) + for k := range propKeys { + d = append(d, low.GenerateHashString(s.FindProperty(propKeys[k]).Value)) + } + if s.XML.Value != nil { + d = append(d, low.GenerateHashString(s.XML.Value)) + } + if s.ExternalDocs.Value != nil { + d = append(d, low.GenerateHashString(s.ExternalDocs.Value)) + } + if s.Discriminator.Value != nil { + d = append(d, low.GenerateHashString(s.Discriminator.Value)) + } + + // hash polymorphic data + if len(s.OneOf.Value) > 0 { + oneOfKeys := make([]string, len(s.OneOf.Value)) + oneOfEntities := make(map[string]*SchemaProxy) + z = 0 + for i := range s.OneOf.Value { + g := s.OneOf.Value[i].Value + r := low.GenerateHashString(g) + oneOfEntities[r] = g + oneOfKeys[z] = r + z++ + + } + sort.Strings(oneOfKeys) + for k := range oneOfKeys { + d = append(d, low.GenerateHashString(oneOfEntities[oneOfKeys[k]])) + } + } + + if len(s.AllOf.Value) > 0 { + allOfKeys := make([]string, len(s.AllOf.Value)) + allOfEntities := make(map[string]*SchemaProxy) + z = 0 + for i := range s.AllOf.Value { + g := s.AllOf.Value[i].Value + r := low.GenerateHashString(g) + allOfEntities[r] = g + allOfKeys[z] = r + z++ + + } + sort.Strings(allOfKeys) + for k := range allOfKeys { + d = append(d, low.GenerateHashString(allOfEntities[allOfKeys[k]])) + } + } + + if len(s.AnyOf.Value) > 0 { + anyOfKeys := make([]string, len(s.AnyOf.Value)) + anyOfEntities := make(map[string]*SchemaProxy) + z = 0 + for i := range s.AnyOf.Value { + g := s.AnyOf.Value[i].Value + r := low.GenerateHashString(g) + anyOfEntities[r] = g + anyOfKeys[z] = r + z++ + + } + sort.Strings(anyOfKeys) + for k := range anyOfKeys { + d = append(d, low.GenerateHashString(anyOfEntities[anyOfKeys[k]])) + } + } + + if !s.Not.IsEmpty() { + d = append(d, low.GenerateHashString(s.Not.Value)) + } + + // check if items is a schema or a bool. + if !s.Items.IsEmpty() && s.Items.Value.IsA() { + d = append(d, low.GenerateHashString(s.Items.Value.A)) + } + if !s.Items.IsEmpty() && s.Items.Value.IsB() { + d = append(d, fmt.Sprint(s.Items.Value.B)) + } + // 3.1 only props + if !s.If.IsEmpty() { + d = append(d, low.GenerateHashString(s.If.Value)) + } + if !s.Else.IsEmpty() { + d = append(d, low.GenerateHashString(s.Else.Value)) + } + if !s.Then.IsEmpty() { + d = append(d, low.GenerateHashString(s.Then.Value)) + } + if !s.PropertyNames.IsEmpty() { + d = append(d, low.GenerateHashString(s.PropertyNames.Value)) + } + if !s.UnevaluatedProperties.IsEmpty() { + d = append(d, low.GenerateHashString(s.UnevaluatedProperties.Value)) + } + if !s.UnevaluatedItems.IsEmpty() { + d = append(d, low.GenerateHashString(s.UnevaluatedItems.Value)) + } + if !s.Anchor.IsEmpty() { + d = append(d, fmt.Sprint(s.Anchor.Value)) + } + + depSchemasKeys := make([]string, len(s.DependentSchemas.Value)) + z = 0 + for i := range s.DependentSchemas.Value { + depSchemasKeys[z] = i.Value + z++ + } + sort.Strings(depSchemasKeys) + for k := range depSchemasKeys { + d = append(d, low.GenerateHashString(s.FindDependentSchema(depSchemasKeys[k]).Value)) + } + + patternPropsKeys := make([]string, len(s.PatternProperties.Value)) + z = 0 + for i := range s.PatternProperties.Value { + patternPropsKeys[z] = i.Value + z++ + } + sort.Strings(patternPropsKeys) + for k := range patternPropsKeys { + d = append(d, low.GenerateHashString(s.FindPatternProperty(patternPropsKeys[k]).Value)) + } + + if len(s.PrefixItems.Value) > 0 { + itemsKeys := make([]string, len(s.PrefixItems.Value)) + itemsEntities := make(map[string]*SchemaProxy) + z = 0 + for i := range s.PrefixItems.Value { + g := s.PrefixItems.Value[i].Value + r := low.GenerateHashString(g) + itemsEntities[r] = g + itemsKeys[z] = r + z++ + } + sort.Strings(itemsKeys) + for k := range itemsKeys { + d = append(d, low.GenerateHashString(itemsEntities[itemsKeys[k]])) + } + } + + // add extensions to hash + keys = make([]string, len(s.Extensions)) + z = 0 + for k := range s.Extensions { + keys[z] = fmt.Sprintf("%s-%x", k.Value, sha256.Sum256([]byte(fmt.Sprint(s.Extensions[k].Value)))) + z++ + } + sort.Strings(keys) + d = append(d, keys...) + if s.Example.Value != nil { + d = append(d, low.GenerateHashString(s.Example.Value)) + } + + // contains + if !s.Contains.IsEmpty() { + d = append(d, low.GenerateHashString(s.Contains.Value)) + } + if !s.MinContains.IsEmpty() { + d = append(d, fmt.Sprint(s.MinContains.Value)) + } + if !s.MaxContains.IsEmpty() { + d = append(d, fmt.Sprint(s.MaxContains.Value)) + } + if !s.Examples.IsEmpty() { + var xph []string + for w := range s.Examples.Value { + xph = append(xph, low.GenerateHashString(s.Examples.Value[w].Value)) + } + sort.Strings(xph) + d = append(d, strings.Join(xph, "|")) + } + return sha256.Sum256([]byte(strings.Join(d, "|"))) +} + +// FindProperty will return a ValueReference pointer containing a SchemaProxy pointer +// from a property key name. if found +func (s *Schema) FindProperty(name string) *low.ValueReference[*SchemaProxy] { + return low.FindItemInMap[*SchemaProxy](name, s.Properties.Value) +} + +// FindDependentSchema will return a ValueReference pointer containing a SchemaProxy pointer +// from a dependent schema key name. if found (3.1+ only) +func (s *Schema) FindDependentSchema(name string) *low.ValueReference[*SchemaProxy] { + return low.FindItemInMap[*SchemaProxy](name, s.DependentSchemas.Value) +} + +// FindPatternProperty will return a ValueReference pointer containing a SchemaProxy pointer +// from a pattern property key name. if found (3.1+ only) +func (s *Schema) FindPatternProperty(name string) *low.ValueReference[*SchemaProxy] { + return low.FindItemInMap[*SchemaProxy](name, s.PatternProperties.Value) +} + +// GetExtensions returns all extensions for Schema +func (s *Schema) GetExtensions() map[low.KeyReference[string]]low.ValueReference[any] { + return s.Extensions +} + +// Build will perform a number of operations. +// Extraction of the following happens in this method: +// - Extensions +// - Type +// - ExclusiveMinimum and ExclusiveMaximum +// - Examples +// - AdditionalProperties +// - Discriminator +// - ExternalDocs +// - XML +// - Properties +// - AllOf, OneOf, AnyOf +// - Not +// - Items +// - PrefixItems +// - If +// - Else +// - Then +// - DependentSchemas +// - PatternProperties +// - PropertyNames +// - UnevaluatedItems +// - UnevaluatedProperties +// - Anchor +func (s *Schema) Build(root *yaml.Node, idx *index.SpecIndex) error { + s.Reference = new(low.Reference) + if h, _, _ := utils.IsNodeRefValue(root); h { + ref, err := low.LocateRefNode(root, idx) + if ref != nil { + root = ref + if err != nil { + if !idx.AllowCircularReferenceResolving() { + return fmt.Errorf("build schema failed: %s", err.Error()) + } + } + } else { + return fmt.Errorf("build schema failed: reference cannot be found: '%s', line %d, col %d", + root.Content[1].Value, root.Content[1].Line, root.Content[1].Column) + } + } + + // Build model using possibly dereferenced root + if err := low.BuildModel(root, s); err != nil { + return err + } + + s.extractExtensions(root) + + // determine schema type, singular (3.0) or multiple (3.1), use a variable value + _, typeLabel, typeValue := utils.FindKeyNodeFullTop(TypeLabel, root.Content) + if typeValue != nil { + if utils.IsNodeStringValue(typeValue) { + s.Type = low.NodeReference[SchemaDynamicValue[string, []low.ValueReference[string]]]{ + KeyNode: typeLabel, + ValueNode: typeValue, + Value: SchemaDynamicValue[string, []low.ValueReference[string]]{N: 0, A: typeValue.Value}, + } + } + if utils.IsNodeArray(typeValue) { + + var refs []low.ValueReference[string] + for r := range typeValue.Content { + refs = append(refs, low.ValueReference[string]{ + Value: typeValue.Content[r].Value, + ValueNode: typeValue.Content[r], + }) + } + s.Type = low.NodeReference[SchemaDynamicValue[string, []low.ValueReference[string]]]{ + KeyNode: typeLabel, + ValueNode: typeValue, + Value: SchemaDynamicValue[string, []low.ValueReference[string]]{N: 1, B: refs}, + } + } + } + + // determine exclusive minimum type, bool (3.0) or int (3.1) + _, exMinLabel, exMinValue := utils.FindKeyNodeFullTop(ExclusiveMinimumLabel, root.Content) + if exMinValue != nil { + if utils.IsNodeBoolValue(exMinValue) { + val, _ := strconv.ParseBool(exMinValue.Value) + s.ExclusiveMinimum = low.NodeReference[*SchemaDynamicValue[bool, int64]]{ + KeyNode: exMinLabel, + ValueNode: exMinValue, + Value: &SchemaDynamicValue[bool, int64]{N: 0, A: val}, + } + } + if utils.IsNodeIntValue(exMinValue) { + val, _ := strconv.ParseInt(exMinValue.Value, 10, 64) + s.ExclusiveMinimum = low.NodeReference[*SchemaDynamicValue[bool, int64]]{ + KeyNode: exMinLabel, + ValueNode: exMinValue, + Value: &SchemaDynamicValue[bool, int64]{N: 1, B: val}, + } + } + } + + // determine exclusive maximum type, bool (3.0) or int (3.1) + _, exMaxLabel, exMaxValue := utils.FindKeyNodeFullTop(ExclusiveMaximumLabel, root.Content) + if exMaxValue != nil { + if utils.IsNodeBoolValue(exMaxValue) { + val, _ := strconv.ParseBool(exMaxValue.Value) + s.ExclusiveMaximum = low.NodeReference[*SchemaDynamicValue[bool, int64]]{ + KeyNode: exMaxLabel, + ValueNode: exMaxValue, + Value: &SchemaDynamicValue[bool, int64]{N: 0, A: val}, + } + } + if utils.IsNodeIntValue(exMaxValue) { + val, _ := strconv.ParseInt(exMaxValue.Value, 10, 64) + s.ExclusiveMaximum = low.NodeReference[*SchemaDynamicValue[bool, int64]]{ + KeyNode: exMaxLabel, + ValueNode: exMaxValue, + Value: &SchemaDynamicValue[bool, int64]{N: 1, B: val}, + } + } + } + + // handle schema reference type if set. (3.1) + _, schemaRefLabel, schemaRefNode := utils.FindKeyNodeFullTop(SchemaTypeLabel, root.Content) + if schemaRefNode != nil { + s.SchemaTypeRef = low.NodeReference[string]{ + Value: schemaRefNode.Value, KeyNode: schemaRefLabel, ValueNode: schemaRefLabel, + } + } + + // handle anchor if set. (3.1) + _, anchorLabel, anchorNode := utils.FindKeyNodeFullTop(AnchorLabel, root.Content) + if anchorNode != nil { + s.Anchor = low.NodeReference[string]{ + Value: anchorNode.Value, KeyNode: anchorLabel, ValueNode: anchorLabel, + } + } + + // handle example if set. (3.0) + _, expLabel, expNode := utils.FindKeyNodeFull(ExampleLabel, root.Content) + if expNode != nil { + s.Example = low.NodeReference[any]{Value: ExtractExampleValue(expNode), KeyNode: expLabel, ValueNode: expNode} + } + + // handle examples if set.(3.1) + _, expArrLabel, expArrNode := utils.FindKeyNodeFullTop(ExamplesLabel, root.Content) + if expArrNode != nil { + if utils.IsNodeArray(expArrNode) { + var examples []low.ValueReference[any] + for i := range expArrNode.Content { + examples = append(examples, low.ValueReference[any]{Value: ExtractExampleValue(expArrNode.Content[i]), ValueNode: expArrNode.Content[i]}) + } + s.Examples = low.NodeReference[[]low.ValueReference[any]]{ + Value: examples, + ValueNode: expArrNode, + KeyNode: expArrLabel, + } + } + } + + _, addPLabel, addPNode := utils.FindKeyNodeFullTop(AdditionalPropertiesLabel, root.Content) + if addPNode != nil { + if utils.IsNodeMap(addPNode) || utils.IsNodeArray(addPNode) { + // check if this is a reference, or an inline schema. + isRef, _, _ := utils.IsNodeRefValue(addPNode) + var sp *SchemaProxy + // now check if this object has a 'type' if so, it's a schema, if not... it's a random + // object, and we should treat it as a raw map. + if _, v := utils.FindKeyNodeTop(TypeLabel, addPNode.Content); v != nil { + sp = &SchemaProxy{ + kn: addPLabel, + vn: addPNode, + idx: idx, + } + } + if isRef { + _, vn := utils.FindKeyNodeTop("$ref", addPNode.Content) + sp = &SchemaProxy{ + kn: addPLabel, + vn: addPNode, + idx: idx, + isReference: true, + referenceLookup: vn.Value, + } + } + + // if this is a reference, or a schema, we're done. + if sp != nil { + s.AdditionalProperties = low.NodeReference[any]{Value: sp, KeyNode: addPLabel, ValueNode: addPNode} + } else { + + // if this is a map, collect all the keys and values. + if utils.IsNodeMap(addPNode) { + + addProps := make(map[low.KeyReference[string]]low.ValueReference[any]) + var label string + for g := range addPNode.Content { + if g%2 == 0 { + label = addPNode.Content[g].Value + continue + } else { + addProps[low.KeyReference[string]{Value: label, KeyNode: addPNode.Content[g-1]}] = + low.ValueReference[any]{Value: addPNode.Content[g].Value, ValueNode: addPNode.Content[g]} + } + } + s.AdditionalProperties = low.NodeReference[any]{Value: addProps, KeyNode: addPLabel, ValueNode: addPNode} + } + + // if the node is an array, extract everything into a trackable structure + if utils.IsNodeArray(addPNode) { + var addProps []low.ValueReference[any] + + // if this is an array or maps, encode the map items correctly. + for i := range addPNode.Content { + if utils.IsNodeMap(addPNode.Content[i]) { + var prop map[string]any + addPNode.Content[i].Decode(&prop) + addProps = append(addProps, + low.ValueReference[any]{Value: prop, ValueNode: addPNode.Content[i]}) + } else { + addProps = append(addProps, + low.ValueReference[any]{Value: addPNode.Content[i].Value, ValueNode: addPNode.Content[i]}) + } + } + + s.AdditionalProperties = + low.NodeReference[any]{Value: addProps, KeyNode: addPLabel, ValueNode: addPNode} + } + } + } + if utils.IsNodeBoolValue(addPNode) { + b, _ := strconv.ParseBool(addPNode.Value) + s.AdditionalProperties = low.NodeReference[any]{Value: b, KeyNode: addPLabel, ValueNode: addPNode} + } + } + + // handle discriminator if set. + _, discLabel, discNode := utils.FindKeyNodeFullTop(DiscriminatorLabel, root.Content) + if discNode != nil { + var discriminator Discriminator + _ = low.BuildModel(discNode, &discriminator) + s.Discriminator = low.NodeReference[*Discriminator]{Value: &discriminator, KeyNode: discLabel, ValueNode: discNode} + } + + // handle externalDocs if set. + _, extDocLabel, extDocNode := utils.FindKeyNodeFullTop(ExternalDocsLabel, root.Content) + if extDocNode != nil { + var exDoc ExternalDoc + _ = low.BuildModel(extDocNode, &exDoc) + _ = exDoc.Build(extDocNode, idx) // throws no errors, can't check for one. + s.ExternalDocs = low.NodeReference[*ExternalDoc]{Value: &exDoc, KeyNode: extDocLabel, ValueNode: extDocNode} + } + + // handle xml if set. + _, xmlLabel, xmlNode := utils.FindKeyNodeFullTop(XMLLabel, root.Content) + if xmlNode != nil { + var xml XML + _ = low.BuildModel(xmlNode, &xml) + // extract extensions if set. + _ = xml.Build(xmlNode, idx) // returns no errors, can't check for one. + s.XML = low.NodeReference[*XML]{Value: &xml, KeyNode: xmlLabel, ValueNode: xmlNode} + } + + // handle properties + props, err := buildPropertyMap(root, idx, PropertiesLabel) + if err != nil { + return err + } + if props != nil { + s.Properties = *props + } + + // handle dependent schemas + props, err = buildPropertyMap(root, idx, DependentSchemasLabel) + if err != nil { + return err + } + if props != nil { + s.DependentSchemas = *props + } + + // handle pattern properties + props, err = buildPropertyMap(root, idx, PatternPropertiesLabel) + if err != nil { + return err + } + if props != nil { + s.PatternProperties = *props + } + + // check items type for schema or bool (3.1 only) + itemsIsBool := false + itemsBoolValue := false + _, itemsLabel, itemsValue := utils.FindKeyNodeFullTop(ItemsLabel, root.Content) + if itemsValue != nil { + if utils.IsNodeBoolValue(itemsValue) { + itemsIsBool = true + itemsBoolValue, _ = strconv.ParseBool(itemsValue.Value) + } + } + if itemsIsBool { + s.Items = low.NodeReference[*SchemaDynamicValue[*SchemaProxy, bool]]{ + Value: &SchemaDynamicValue[*SchemaProxy, bool]{ + B: itemsBoolValue, + N: 1, + }, + KeyNode: itemsLabel, + ValueNode: itemsValue, + } + } + + var allOf, anyOf, oneOf, prefixItems []low.ValueReference[*SchemaProxy] + var items, not, contains, sif, selse, sthen, propertyNames, unevalItems, unevalProperties low.ValueReference[*SchemaProxy] + + _, allOfLabel, allOfValue := utils.FindKeyNodeFullTop(AllOfLabel, root.Content) + _, anyOfLabel, anyOfValue := utils.FindKeyNodeFullTop(AnyOfLabel, root.Content) + _, oneOfLabel, oneOfValue := utils.FindKeyNodeFullTop(OneOfLabel, root.Content) + _, notLabel, notValue := utils.FindKeyNodeFullTop(NotLabel, root.Content) + _, prefixItemsLabel, prefixItemsValue := utils.FindKeyNodeFullTop(PrefixItemsLabel, root.Content) + _, containsLabel, containsValue := utils.FindKeyNodeFullTop(ContainsLabel, root.Content) + _, sifLabel, sifValue := utils.FindKeyNodeFullTop(IfLabel, root.Content) + _, selseLabel, selseValue := utils.FindKeyNodeFullTop(ElseLabel, root.Content) + _, sthenLabel, sthenValue := utils.FindKeyNodeFullTop(ThenLabel, root.Content) + _, propNamesLabel, propNamesValue := utils.FindKeyNodeFullTop(PropertyNamesLabel, root.Content) + + _, unevalItemsLabel, unevalItemsValue := utils.FindKeyNodeFullTop(UnevaluatedItemsLabel, root.Content) + _, unevalPropsLabel, unevalPropsValue := utils.FindKeyNodeFullTop(UnevaluatedPropertiesLabel, root.Content) + + errorChan := make(chan error) + allOfChan := make(chan schemaProxyBuildResult) + anyOfChan := make(chan schemaProxyBuildResult) + oneOfChan := make(chan schemaProxyBuildResult) + itemsChan := make(chan schemaProxyBuildResult) + prefixItemsChan := make(chan schemaProxyBuildResult) + notChan := make(chan schemaProxyBuildResult) + containsChan := make(chan schemaProxyBuildResult) + ifChan := make(chan schemaProxyBuildResult) + elseChan := make(chan schemaProxyBuildResult) + thenChan := make(chan schemaProxyBuildResult) + propNamesChan := make(chan schemaProxyBuildResult) + unevalItemsChan := make(chan schemaProxyBuildResult) + unevalPropsChan := make(chan schemaProxyBuildResult) + + totalBuilds := countSubSchemaItems(allOfValue) + + countSubSchemaItems(anyOfValue) + + countSubSchemaItems(oneOfValue) + + countSubSchemaItems(prefixItemsValue) + + if allOfValue != nil { + go buildSchema(allOfChan, allOfLabel, allOfValue, errorChan, idx) + } + if anyOfValue != nil { + go buildSchema(anyOfChan, anyOfLabel, anyOfValue, errorChan, idx) + } + if oneOfValue != nil { + go buildSchema(oneOfChan, oneOfLabel, oneOfValue, errorChan, idx) + } + if prefixItemsValue != nil { + go buildSchema(prefixItemsChan, prefixItemsLabel, prefixItemsValue, errorChan, idx) + } + if notValue != nil { + totalBuilds++ + go buildSchema(notChan, notLabel, notValue, errorChan, idx) + } + if containsValue != nil { + totalBuilds++ + go buildSchema(containsChan, containsLabel, containsValue, errorChan, idx) + } + if !itemsIsBool && itemsValue != nil { + totalBuilds++ + go buildSchema(itemsChan, itemsLabel, itemsValue, errorChan, idx) + } + if sifValue != nil { + totalBuilds++ + go buildSchema(ifChan, sifLabel, sifValue, errorChan, idx) + } + if selseValue != nil { + totalBuilds++ + go buildSchema(elseChan, selseLabel, selseValue, errorChan, idx) + } + if sthenValue != nil { + totalBuilds++ + go buildSchema(thenChan, sthenLabel, sthenValue, errorChan, idx) + } + if propNamesValue != nil { + totalBuilds++ + go buildSchema(propNamesChan, propNamesLabel, propNamesValue, errorChan, idx) + } + if unevalItemsValue != nil { + totalBuilds++ + go buildSchema(unevalItemsChan, unevalItemsLabel, unevalItemsValue, errorChan, idx) + } + if unevalPropsValue != nil { + totalBuilds++ + go buildSchema(unevalPropsChan, unevalPropsLabel, unevalPropsValue, errorChan, idx) + } + + completeCount := 0 + for completeCount < totalBuilds { + select { + case e := <-errorChan: + return e + case r := <-allOfChan: + completeCount++ + allOf = append(allOf, r.v) + case r := <-anyOfChan: + completeCount++ + anyOf = append(anyOf, r.v) + case r := <-oneOfChan: + completeCount++ + oneOf = append(oneOf, r.v) + case r := <-itemsChan: + completeCount++ + items = r.v + case r := <-prefixItemsChan: + completeCount++ + prefixItems = append(prefixItems, r.v) + case r := <-notChan: + completeCount++ + not = r.v + case r := <-containsChan: + completeCount++ + contains = r.v + case r := <-ifChan: + completeCount++ + sif = r.v + case r := <-elseChan: + completeCount++ + selse = r.v + case r := <-thenChan: + completeCount++ + sthen = r.v + case r := <-propNamesChan: + completeCount++ + propertyNames = r.v + case r := <-unevalItemsChan: + completeCount++ + unevalItems = r.v + case r := <-unevalPropsChan: + completeCount++ + unevalProperties = r.v + } + } + + if len(anyOf) > 0 { + s.AnyOf = low.NodeReference[[]low.ValueReference[*SchemaProxy]]{ + Value: anyOf, + KeyNode: anyOfLabel, + ValueNode: anyOfValue, + } + } + if len(oneOf) > 0 { + s.OneOf = low.NodeReference[[]low.ValueReference[*SchemaProxy]]{ + Value: oneOf, + KeyNode: oneOfLabel, + ValueNode: oneOfValue, + } + } + if len(allOf) > 0 { + s.AllOf = low.NodeReference[[]low.ValueReference[*SchemaProxy]]{ + Value: allOf, + KeyNode: allOfLabel, + ValueNode: allOfValue, + } + } + if !not.IsEmpty() { + s.Not = low.NodeReference[*SchemaProxy]{ + Value: not.Value, + KeyNode: notLabel, + ValueNode: notValue, + } + } + if !itemsIsBool && !items.IsEmpty() { + s.Items = low.NodeReference[*SchemaDynamicValue[*SchemaProxy, bool]]{ + Value: &SchemaDynamicValue[*SchemaProxy, bool]{ + A: items.Value, + }, + KeyNode: itemsLabel, + ValueNode: itemsValue, + } + } + if len(prefixItems) > 0 { + s.PrefixItems = low.NodeReference[[]low.ValueReference[*SchemaProxy]]{ + Value: prefixItems, + KeyNode: prefixItemsLabel, + ValueNode: prefixItemsValue, + } + } + if !contains.IsEmpty() { + s.Contains = low.NodeReference[*SchemaProxy]{ + Value: contains.Value, + KeyNode: containsLabel, + ValueNode: containsValue, + } + } + if !sif.IsEmpty() { + s.If = low.NodeReference[*SchemaProxy]{ + Value: sif.Value, + KeyNode: sifLabel, + ValueNode: sifValue, + } + } + if !selse.IsEmpty() { + s.Else = low.NodeReference[*SchemaProxy]{ + Value: selse.Value, + KeyNode: selseLabel, + ValueNode: selseValue, + } + } + if !sthen.IsEmpty() { + s.Then = low.NodeReference[*SchemaProxy]{ + Value: sthen.Value, + KeyNode: sthenLabel, + ValueNode: sthenValue, + } + } + if !propertyNames.IsEmpty() { + s.PropertyNames = low.NodeReference[*SchemaProxy]{ + Value: propertyNames.Value, + KeyNode: propNamesLabel, + ValueNode: propNamesValue, + } + } + if !unevalItems.IsEmpty() { + s.UnevaluatedItems = low.NodeReference[*SchemaProxy]{ + Value: unevalItems.Value, + KeyNode: unevalItemsLabel, + ValueNode: unevalItemsValue, + } + } + if !unevalProperties.IsEmpty() { + s.UnevaluatedProperties = low.NodeReference[*SchemaProxy]{ + Value: unevalProperties.Value, + KeyNode: unevalPropsLabel, + ValueNode: unevalPropsValue, + } + } + return nil +} + +func buildPropertyMap(root *yaml.Node, idx *index.SpecIndex, label string) (*low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*SchemaProxy]], error) { + // for property, build in a new thread! + bChan := make(chan schemaProxyBuildResult) + + buildProperty := func(label *yaml.Node, value *yaml.Node, c chan schemaProxyBuildResult, isRef bool, + refString string, + ) { + c <- schemaProxyBuildResult{ + k: low.KeyReference[string]{ + KeyNode: label, + Value: label.Value, + }, + v: low.ValueReference[*SchemaProxy]{ + Value: &SchemaProxy{kn: label, vn: value, idx: idx, isReference: isRef, referenceLookup: refString}, + ValueNode: value, + }, + } + } + + _, propLabel, propsNode := utils.FindKeyNodeFullTop(label, root.Content) + if propsNode != nil { + propertyMap := make(map[low.KeyReference[string]]low.ValueReference[*SchemaProxy]) + var currentProp *yaml.Node + totalProps := 0 + for i, prop := range propsNode.Content { + if i%2 == 0 { + currentProp = prop + continue + } + + // check our prop isn't reference + isRef := false + refString := "" + if h, _, l := utils.IsNodeRefValue(prop); h { + ref, _ := low.LocateRefNode(prop, idx) + if ref != nil { + isRef = true + prop = ref + refString = l + } else { + return nil, fmt.Errorf("schema properties build failed: cannot find reference %s, line %d, col %d", + prop.Content[1].Value, prop.Content[1].Line, prop.Content[1].Column) + } + } + totalProps++ + go buildProperty(currentProp, prop, bChan, isRef, refString) + } + completedProps := 0 + for completedProps < totalProps { + select { + case res := <-bChan: + completedProps++ + propertyMap[res.k] = res.v + } + } + return &low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*SchemaProxy]]{ + Value: propertyMap, + KeyNode: propLabel, + ValueNode: propsNode, + }, nil + } + return nil, nil +} + +// count the number of sub-schemas in a node. +func countSubSchemaItems(node *yaml.Node) int { + if utils.IsNodeMap(node) { + return 1 + } + if utils.IsNodeArray(node) { + return len(node.Content) + } + return 0 +} + +// schema build result container used for async building. +type schemaProxyBuildResult struct { + k low.KeyReference[string] + v low.ValueReference[*SchemaProxy] +} + +// extract extensions from schema +func (s *Schema) extractExtensions(root *yaml.Node) { + s.Extensions = low.ExtractExtensions(root) +} + +// build out a child schema for parent schema. +func buildSchema(schemas chan schemaProxyBuildResult, labelNode, valueNode *yaml.Node, errors chan error, idx *index.SpecIndex) { + if valueNode != nil { + type buildResult struct { + res *low.ValueReference[*SchemaProxy] + idx int + } + + syncChan := make(chan buildResult) + + // build out a SchemaProxy for every sub-schema. + build := func(kn *yaml.Node, vn *yaml.Node, schemaIdx int, c chan buildResult, + isRef bool, refLocation string, + ) { + // a proxy design works best here. polymorphism, pretty much guarantees that a sub-schema can + // take on circular references through polymorphism. Like the resolver, if we try and follow these + // journey's through hyperspace, we will end up creating endless amounts of threads, spinning off + // chasing down circles, that in turn spin up endless threads. + // In order to combat this, we need a schema proxy that will only resolve the schema when asked, and then + // it will only do it one level at a time. + sp := new(SchemaProxy) + sp.kn = kn + sp.vn = vn + sp.idx = idx + if isRef { + sp.referenceLookup = refLocation + sp.isReference = true + } + res := &low.ValueReference[*SchemaProxy]{ + Value: sp, + ValueNode: vn, + } + c <- buildResult{ + res: res, + idx: schemaIdx, + } + } + + isRef := false + refLocation := "" + if utils.IsNodeMap(valueNode) { + h := false + if h, _, refLocation = utils.IsNodeRefValue(valueNode); h { + isRef = true + ref, _ := low.LocateRefNode(valueNode, idx) + if ref != nil { + valueNode = ref + } else { + errors <- fmt.Errorf("build schema failed: reference cannot be found: %s, line %d, col %d", + valueNode.Content[1].Value, valueNode.Content[1].Line, valueNode.Content[1].Column) + } + } + + // this only runs once, however to keep things consistent, it makes sense to use the same async method + // that arrays will use. + go build(labelNode, valueNode, -1, syncChan, isRef, refLocation) + select { + case r := <-syncChan: + schemas <- schemaProxyBuildResult{ + k: low.KeyReference[string]{ + KeyNode: labelNode, + Value: labelNode.Value, + }, + v: *r.res, + } + } + } + if utils.IsNodeArray(valueNode) { + refBuilds := 0 + results := make([]*low.ValueReference[*SchemaProxy], len(valueNode.Content)) + + for i, vn := range valueNode.Content { + isRef = false + h := false + if h, _, refLocation = utils.IsNodeRefValue(vn); h { + isRef = true + ref, _ := low.LocateRefNode(vn, idx) + if ref != nil { + vn = ref + } else { + err := fmt.Errorf("build schema failed: reference cannot be found: %s, line %d, col %d", + vn.Content[1].Value, vn.Content[1].Line, vn.Content[1].Column) + errors <- err + return + } + } + refBuilds++ + go build(vn, vn, i, syncChan, isRef, refLocation) + } + + completedBuilds := 0 + for completedBuilds < refBuilds { + select { + case res := <-syncChan: + completedBuilds++ + results[res.idx] = res.res + } + } + + for _, r := range results { + schemas <- schemaProxyBuildResult{ + k: low.KeyReference[string]{ + KeyNode: labelNode, + Value: labelNode.Value, + }, + v: *r, + } + } + } + } +} + +// ExtractSchema will return a pointer to a NodeReference that contains a *SchemaProxy if successful. The function +// will specifically look for a key node named 'schema' and extract the value mapped to that key. If the operation +// fails then no NodeReference is returned and an error is returned instead. +func ExtractSchema(root *yaml.Node, idx *index.SpecIndex) (*low.NodeReference[*SchemaProxy], error) { + var schLabel, schNode *yaml.Node + errStr := "schema build failed: reference '%s' cannot be found at line %d, col %d" + + isRef := false + refLocation := "" + if rf, rl, _ := utils.IsNodeRefValue(root); rf { + // locate reference in index. + isRef = true + ref, _ := low.LocateRefNode(root, idx) + if ref != nil { + schNode = ref + schLabel = rl + } else { + return nil, fmt.Errorf(errStr, + root.Content[1].Value, root.Content[1].Line, root.Content[1].Column) + } + } else { + _, schLabel, schNode = utils.FindKeyNodeFull(SchemaLabel, root.Content) + if schNode != nil { + h := false + if h, _, refLocation = utils.IsNodeRefValue(schNode); h { + isRef = true + ref, _ := low.LocateRefNode(schNode, idx) + if ref != nil { + schNode = ref + } else { + return nil, fmt.Errorf(errStr, + schNode.Content[1].Value, schNode.Content[1].Line, schNode.Content[1].Column) + } + } + } + } + + if schNode != nil { + // check if schema has already been built. + schema := &SchemaProxy{kn: schLabel, vn: schNode, idx: idx, isReference: isRef, referenceLookup: refLocation} + return &low.NodeReference[*SchemaProxy]{Value: schema, KeyNode: schLabel, ValueNode: schNode, ReferenceNode: isRef, + Reference: refLocation}, nil + } + return nil, nil +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/low/base/schema_proxy.go b/vendor/github.com/pb33f/libopenapi/datamodel/low/base/schema_proxy.go new file mode 100644 index 0000000000..a3ac15ed12 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/low/base/schema_proxy.go @@ -0,0 +1,150 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package base + +import ( + "crypto/sha256" + + "github.com/pb33f/libopenapi/index" + "github.com/pb33f/libopenapi/utils" + "gopkg.in/yaml.v3" +) + +// SchemaProxy exists as a stub that will create a Schema once (and only once) the Schema() method is called. +// +// Why use a Proxy design? +// +// There are three reasons. +// +// 1. Circular References and Endless Loops. +// +// JSON Schema allows for references to be used. This means references can loop around and create infinite recursive +// structures, These 'Circular references' technically mean a schema can NEVER be resolved, not without breaking the +// loop somewhere along the chain. +// +// Polymorphism in the form of 'oneOf' and 'anyOf' in version 3+ only exacerbates the problem. +// +// These circular traps can be discovered using the resolver, however it's still not enough to stop endless loops and +// endless goroutine spawning. A proxy design means that resolving occurs on demand and runs down a single level only. +// preventing any run-away loops. +// +// 2. Performance +// +// Even without circular references, Polymorphism creates large additional resolving chains that take a long time +// and slow things down when building. By preventing recursion through every polymorphic item, building models is kept +// fast and snappy, which is desired for realtime processing of specs. +// +// - Q: Yeah, but, why not just use state to avoiding re-visiting seen polymorphic nodes? +// - A: It's slow, takes up memory and still has runaway potential in very, very long chains. +// +// 3. Short Circuit Errors. +// +// Schemas are where things can get messy, mainly because the Schema standard changes between versions, and +// it's not actually JSONSchema until 3.1, so lots of times a bad schema will break parsing. Errors are only found +// when a schema is needed, so the rest of the document is parsed and ready to use. +type SchemaProxy struct { + kn *yaml.Node + vn *yaml.Node + idx *index.SpecIndex + rendered *Schema + buildError error + isReference bool // Is the schema underneath originally a $ref? + referenceLookup string // If the schema is a $ref, what's its name? +} + +// Build will prepare the SchemaProxy for rendering, it does not build the Schema, only sets up internal state. +func (sp *SchemaProxy) Build(root *yaml.Node, idx *index.SpecIndex) error { + sp.vn = root + sp.idx = idx + if rf, _, r := utils.IsNodeRefValue(root); rf { + sp.isReference = true + sp.referenceLookup = r + } + return nil +} + +// Schema will first check if this SchemaProxy has already rendered the schema, and return the pre-rendered version +// first. +// +// If this is the first run of Schema(), then the SchemaProxy will create a new Schema from the underlying +// yaml.Node. Once built out, the SchemaProxy will record that Schema as rendered and store it for later use, +// (this is what is we mean when we say 'pre-rendered'). +// +// Schema() then returns the newly created Schema. +// +// If anything goes wrong during the build, then nothing is returned and the error that occurred can +// be retrieved by using GetBuildError() +func (sp *SchemaProxy) Schema() *Schema { + if sp.rendered != nil { + return sp.rendered + } + schema := new(Schema) + err := schema.Build(sp.vn, sp.idx) + if err != nil { + sp.buildError = err + return nil + } + schema.ParentProxy = sp // https://github.com/pb33f/libopenapi/issues/29 + sp.rendered = schema + return schema +} + +// GetBuildError returns the build error that was set when Schema() was called. If Schema() has not been run, or +// there were no errors during build, then nil will be returned. +func (sp *SchemaProxy) GetBuildError() error { + return sp.buildError +} + +// IsSchemaReference returns true if the Schema that this SchemaProxy represents, is actually a reference to +// a Schema contained within Components or Definitions. There is no difference in the mechanism used to resolve the +// Schema when calling Schema(), however if we want to know if this schema was originally a reference, we won't +// be able to determine that from the model, without this bit. +func (sp *SchemaProxy) IsSchemaReference() bool { + return sp.isReference +} + +// IsReference is an alias for IsSchemaReference() except it's compatible wih the IsReferenced interface type. +func (sp *SchemaProxy) IsReference() bool { + return sp.IsSchemaReference() +} + +// GetReference is an alias for GetSchemaReference() except it's compatible wih the IsReferenced interface type. +func (sp *SchemaProxy) GetReference() string { + return sp.GetSchemaReference() +} + +// SetReference will set the reference lookup for this SchemaProxy. +func (sp *SchemaProxy) SetReference(ref string) { + sp.referenceLookup = ref +} + +// GetSchemaReference will return the lookup defined by the $ref that this schema points to. If the schema +// is inline, and not a reference, then this method returns an empty string. Only useful when combined with +// IsSchemaReference() +func (sp *SchemaProxy) GetSchemaReference() string { + return sp.referenceLookup +} + +// GetValueNode will return the yaml.Node pointer used by the proxy to generate the Schema. +func (sp *SchemaProxy) GetValueNode() *yaml.Node { + return sp.vn +} + +// Hash will return a consistent SHA256 Hash of the SchemaProxy object (it will resolve it) +func (sp *SchemaProxy) Hash() [32]byte { + if sp.rendered != nil { + if !sp.isReference { + return sp.rendered.Hash() + } + } else { + if !sp.isReference { + // only resolve this proxy if it's not a ref. + sch := sp.Schema() + sp.rendered = sch + return sch.Hash() + } + } + // hash reference value only, do not resolve! + return sha256.Sum256([]byte(sp.referenceLookup)) +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/low/base/security_requirement.go b/vendor/github.com/pb33f/libopenapi/datamodel/low/base/security_requirement.go new file mode 100644 index 0000000000..ac57e6ea3b --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/low/base/security_requirement.go @@ -0,0 +1,104 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package base + +import ( + "crypto/sha256" + "fmt" + "github.com/pb33f/libopenapi/datamodel/low" + "github.com/pb33f/libopenapi/index" + "gopkg.in/yaml.v3" + "sort" + "strings" +) + +// SecurityRequirement is a low-level representation of a Swagger / OpenAPI 3 SecurityRequirement object. +// +// SecurityRequirement lists the required security schemes to execute this operation. The object can have multiple +// security schemes declared in it which are all required (that is, there is a logical AND between the schemes). +// +// The name used for each property MUST correspond to a security scheme declared in the Security Definitions +// - https://swagger.io/specification/v2/#securityDefinitionsObject +// - https://swagger.io/specification/#security-requirement-object +type SecurityRequirement struct { + Requirements low.ValueReference[map[low.KeyReference[string]]low.ValueReference[[]low.ValueReference[string]]] + *low.Reference +} + +// Build will extract security requirements from the node (the structure is odd, to be honest) +func (s *SecurityRequirement) Build(root *yaml.Node, _ *index.SpecIndex) error { + s.Reference = new(low.Reference) + var labelNode *yaml.Node + valueMap := make(map[low.KeyReference[string]]low.ValueReference[[]low.ValueReference[string]]) + var arr []low.ValueReference[string] + for i := range root.Content { + if i%2 == 0 { + labelNode = root.Content[i] + arr = []low.ValueReference[string]{} // reset roles. + continue + } + for j := range root.Content[i].Content { + arr = append(arr, low.ValueReference[string]{ + Value: root.Content[i].Content[j].Value, + ValueNode: root.Content[i].Content[j], + }) + } + valueMap[low.KeyReference[string]{ + Value: labelNode.Value, + KeyNode: labelNode, + }] = low.ValueReference[[]low.ValueReference[string]]{ + Value: arr, + ValueNode: root.Content[i], + } + } + s.Requirements = low.ValueReference[map[low.KeyReference[string]]low.ValueReference[[]low.ValueReference[string]]]{ + Value: valueMap, + ValueNode: root, + } + return nil +} + +// FindRequirement will attempt to locate a security requirement string from a supplied name. +func (s *SecurityRequirement) FindRequirement(name string) []low.ValueReference[string] { + for k := range s.Requirements.Value { + if k.Value == name { + return s.Requirements.Value[k].Value + } + } + return nil +} + +// GetKeys returns a string slice of all the keys used in the requirement. +func (s *SecurityRequirement) GetKeys() []string { + keys := make([]string, len(s.Requirements.Value)) + z := 0 + for k := range s.Requirements.Value { + keys[z] = k.Value + } + return keys +} + +// Hash will return a consistent SHA256 Hash of the SecurityRequirement object +func (s *SecurityRequirement) Hash() [32]byte { + var f []string + values := make(map[string][]string, len(s.Requirements.Value)) + var valKeys []string + for k := range s.Requirements.Value { + var vals []string + for y := range s.Requirements.Value[k].Value { + vals = append(vals, s.Requirements.Value[k].Value[y].Value) + // lol, I know. -------^^^^^ <- this is the actual value. + } + sort.Strings(vals) + valKeys = append(valKeys, k.Value) + if len(vals) > 0 { + values[k.Value] = vals + } + } + sort.Strings(valKeys) + for val := range valKeys { + f = append(f, fmt.Sprintf("%s-%s", valKeys[val], strings.Join(values[valKeys[val]], "|"))) + } + return sha256.Sum256([]byte(strings.Join(f, "|"))) +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/low/base/tag.go b/vendor/github.com/pb33f/libopenapi/datamodel/low/base/tag.go new file mode 100644 index 0000000000..dc99cb9e8f --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/low/base/tag.go @@ -0,0 +1,94 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package base + +import ( + "crypto/sha256" + "fmt" + "github.com/pb33f/libopenapi/datamodel/low" + "github.com/pb33f/libopenapi/index" + "gopkg.in/yaml.v3" + "sort" + "strings" +) + +// Tag represents a low-level Tag instance that is backed by a low-level one. +// +// Adds metadata to a single tag that is used by the Operation Object. It is not mandatory to have a Tag Object per +// tag defined in the Operation Object instances. +// - v2: https://swagger.io/specification/v2/#tagObject +// - v3: https://swagger.io/specification/#tag-object +type Tag struct { + Name low.NodeReference[string] + Description low.NodeReference[string] + ExternalDocs low.NodeReference[*ExternalDoc] + Extensions map[low.KeyReference[string]]low.ValueReference[any] + *low.Reference +} + +// FindExtension returns a ValueReference containing the extension value, if found. +func (t *Tag) FindExtension(ext string) *low.ValueReference[any] { + return low.FindItemInMap[any](ext, t.Extensions) +} + +// Build will extract extensions and external docs for the Tag. +func (t *Tag) Build(root *yaml.Node, idx *index.SpecIndex) error { + t.Reference = new(low.Reference) + t.Extensions = low.ExtractExtensions(root) + + // extract externalDocs + extDocs, err := low.ExtractObject[*ExternalDoc](ExternalDocsLabel, root, idx) + t.ExternalDocs = extDocs + return err +} + +// GetExtensions returns all Tag extensions and satisfies the low.HasExtensions interface. +func (t *Tag) GetExtensions() map[low.KeyReference[string]]low.ValueReference[any] { + return t.Extensions +} + +// Hash will return a consistent SHA256 Hash of the Info object +func (t *Tag) Hash() [32]byte { + var f []string + if !t.Name.IsEmpty() { + f = append(f, t.Name.Value) + } + if !t.Description.IsEmpty() { + f = append(f, t.Description.Value) + } + if !t.ExternalDocs.IsEmpty() { + f = append(f, low.GenerateHashString(t.ExternalDocs.Value)) + } + keys := make([]string, len(t.Extensions)) + z := 0 + for k := range t.Extensions { + keys[z] = fmt.Sprintf("%s-%x", k.Value, sha256.Sum256([]byte(fmt.Sprint(t.Extensions[k].Value)))) + z++ + } + sort.Strings(keys) + f = append(f, keys...) + return sha256.Sum256([]byte(strings.Join(f, "|"))) +} + +// TODO: future mutation API experiment code is here. this snippet is to re-marshal the object. +//func (t *Tag) MarshalYAML() (interface{}, error) { +// m := make(map[string]interface{}) +// for i := range t.Extensions { +// m[i.Value] = t.Extensions[i].Value +// } +// if t.Name.Value != "" { +// m[NameLabel] = t.Name.Value +// } +// if t.Description.Value != "" { +// m[DescriptionLabel] = t.Description.Value +// } +// if t.ExternalDocs.Value != nil { +// m[ExternalDocsLabel] = t.ExternalDocs.Value +// } +// return m, nil +//} +// +//func NewTag() *Tag { +// return new(Tag) +//} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/low/base/xml.go b/vendor/github.com/pb33f/libopenapi/datamodel/low/base/xml.go new file mode 100644 index 0000000000..607f7091d5 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/low/base/xml.go @@ -0,0 +1,70 @@ +package base + +import ( + "crypto/sha256" + "fmt" + "github.com/pb33f/libopenapi/datamodel/low" + "github.com/pb33f/libopenapi/index" + "gopkg.in/yaml.v3" + "sort" + "strings" +) + +// XML represents a low-level representation of an XML object defined by all versions of OpenAPI. +// +// A metadata object that allows for more fine-tuned XML model definitions. +// +// When using arrays, XML element names are not inferred (for singular/plural forms) and the name property SHOULD be +// used to add that information. See examples for expected behavior. +// v2 - https://swagger.io/specification/v2/#xmlObject +// v3 - https://swagger.io/specification/#xml-object +type XML struct { + Name low.NodeReference[string] + Namespace low.NodeReference[string] + Prefix low.NodeReference[string] + Attribute low.NodeReference[bool] + Wrapped low.NodeReference[bool] + Extensions map[low.KeyReference[string]]low.ValueReference[any] + *low.Reference +} + +// Build will extract extensions from the XML instance. +func (x *XML) Build(root *yaml.Node, _ *index.SpecIndex) error { + x.Reference = new(low.Reference) + x.Extensions = low.ExtractExtensions(root) + return nil +} + +// GetExtensions returns all Tag extensions and satisfies the low.HasExtensions interface. +func (x *XML) GetExtensions() map[low.KeyReference[string]]low.ValueReference[any] { + return x.Extensions +} + +// Hash generates a SHA256 hash of the XML object using properties +func (x *XML) Hash() [32]byte { + var f []string + if !x.Name.IsEmpty() { + f = append(f, x.Name.Value) + } + if !x.Namespace.IsEmpty() { + f = append(f, x.Namespace.Value) + } + if !x.Prefix.IsEmpty() { + f = append(f, x.Prefix.Value) + } + if !x.Attribute.IsEmpty() { + f = append(f, fmt.Sprint(x.Attribute.Value)) + } + if !x.Wrapped.IsEmpty() { + f = append(f, fmt.Sprint(x.Wrapped.Value)) + } + keys := make([]string, len(x.Extensions)) + z := 0 + for k := range x.Extensions { + keys[z] = fmt.Sprintf("%s-%x", k.Value, sha256.Sum256([]byte(fmt.Sprint(x.Extensions[k].Value)))) + z++ + } + sort.Strings(keys) + f = append(f, keys...) + return sha256.Sum256([]byte(strings.Join(f, "|"))) +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/low/extraction_functions.go b/vendor/github.com/pb33f/libopenapi/datamodel/low/extraction_functions.go new file mode 100644 index 0000000000..b4cab9886c --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/low/extraction_functions.go @@ -0,0 +1,689 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package low + +import ( + "crypto/sha256" + "fmt" + "strconv" + "strings" + + "github.com/pb33f/libopenapi/index" + "github.com/pb33f/libopenapi/utils" + "github.com/vmware-labs/yaml-jsonpath/pkg/yamlpath" + "gopkg.in/yaml.v3" +) + +// FindItemInMap accepts a string key and a collection of KeyReference[string] and ValueReference[T]. Every +// KeyReference will have its value checked against the string key and if there is a match, it will be returned. +func FindItemInMap[T any](item string, collection map[KeyReference[string]]ValueReference[T]) *ValueReference[T] { + for n, o := range collection { + if n.Value == item { + return &o + } + if strings.ToLower(n.Value) == strings.ToLower(item) { + return &o + } + } + return nil +} + +// helper function to generate a list of all the things an index should be searched for. +func generateIndexCollection(idx *index.SpecIndex) []func() map[string]*index.Reference { + return []func() map[string]*index.Reference{ + idx.GetAllComponentSchemas, + idx.GetMappedReferences, + idx.GetAllExternalDocuments, + idx.GetAllParameters, + idx.GetAllHeaders, + idx.GetAllCallbacks, + idx.GetAllLinks, + idx.GetAllExamples, + idx.GetAllRequestBodies, + idx.GetAllResponses, + idx.GetAllSecuritySchemes, + } +} + +// LocateRefNode will perform a complete lookup for a $ref node. This function searches the entire index for +// the reference being supplied. If there is a match found, the reference *yaml.Node is returned. +func LocateRefNode(root *yaml.Node, idx *index.SpecIndex) (*yaml.Node, error) { + if rf, _, rv := utils.IsNodeRefValue(root); rf { + + // run through everything and return as soon as we find a match. + // this operates as fast as possible as ever + collections := generateIndexCollection(idx) + + // if there are any external indexes being used by remote + // documents, then we need to search through them also. + externalIndexes := idx.GetAllExternalIndexes() + if len(externalIndexes) > 0 { + var extCollection []func() map[string]*index.Reference + for _, extIndex := range externalIndexes { + extCollection = generateIndexCollection(extIndex) + collections = append(collections, extCollection...) + } + } + + var found map[string]*index.Reference + for _, collection := range collections { + found = collection() + if found != nil && found[rv] != nil { + + // if this is a ref node, we need to keep diving + // until we hit something that isn't a ref. + if jh, _, _ := utils.IsNodeRefValue(found[rv].Node); jh { + // if this node is circular, stop drop and roll. + if !IsCircular(found[rv].Node, idx) { + return LocateRefNode(found[rv].Node, idx) + } else { + return found[rv].Node, fmt.Errorf("circular reference '%s' found during lookup at line "+ + "%d, column %d, It cannot be resolved", + GetCircularReferenceResult(found[rv].Node, idx).GenerateJourneyPath(), + found[rv].Node.Line, + found[rv].Node.Column) + } + } + return found[rv].Node, nil + } + } + + // perform a search for the reference in the index + foundRefs := idx.SearchIndexForReference(rv) + if len(foundRefs) > 0 { + return foundRefs[0].Node, nil + } + + // let's try something else to find our references. + + // cant be found? last resort is to try a path lookup + _, friendly := utils.ConvertComponentIdIntoFriendlyPathSearch(rv) + if friendly != "" { + path, err := yamlpath.NewPath(friendly) + if err == nil { + nodes, fErr := path.Find(idx.GetRootNode()) + if fErr == nil { + if len(nodes) > 0 { + return nodes[0], nil + } + } + } + } + return nil, fmt.Errorf("reference '%s' at line %d, column %d was not found", + rv, root.Line, root.Column) + } + return nil, nil +} + +// ExtractObjectRaw will extract a typed Buildable[N] object from a root yaml.Node. The 'raw' aspect is +// that there is no NodeReference wrapper around the result returned, just the raw object. +func ExtractObjectRaw[T Buildable[N], N any](root *yaml.Node, idx *index.SpecIndex) (T, error, bool, string) { + var circError error + var isReference bool + var referenceValue string + if h, _, rv := utils.IsNodeRefValue(root); h { + ref, err := LocateRefNode(root, idx) + if ref != nil { + root = ref + isReference = true + referenceValue = rv + if err != nil { + circError = err + } + } else { + if err != nil { + return nil, fmt.Errorf("object extraction failed: %s", err.Error()), isReference, referenceValue + } + } + } + var n T = new(N) + err := BuildModel(root, n) + if err != nil { + return n, err, isReference, referenceValue + } + err = n.Build(root, idx) + if err != nil { + return n, err, isReference, referenceValue + } + + // if this is a reference, keep track of the reference in the value + if isReference { + SetReference(n, referenceValue) + } + + // do we want to throw an error as well if circular error reporting is on? + if circError != nil && !idx.AllowCircularReferenceResolving() { + return n, circError, isReference, referenceValue + } + return n, nil, isReference, referenceValue +} + +// ExtractObject will extract a typed Buildable[N] object from a root yaml.Node. The result is wrapped in a +// NodeReference[T] that contains the key node found and value node found when looking up the reference. +func ExtractObject[T Buildable[N], N any](label string, root *yaml.Node, idx *index.SpecIndex) (NodeReference[T], error) { + var ln, vn *yaml.Node + var circError error + var isReference bool + var referenceValue string + if rf, rl, refVal := utils.IsNodeRefValue(root); rf { + ref, err := LocateRefNode(root, idx) + if ref != nil { + vn = ref + ln = rl + isReference = true + referenceValue = refVal + if err != nil { + circError = err + } + } else { + if err != nil { + return NodeReference[T]{}, fmt.Errorf("object extraction failed: %s", err.Error()) + } + } + } else { + _, ln, vn = utils.FindKeyNodeFull(label, root.Content) + if vn != nil { + if h, _, rVal := utils.IsNodeRefValue(vn); h { + ref, lerr := LocateRefNode(vn, idx) + if ref != nil { + vn = ref + isReference = true + referenceValue = rVal + if lerr != nil { + circError = lerr + } + } else { + if lerr != nil { + return NodeReference[T]{}, fmt.Errorf("object extraction failed: %s", lerr.Error()) + } + } + } + } + } + var n T = new(N) + err := BuildModel(vn, n) + if err != nil { + return NodeReference[T]{}, err + } + if ln == nil { + return NodeReference[T]{}, nil + } + err = n.Build(vn, idx) + if err != nil { + return NodeReference[T]{}, err + } + + // if this is a reference, keep track of the reference in the value + if isReference { + SetReference(n, referenceValue) + } + + res := NodeReference[T]{ + Value: n, + KeyNode: ln, + ValueNode: vn, + ReferenceNode: isReference, + Reference: referenceValue, + } + + // do we want to throw an error as well if circular error reporting is on? + if circError != nil && !idx.AllowCircularReferenceResolving() { + return res, circError + } + return res, nil +} + +func SetReference(obj any, ref string) { + if obj == nil { + return + } + if r, ok := obj.(IsReferenced); ok { + r.SetReference(ref) + } +} + +// ExtractArray will extract a slice of []ValueReference[T] from a root yaml.Node that is defined as a sequence. +// Used when the value being extracted is an array. +func ExtractArray[T Buildable[N], N any](label string, root *yaml.Node, idx *index.SpecIndex) ([]ValueReference[T], + *yaml.Node, *yaml.Node, error, +) { + var ln, vn *yaml.Node + var circError error + if rf, rl, _ := utils.IsNodeRefValue(root); rf { + ref, err := LocateRefNode(root, idx) + if ref != nil { + vn = ref + ln = rl + if err != nil { + circError = err + } + } else { + return []ValueReference[T]{}, nil, nil, fmt.Errorf("array build failed: reference cannot be found: %s", + root.Content[1].Value) + } + } else { + _, ln, vn = utils.FindKeyNodeFullTop(label, root.Content) + if vn != nil { + if h, _, _ := utils.IsNodeRefValue(vn); h { + ref, err := LocateRefNode(vn, idx) + if ref != nil { + vn = ref + //referenceValue = rVal + if err != nil { + circError = err + } + } else { + if err != nil { + return []ValueReference[T]{}, nil, nil, fmt.Errorf("array build failed: reference cannot be found: %s", + err.Error()) + } + } + } + } + } + + var items []ValueReference[T] + if vn != nil && ln != nil { + if !utils.IsNodeArray(vn) { + return []ValueReference[T]{}, nil, nil, fmt.Errorf("array build failed, input is not an array, line %d, column %d", vn.Line, vn.Column) + } + for _, node := range vn.Content { + localReferenceValue := "" + //localIsReference := false + + if rf, _, rv := utils.IsNodeRefValue(node); rf { + refg, err := LocateRefNode(node, idx) + if refg != nil { + node = refg + //localIsReference = true + localReferenceValue = rv + if err != nil { + circError = err + } + } else { + if err != nil { + return []ValueReference[T]{}, nil, nil, fmt.Errorf("array build failed: reference cannot be found: %s", + err.Error()) + } + } + } + var n T = new(N) + err := BuildModel(node, n) + if err != nil { + return []ValueReference[T]{}, ln, vn, err + } + berr := n.Build(node, idx) + if berr != nil { + return nil, ln, vn, berr + } + + if localReferenceValue != "" { + SetReference(n, localReferenceValue) + } + + items = append(items, ValueReference[T]{ + Value: n, + ValueNode: node, + ReferenceNode: localReferenceValue != "", + Reference: localReferenceValue, + }) + } + } + // include circular errors? + if circError != nil && !idx.AllowCircularReferenceResolving() { + return items, ln, vn, circError + } + return items, ln, vn, nil +} + +// ExtractExample will extract a value supplied as an example into a NodeReference. Value can be anything. +// the node value is untyped, so casting will be required when trying to use it. +func ExtractExample(expNode, expLabel *yaml.Node) NodeReference[any] { + ref := NodeReference[any]{Value: expNode.Value, KeyNode: expLabel, ValueNode: expNode} + if utils.IsNodeMap(expNode) { + var decoded map[string]interface{} + _ = expNode.Decode(&decoded) + ref.Value = decoded + } + if utils.IsNodeArray(expNode) { + var decoded []interface{} + _ = expNode.Decode(&decoded) + ref.Value = decoded + } + return ref +} + +// ExtractMapNoLookupExtensions will extract a map of KeyReference and ValueReference from a root yaml.Node. The 'NoLookup' part +// refers to the fact that there is no key supplied as part of the extraction, there is no lookup performed and the +// root yaml.Node pointer is used directly. Pass a true bit to includeExtensions to include extension keys in the map. +// +// This is useful when the node to be extracted, is already known and does not require a search. +func ExtractMapNoLookupExtensions[PT Buildable[N], N any]( + root *yaml.Node, + idx *index.SpecIndex, + includeExtensions bool, +) (map[KeyReference[string]]ValueReference[PT], error) { + valueMap := make(map[KeyReference[string]]ValueReference[PT]) + var circError error + if utils.IsNodeMap(root) { + var currentKey *yaml.Node + skip := false + for i, node := range root.Content { + if !includeExtensions { + if strings.HasPrefix(strings.ToLower(node.Value), "x-") { + skip = true + continue + } + } + if skip { + skip = false + continue + } + if i%2 == 0 { + currentKey = node + continue + } + + var isReference bool + var referenceValue string + // if value is a reference, we have to look it up in the index! + if h, _, rv := utils.IsNodeRefValue(node); h { + ref, err := LocateRefNode(node, idx) + if ref != nil { + node = ref + isReference = true + referenceValue = rv + if err != nil { + circError = err + } + } else { + if err != nil { + return nil, fmt.Errorf("map build failed: reference cannot be found: %s", err.Error()) + } + } + } + + var n PT = new(N) + err := BuildModel(node, n) + if err != nil { + return nil, err + } + berr := n.Build(node, idx) + if berr != nil { + return nil, berr + } + if isReference { + SetReference(n, referenceValue) + } + if currentKey != nil { + valueMap[KeyReference[string]{ + Value: currentKey.Value, + KeyNode: currentKey, + }] = ValueReference[PT]{ + Value: n, + ValueNode: node, + //IsReference: isReference, + Reference: referenceValue, + } + } + } + } + if circError != nil && !idx.AllowCircularReferenceResolving() { + return valueMap, circError + } + return valueMap, nil + +} + +// ExtractMapNoLookup will extract a map of KeyReference and ValueReference from a root yaml.Node. The 'NoLookup' part +// refers to the fact that there is no key supplied as part of the extraction, there is no lookup performed and the +// root yaml.Node pointer is used directly. +// +// This is useful when the node to be extracted, is already known and does not require a search. +func ExtractMapNoLookup[PT Buildable[N], N any]( + root *yaml.Node, + idx *index.SpecIndex, +) (map[KeyReference[string]]ValueReference[PT], error) { + return ExtractMapNoLookupExtensions[PT, N](root, idx, false) +} + +type mappingResult[T any] struct { + k KeyReference[string] + v ValueReference[T] +} + +// ExtractMapExtensions will extract a map of KeyReference and ValueReference from a root yaml.Node. The 'label' is +// used to locate the node to be extracted from the root node supplied. Supply a bit to decide if extensions should +// be included or not. required in some use cases. +// +// The second return value is the yaml.Node found for the 'label' and the third return value is the yaml.Node +// found for the value extracted from the label node. +func ExtractMapExtensions[PT Buildable[N], N any]( + label string, + root *yaml.Node, + idx *index.SpecIndex, + extensions bool, +) (map[KeyReference[string]]ValueReference[PT], *yaml.Node, *yaml.Node, error) { + //var isReference bool + var referenceValue string + var labelNode, valueNode *yaml.Node + var circError error + if rf, rl, rv := utils.IsNodeRefValue(root); rf { + // locate reference in index. + ref, err := LocateRefNode(root, idx) + if ref != nil { + valueNode = ref + labelNode = rl + //isReference = true + referenceValue = rv + if err != nil { + circError = err + } + } else { + return nil, labelNode, valueNode, fmt.Errorf("map build failed: reference cannot be found: %s", + root.Content[1].Value) + } + } else { + _, labelNode, valueNode = utils.FindKeyNodeFull(label, root.Content) + if valueNode != nil { + if h, _, rvt := utils.IsNodeRefValue(valueNode); h { + ref, err := LocateRefNode(valueNode, idx) + if ref != nil { + valueNode = ref + //isReference = true + referenceValue = rvt + if err != nil { + circError = err + } + } else { + if err != nil { + return nil, labelNode, valueNode, fmt.Errorf("map build failed: reference cannot be found: %s", + err.Error()) + } + } + } + } + } + if valueNode != nil { + var currentLabelNode *yaml.Node + valueMap := make(map[KeyReference[string]]ValueReference[PT]) + + bChan := make(chan mappingResult[PT]) + eChan := make(chan error) + + buildMap := func(label *yaml.Node, value *yaml.Node, c chan mappingResult[PT], ec chan<- error, ref string) { + var n PT = new(N) + _ = BuildModel(value, n) + err := n.Build(value, idx) + if err != nil { + ec <- err + return + } + + //isRef := false + if ref != "" { + //isRef = true + SetReference(n, ref) + } + + c <- mappingResult[PT]{ + k: KeyReference[string]{ + KeyNode: label, + Value: label.Value, + }, + v: ValueReference[PT]{ + Value: n, + ValueNode: value, + //IsReference: isRef, + Reference: ref, + }, + } + } + + totalKeys := 0 + for i, en := range valueNode.Content { + referenceValue = "" + if i%2 == 0 { + currentLabelNode = en + continue + } + // check our valueNode isn't a reference still. + if h, _, refVal := utils.IsNodeRefValue(en); h { + ref, err := LocateRefNode(en, idx) + if ref != nil { + en = ref + referenceValue = refVal + if err != nil { + circError = err + } + } else { + if err != nil { + return nil, labelNode, valueNode, fmt.Errorf("flat map build failed: reference cannot be found: %s", + err.Error()) + } + } + } + + if !extensions { + if strings.HasPrefix(currentLabelNode.Value, "x-") { + continue // yo, don't pay any attention to extensions, not here anyway. + } + } + totalKeys++ + go buildMap(currentLabelNode, en, bChan, eChan, referenceValue) + } + + completedKeys := 0 + for completedKeys < totalKeys { + select { + case err := <-eChan: + return valueMap, labelNode, valueNode, err + case res := <-bChan: + completedKeys++ + valueMap[res.k] = res.v + } + } + if circError != nil && !idx.AllowCircularReferenceResolving() { + return valueMap, labelNode, valueNode, circError + } + return valueMap, labelNode, valueNode, nil + } + return nil, labelNode, valueNode, nil +} + +// ExtractMap will extract a map of KeyReference and ValueReference from a root yaml.Node. The 'label' is +// used to locate the node to be extracted from the root node supplied. +// +// The second return value is the yaml.Node found for the 'label' and the third return value is the yaml.Node +// found for the value extracted from the label node. +func ExtractMap[PT Buildable[N], N any]( + label string, + root *yaml.Node, + idx *index.SpecIndex, +) (map[KeyReference[string]]ValueReference[PT], *yaml.Node, *yaml.Node, error) { + return ExtractMapExtensions[PT, N](label, root, idx, false) +} + +// ExtractExtensions will extract any 'x-' prefixed key nodes from a root node into a map. Requirements have been pre-cast: +// +// Maps +// +// map[string]interface{} for maps +// +// Slices +// +// []interface{} +// +// int, float, bool, string +// +// int64, float64, bool, string +func ExtractExtensions(root *yaml.Node) map[KeyReference[string]]ValueReference[any] { + extensions := utils.FindExtensionNodes(root.Content) + extensionMap := make(map[KeyReference[string]]ValueReference[any]) + for _, ext := range extensions { + if utils.IsNodeMap(ext.Value) { + var v interface{} + _ = ext.Value.Decode(&v) + extensionMap[KeyReference[string]{ + Value: ext.Key.Value, + KeyNode: ext.Key, + }] = ValueReference[any]{Value: v, ValueNode: ext.Value} + } + if utils.IsNodeStringValue(ext.Value) { + extensionMap[KeyReference[string]{ + Value: ext.Key.Value, + KeyNode: ext.Key, + }] = ValueReference[any]{Value: ext.Value.Value, ValueNode: ext.Value} + } + if utils.IsNodeFloatValue(ext.Value) { + fv, _ := strconv.ParseFloat(ext.Value.Value, 64) + extensionMap[KeyReference[string]{ + Value: ext.Key.Value, + KeyNode: ext.Key, + }] = ValueReference[any]{Value: fv, ValueNode: ext.Value} + } + if utils.IsNodeIntValue(ext.Value) { + iv, _ := strconv.ParseInt(ext.Value.Value, 10, 64) + extensionMap[KeyReference[string]{ + Value: ext.Key.Value, + KeyNode: ext.Key, + }] = ValueReference[any]{Value: iv, ValueNode: ext.Value} + } + if utils.IsNodeBoolValue(ext.Value) { + bv, _ := strconv.ParseBool(ext.Value.Value) + extensionMap[KeyReference[string]{ + Value: ext.Key.Value, + KeyNode: ext.Key, + }] = ValueReference[any]{Value: bv, ValueNode: ext.Value} + } + if utils.IsNodeArray(ext.Value) { + var v []interface{} + _ = ext.Value.Decode(&v) + extensionMap[KeyReference[string]{ + Value: ext.Key.Value, + KeyNode: ext.Key, + }] = ValueReference[any]{Value: v, ValueNode: ext.Value} + } + } + return extensionMap +} + +// AreEqual returns true if two Hashable objects are equal or not. +func AreEqual(l, r Hashable) bool { + if l == nil || r == nil { + return false + } + return l.Hash() == r.Hash() +} + +// GenerateHashString will generate a SHA36 hash of any object passed in. If the object is Hashable +// then the underlying Hash() method will be called. +func GenerateHashString(v any) string { + if h, ok := v.(Hashable); ok { + if h != nil { + return fmt.Sprintf(HASH, h.Hash()) + } + } + return fmt.Sprintf(HASH, sha256.Sum256([]byte(fmt.Sprint(v)))) +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/low/low.go b/vendor/github.com/pb33f/libopenapi/datamodel/low/low.go new file mode 100644 index 0000000000..8a3d1e01fe --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/low/low.go @@ -0,0 +1,14 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +// Package low contains a set of low-level models that represent OpenAPI 2 and 3 documents. +// These low-level models (plumbing) are used to create high-level models, and used when deep knowledge +// about the original data, positions, comments and the original node structures. +// +// Low-level models are not designed to be easily navigated, every single property is either a NodeReference +// an KeyReference or a ValueReference. These references hold the raw value and key or value nodes that contain +// the original yaml.Node trees that make up the object. +// +// Navigating maps that use a KeyReference as a key is tricky, because there is no easy way to provide a lookup. +// Convenience methods for lookup up properties in a low-level model have therefore been provided. +package low diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/low/model_builder.go b/vendor/github.com/pb33f/libopenapi/datamodel/low/model_builder.go new file mode 100644 index 0000000000..deb1400fa0 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/low/model_builder.go @@ -0,0 +1,487 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package low + +import ( + "fmt" + "reflect" + "strconv" + "strings" + "sync" + + "github.com/pb33f/libopenapi/utils" + "gopkg.in/yaml.v3" +) + +// BuildModel accepts a yaml.Node pointer and a model, which can be any struct. Using reflection, the model is +// analyzed and the names of all the properties are extracted from the model and subsequently looked up from within +// the yaml.Node.Content value. +// +// BuildModel is non-recursive and will only build out a single layer of the node tree. +func BuildModel(node *yaml.Node, model interface{}) error { + if node == nil { + return nil + } + + if reflect.ValueOf(model).Type().Kind() != reflect.Pointer { + return fmt.Errorf("cannot build model on non-pointer: %v", reflect.ValueOf(model).Type().Kind()) + } + v := reflect.ValueOf(model).Elem() + num := v.NumField() + for i := 0; i < num; i++ { + + fName := v.Type().Field(i).Name + + if fName == "Extensions" { + continue // internal construct + } + + if fName == "PathItems" { + continue // internal construct + } + + kn, vn := utils.FindKeyNodeTop(strings.ToLower(fName), node.Content) + if vn == nil { + // no point in going on. + continue + } + + field := v.FieldByName(fName) + kind := field.Kind() + switch kind { + case reflect.Struct, reflect.Slice, reflect.Map, reflect.Pointer: + err := SetField(&field, vn, kn) + if err != nil { + return err + } + default: + return fmt.Errorf("unable to parse unsupported type: %v", kind) + } + + } + + return nil +} + +// SetField accepts a field reflection value, a yaml.Node valueNode and a yaml.Node keyNode. Using reflection, the +// function will attempt to set the value of the field based on the key and value nodes. This method is only useful +// for low-level models, it has no value to high-level ones. +func SetField(field *reflect.Value, valueNode *yaml.Node, keyNode *yaml.Node) error { + if valueNode == nil { + return nil + } + + switch field.Type() { + + case reflect.TypeOf(map[string]NodeReference[any]{}): + if utils.IsNodeMap(valueNode) { + if field.CanSet() { + items := make(map[string]NodeReference[any]) + var currentLabel string + for i, sliceItem := range valueNode.Content { + if i%2 == 0 { + currentLabel = sliceItem.Value + continue + } + var decoded map[string]interface{} + // I cannot think of a way to make this error out by this point. + _ = sliceItem.Decode(&decoded) + items[currentLabel] = NodeReference[any]{ + Value: decoded, + ValueNode: sliceItem, + KeyNode: valueNode, + } + } + field.Set(reflect.ValueOf(items)) + } + } + + case reflect.TypeOf(map[string]NodeReference[string]{}): + + if utils.IsNodeMap(valueNode) { + if field.CanSet() { + items := make(map[string]NodeReference[string]) + var currentLabel string + for i, sliceItem := range valueNode.Content { + if i%2 == 0 { + currentLabel = sliceItem.Value + continue + } + items[currentLabel] = NodeReference[string]{ + Value: fmt.Sprintf("%v", sliceItem.Value), + ValueNode: sliceItem, + KeyNode: valueNode, + } + } + field.Set(reflect.ValueOf(items)) + } + } + + case reflect.TypeOf(NodeReference[any]{}): + + var decoded interface{} + _ = valueNode.Decode(&decoded) + if field.CanSet() { + or := NodeReference[any]{Value: decoded, ValueNode: valueNode, KeyNode: keyNode} + field.Set(reflect.ValueOf(or)) + } + + case reflect.TypeOf([]NodeReference[any]{}): + + if utils.IsNodeArray(valueNode) { + if field.CanSet() { + var items []NodeReference[any] + for _, sliceItem := range valueNode.Content { + var decoded map[string]interface{} + err := sliceItem.Decode(&decoded) + if err != nil { + return err + } + items = append(items, NodeReference[any]{ + Value: decoded, + ValueNode: sliceItem, + KeyNode: valueNode, + }) + } + field.Set(reflect.ValueOf(items)) + } + } + + case reflect.TypeOf(NodeReference[string]{}): + + if field.CanSet() { + nr := NodeReference[string]{ + Value: fmt.Sprintf("%v", valueNode.Value), + ValueNode: valueNode, + KeyNode: keyNode, + } + field.Set(reflect.ValueOf(nr)) + } + + case reflect.TypeOf(ValueReference[string]{}): + + if field.CanSet() { + nr := ValueReference[string]{ + Value: fmt.Sprintf("%v", valueNode.Value), + ValueNode: valueNode, + } + field.Set(reflect.ValueOf(nr)) + } + + case reflect.TypeOf(NodeReference[bool]{}): + + if utils.IsNodeBoolValue(valueNode) { + if field.CanSet() { + bv, _ := strconv.ParseBool(valueNode.Value) + nr := NodeReference[bool]{ + Value: bv, + ValueNode: valueNode, + KeyNode: keyNode, + } + field.Set(reflect.ValueOf(nr)) + } + } + + case reflect.TypeOf(NodeReference[int]{}): + + if utils.IsNodeIntValue(valueNode) { + if field.CanSet() { + fv, _ := strconv.Atoi(valueNode.Value) + nr := NodeReference[int]{ + Value: fv, + ValueNode: valueNode, + KeyNode: keyNode, + } + field.Set(reflect.ValueOf(nr)) + } + } + + case reflect.TypeOf(NodeReference[int64]{}): + + if utils.IsNodeIntValue(valueNode) || utils.IsNodeFloatValue(valueNode) { + if field.CanSet() { + fv, _ := strconv.ParseInt(valueNode.Value, 10, 64) + nr := NodeReference[int64]{ + Value: fv, + ValueNode: valueNode, + KeyNode: keyNode, + } + field.Set(reflect.ValueOf(nr)) + } + } + + case reflect.TypeOf(NodeReference[float32]{}): + + if utils.IsNodeFloatValue(valueNode) { + if field.CanSet() { + fv, _ := strconv.ParseFloat(valueNode.Value, 32) + nr := NodeReference[float32]{ + Value: float32(fv), + ValueNode: valueNode, + KeyNode: keyNode, + } + field.Set(reflect.ValueOf(nr)) + } + } + + case reflect.TypeOf(NodeReference[float64]{}): + + if utils.IsNodeFloatValue(valueNode) { + if field.CanSet() { + fv, _ := strconv.ParseFloat(valueNode.Value, 64) + nr := NodeReference[float64]{ + Value: fv, + ValueNode: valueNode, + KeyNode: keyNode, + } + field.Set(reflect.ValueOf(nr)) + } + } + + case reflect.TypeOf([]NodeReference[string]{}): + + if utils.IsNodeArray(valueNode) { + if field.CanSet() { + var items []NodeReference[string] + for _, sliceItem := range valueNode.Content { + items = append(items, NodeReference[string]{ + Value: sliceItem.Value, + ValueNode: sliceItem, + KeyNode: valueNode, + }) + } + field.Set(reflect.ValueOf(items)) + } + } + + case reflect.TypeOf([]NodeReference[float32]{}): + + if utils.IsNodeArray(valueNode) { + if field.CanSet() { + var items []NodeReference[float32] + for _, sliceItem := range valueNode.Content { + fv, _ := strconv.ParseFloat(sliceItem.Value, 32) + items = append(items, NodeReference[float32]{ + Value: float32(fv), + ValueNode: sliceItem, + KeyNode: valueNode, + }) + } + field.Set(reflect.ValueOf(items)) + } + } + + case reflect.TypeOf([]NodeReference[float64]{}): + + if utils.IsNodeArray(valueNode) { + if field.CanSet() { + var items []NodeReference[float64] + for _, sliceItem := range valueNode.Content { + fv, _ := strconv.ParseFloat(sliceItem.Value, 64) + items = append(items, NodeReference[float64]{Value: fv, ValueNode: sliceItem}) + } + field.Set(reflect.ValueOf(items)) + } + } + + case reflect.TypeOf([]NodeReference[int]{}): + + if utils.IsNodeArray(valueNode) { + if field.CanSet() { + var items []NodeReference[int] + for _, sliceItem := range valueNode.Content { + iv, _ := strconv.Atoi(sliceItem.Value) + items = append(items, NodeReference[int]{ + Value: iv, + ValueNode: sliceItem, + KeyNode: valueNode, + }) + } + field.Set(reflect.ValueOf(items)) + } + } + + case reflect.TypeOf([]NodeReference[int64]{}): + + if utils.IsNodeArray(valueNode) { + if field.CanSet() { + var items []NodeReference[int64] + for _, sliceItem := range valueNode.Content { + iv, _ := strconv.ParseInt(sliceItem.Value, 10, 64) + items = append(items, NodeReference[int64]{ + Value: iv, + ValueNode: sliceItem, + KeyNode: valueNode, + }) + } + field.Set(reflect.ValueOf(items)) + } + } + + case reflect.TypeOf([]NodeReference[bool]{}): + + if utils.IsNodeArray(valueNode) { + if field.CanSet() { + var items []NodeReference[bool] + for _, sliceItem := range valueNode.Content { + bv, _ := strconv.ParseBool(sliceItem.Value) + items = append(items, NodeReference[bool]{ + Value: bv, + ValueNode: sliceItem, + KeyNode: valueNode, + }) + } + field.Set(reflect.ValueOf(items)) + } + } + + // helper for unpacking string maps. + case reflect.TypeOf(map[KeyReference[string]]ValueReference[string]{}): + + if utils.IsNodeMap(valueNode) { + if field.CanSet() { + items := make(map[KeyReference[string]]ValueReference[string]) + var cf *yaml.Node + for i, sliceItem := range valueNode.Content { + if i%2 == 0 { + cf = sliceItem + continue + } + items[KeyReference[string]{ + Value: cf.Value, + KeyNode: cf, + }] = ValueReference[string]{ + Value: sliceItem.Value, + ValueNode: sliceItem, + } + } + field.Set(reflect.ValueOf(items)) + } + } + + case reflect.TypeOf(KeyReference[map[KeyReference[string]]ValueReference[string]]{}): + + if utils.IsNodeMap(valueNode) { + if field.CanSet() { + items := make(map[KeyReference[string]]ValueReference[string]) + var cf *yaml.Node + for i, sliceItem := range valueNode.Content { + if i%2 == 0 { + cf = sliceItem + continue + } + items[KeyReference[string]{ + Value: cf.Value, + KeyNode: cf, + }] = ValueReference[string]{ + Value: sliceItem.Value, + ValueNode: sliceItem, + } + } + ref := KeyReference[map[KeyReference[string]]ValueReference[string]]{ + Value: items, + KeyNode: keyNode, + } + field.Set(reflect.ValueOf(ref)) + } + } + case reflect.TypeOf(NodeReference[map[KeyReference[string]]ValueReference[string]]{}): + if utils.IsNodeMap(valueNode) { + if field.CanSet() { + items := make(map[KeyReference[string]]ValueReference[string]) + var cf *yaml.Node + for i, sliceItem := range valueNode.Content { + if i%2 == 0 { + cf = sliceItem + continue + } + items[KeyReference[string]{ + Value: cf.Value, + KeyNode: cf, + }] = ValueReference[string]{ + Value: sliceItem.Value, + ValueNode: sliceItem, + } + } + ref := NodeReference[map[KeyReference[string]]ValueReference[string]]{ + Value: items, + KeyNode: keyNode, + ValueNode: valueNode, + } + field.Set(reflect.ValueOf(ref)) + } + } + case reflect.TypeOf(NodeReference[[]ValueReference[string]]{}): + + if utils.IsNodeArray(valueNode) { + if field.CanSet() { + var items []ValueReference[string] + for _, sliceItem := range valueNode.Content { + items = append(items, ValueReference[string]{ + Value: sliceItem.Value, + ValueNode: sliceItem, + }) + } + n := NodeReference[[]ValueReference[string]]{ + Value: items, + KeyNode: keyNode, + ValueNode: valueNode, + } + field.Set(reflect.ValueOf(n)) + } + } + + case reflect.TypeOf(NodeReference[[]ValueReference[any]]{}): + + if utils.IsNodeArray(valueNode) { + if field.CanSet() { + var items []ValueReference[any] + for _, sliceItem := range valueNode.Content { + + var val any + if utils.IsNodeIntValue(sliceItem) || utils.IsNodeFloatValue(sliceItem) { + if utils.IsNodeIntValue(sliceItem) { + val, _ = strconv.ParseInt(sliceItem.Value, 10, 64) + } else { + val, _ = strconv.ParseFloat(sliceItem.Value, 64) + } + } + if utils.IsNodeBoolValue(sliceItem) { + val, _ = strconv.ParseBool(sliceItem.Value) + } + if utils.IsNodeStringValue(sliceItem) { + val = sliceItem.Value + } + + items = append(items, ValueReference[any]{ + Value: val, + ValueNode: sliceItem, + }) + } + n := NodeReference[[]ValueReference[any]]{ + Value: items, + KeyNode: keyNode, + ValueNode: valueNode, + } + field.Set(reflect.ValueOf(n)) + } + } + + default: + // we want to ignore everything else, each model handles its own complex types. + break + } + return nil +} + +// BuildModelAsync is a convenience function for calling BuildModel from a goroutine, requires a sync.WaitGroup +func BuildModelAsync(n *yaml.Node, model interface{}, lwg *sync.WaitGroup, errors *[]error) { + if n != nil { + err := BuildModel(n, model) + if err != nil { + *errors = append(*errors, err) + } + } + lwg.Done() +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/low/model_interfaces.go b/vendor/github.com/pb33f/libopenapi/datamodel/low/model_interfaces.go new file mode 100644 index 0000000000..e2f8296963 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/low/model_interfaces.go @@ -0,0 +1,124 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package low + +type SharedParameters interface { + HasDescription + Hash() [32]byte + GetName() *NodeReference[string] + GetIn() *NodeReference[string] + GetAllowEmptyValue() *NodeReference[bool] + GetRequired() *NodeReference[bool] + GetSchema() *NodeReference[any] // requires cast. +} + +type HasExternalDocs interface { + GetExternalDocs() *NodeReference[any] +} + +type HasDescription interface { + GetDescription() *NodeReference[string] +} + +type HasInfo interface { + GetInfo() *NodeReference[any] +} + +type SwaggerParameter interface { + SharedParameters + GetType() *NodeReference[string] + GetFormat() *NodeReference[string] + GetCollectionFormat() *NodeReference[string] + GetDefault() *NodeReference[any] + GetMaximum() *NodeReference[int] + GetExclusiveMaximum() *NodeReference[bool] + GetMinimum() *NodeReference[int] + GetExclusiveMinimum() *NodeReference[bool] + GetMaxLength() *NodeReference[int] + GetMinLength() *NodeReference[int] + GetPattern() *NodeReference[string] + GetMaxItems() *NodeReference[int] + GetMinItems() *NodeReference[int] + GetUniqueItems() *NodeReference[bool] + GetEnum() *NodeReference[[]ValueReference[any]] + GetMultipleOf() *NodeReference[int] +} + +type SwaggerHeader interface { + HasDescription + Hash() [32]byte + GetType() *NodeReference[string] + GetFormat() *NodeReference[string] + GetCollectionFormat() *NodeReference[string] + GetDefault() *NodeReference[any] + GetMaximum() *NodeReference[int] + GetExclusiveMaximum() *NodeReference[bool] + GetMinimum() *NodeReference[int] + GetExclusiveMinimum() *NodeReference[bool] + GetMaxLength() *NodeReference[int] + GetMinLength() *NodeReference[int] + GetPattern() *NodeReference[string] + GetMaxItems() *NodeReference[int] + GetMinItems() *NodeReference[int] + GetUniqueItems() *NodeReference[bool] + GetEnum() *NodeReference[[]ValueReference[any]] + GetMultipleOf() *NodeReference[int] + GetItems() *NodeReference[any] // requires cast. +} + +type OpenAPIHeader interface { + HasDescription + Hash() [32]byte + GetDeprecated() *NodeReference[bool] + GetStyle() *NodeReference[string] + GetAllowReserved() *NodeReference[bool] + GetExplode() *NodeReference[bool] + GetExample() *NodeReference[any] + GetRequired() *NodeReference[bool] + GetAllowEmptyValue() *NodeReference[bool] + GetSchema() *NodeReference[any] // requires cast. + GetExamples() *NodeReference[any] // requires cast. + GetContent() *NodeReference[any] // requires cast. +} + +type OpenAPIParameter interface { + SharedParameters + GetDeprecated() *NodeReference[bool] + GetStyle() *NodeReference[string] + GetAllowReserved() *NodeReference[bool] + GetExplode() *NodeReference[bool] + GetExample() *NodeReference[any] + GetExamples() *NodeReference[any] // requires cast. + GetContent() *NodeReference[any] // requires cast. +} + +//TODO: this needs to be fixed, move returns to pointers. + +type SharedOperations interface { + //HasDescription + //HasExternalDocs + GetOperationId() NodeReference[string] + GetExternalDocs() NodeReference[any] + GetDescription() NodeReference[string] + GetTags() NodeReference[[]ValueReference[string]] + GetSummary() NodeReference[string] + GetDeprecated() NodeReference[bool] + GetExtensions() map[KeyReference[string]]ValueReference[any] + GetResponses() NodeReference[any] // requires cast. + GetParameters() NodeReference[any] // requires cast. + GetSecurity() NodeReference[any] // requires cast. +} + +type SwaggerOperations interface { + SharedOperations + GetConsumes() NodeReference[[]ValueReference[string]] + GetProduces() NodeReference[[]ValueReference[string]] + GetSchemes() NodeReference[[]ValueReference[string]] +} + +type OpenAPIOperations interface { + SharedOperations + GetCallbacks() NodeReference[map[KeyReference[string]]ValueReference[any]] // requires cast + GetServers() NodeReference[any] // requires cast. +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/low/reference.go b/vendor/github.com/pb33f/libopenapi/datamodel/low/reference.go new file mode 100644 index 0000000000..30b75d8046 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/low/reference.go @@ -0,0 +1,375 @@ +package low + +import ( + "fmt" + "github.com/pb33f/libopenapi/index" + "github.com/pb33f/libopenapi/utils" + "gopkg.in/yaml.v3" +) + +const ( + HASH = "%x" +) + +type Reference struct { + Reference string `json:"-" yaml:"-"` +} + +func (r *Reference) GetReference() string { + return r.Reference +} + +func (r *Reference) IsReference() bool { + return r.Reference != "" +} + +func (r *Reference) SetReference(ref string) { + r.Reference = ref +} + +type IsReferenced interface { + IsReference() bool + GetReference() string + SetReference(string) +} + +// Buildable is an interface for any struct that can be 'built out'. This means that a struct can accept +// a root node and a reference to the index that carries data about any references used. +// +// Used by generic functions when automatically building out structs based on yaml.Node inputs. +type Buildable[T any] interface { + Build(node *yaml.Node, idx *index.SpecIndex) error + *T +} + +// HasValueNode is implemented by NodeReference and ValueReference to return the yaml.Node backing the value. +type HasValueNode[T any] interface { + GetValueNode() *yaml.Node + *T +} + +// HasValueNodeUntyped is implemented by NodeReference and ValueReference to return the yaml.Node backing the value. +type HasValueNodeUntyped interface { + GetValueNode() *yaml.Node + IsReferenced +} + +// Hashable defines any struct that implements a Hash function that returns a 256SHA hash of the state of the +// representative object. Great for equality checking! +type Hashable interface { + Hash() [32]byte +} + +// HasExtensions is implemented by any object that exposes extensions +type HasExtensions[T any] interface { + + // GetExtensions returns generic low level extensions + GetExtensions() map[KeyReference[string]]ValueReference[any] +} + +// HasExtensionsUntyped is implemented by any object that exposes extensions +type HasExtensionsUntyped interface { + + // GetExtensions returns generic low level extensions + GetExtensions() map[KeyReference[string]]ValueReference[any] +} + +// HasValue is implemented by NodeReference and ValueReference to return the yaml.Node backing the value. +type HasValue[T any] interface { + GetValue() T + GetValueNode() *yaml.Node + IsEmpty() bool + *T +} + +// HasValueUnTyped is implemented by NodeReference and ValueReference to return the yaml.Node backing the value. +type HasValueUnTyped interface { + GetValueUntyped() any + GetValueNode() *yaml.Node +} + +// HasKeyNode is implemented by KeyReference to return the yaml.Node backing the key. +type HasKeyNode interface { + GetKeyNode() *yaml.Node +} + +// NodeReference is a low-level container for holding a Value of type T, as well as references to +// a key yaml.Node that points to the key node that contains the value node, and the value node that contains +// the actual value. +type NodeReference[T any] struct { + + // The value being referenced + Value T + + // The yaml.Node that holds the value + ValueNode *yaml.Node + + // The yaml.Node that is the key, that contains the value. + KeyNode *yaml.Node + + // Is this value actually a reference in the original tree? + ReferenceNode bool + + // If HasReference is true, then Reference contains the original $ref value. + Reference string +} + +// KeyReference is a low-level container for key nodes holding a Value of type T. A KeyNode is a pointer to the +// yaml.Node that holds a key to a value. +type KeyReference[T any] struct { + + // The value being referenced. + Value T + + // The yaml.Node that holds this referenced key + KeyNode *yaml.Node +} + +// ValueReference is a low-level container for value nodes that hold a Value of type T. A ValueNode is a pointer +// to the yaml.Node that holds the value. +type ValueReference[T any] struct { + + // The value being referenced. + Value T + + // The yaml.Node that holds the referenced value + ValueNode *yaml.Node + + // Is this value actually a reference in the original tree? + ReferenceNode bool + + // If HasReference is true, then Reference contains the original $ref value. + Reference string +} + +// IsEmpty will return true if this reference has no key or value nodes assigned (it's been ignored) +func (n NodeReference[T]) IsEmpty() bool { + return n.KeyNode == nil && n.ValueNode == nil +} + +func (n NodeReference[T]) NodeLineNumber() int { + if !n.IsEmpty() { + return n.ValueNode.Line + } else { + return 0 + } +} + +func (n NodeReference[T]) GetReference() string { + return n.Reference +} + +func (n NodeReference[T]) SetReference(ref string) { + n.Reference = ref +} + +// IsReference will return true if the key node contains a $ref key. +func (n NodeReference[T]) IsReference() bool { + if n.ReferenceNode { + return true + } + if n.KeyNode != nil { + for k := range n.KeyNode.Content { + if k%2 == 0 { + if n.KeyNode.Content[k].Value == "$ref" { + n.ReferenceNode = true + return true + } + } + } + } + return false +} + +// GenerateMapKey will return a string based on the line and column number of the node, e.g. 33:56 for line 33, col 56. +func (n NodeReference[T]) GenerateMapKey() string { + return fmt.Sprintf("%d:%d", n.ValueNode.Line, n.ValueNode.Column) +} + +// Mutate will set the reference value to what is supplied. This happens to both the Value and ValueNode, which means +// the root document is permanently mutated and changes will be reflected in any serialization of the root document. +func (n NodeReference[T]) Mutate(value T) NodeReference[T] { + n.ValueNode.Value = fmt.Sprintf("%v", value) + n.Value = value + return n +} + +// GetValueNode will return the yaml.Node containing the reference value node +func (n NodeReference[T]) GetValueNode() *yaml.Node { + return n.ValueNode +} + +// GetKeyNode will return the yaml.Node containing the reference key node +func (n NodeReference[T]) GetKeyNode() *yaml.Node { + return n.KeyNode +} + +// GetValue will return the raw value of the node +func (n NodeReference[T]) GetValue() T { + return n.Value +} + +// GetValueUntyped will return the raw value of the node with no type +func (n NodeReference[T]) GetValueUntyped() any { + return n.Value +} + +// IsEmpty will return true if this reference has no key or value nodes assigned (it's been ignored) +func (n ValueReference[T]) IsEmpty() bool { + return n.ValueNode == nil +} + +// NodeLineNumber will return the line number of the value node (or 0 if the value node is empty) +func (n ValueReference[T]) NodeLineNumber() int { + if !n.IsEmpty() { + return n.ValueNode.Line + } else { + return 0 + } +} + +// GenerateMapKey will return a string based on the line and column number of the node, e.g. 33:56 for line 33, col 56. +func (n ValueReference[T]) GenerateMapKey() string { + return fmt.Sprintf("%d:%d", n.ValueNode.Line, n.ValueNode.Column) +} + +// GetValueNode will return the yaml.Node containing the reference value node +func (n ValueReference[T]) GetValueNode() *yaml.Node { + return n.ValueNode +} + +// GetValue will return the raw value of the node +func (n ValueReference[T]) GetValue() T { + return n.Value +} + +// GetValueUntyped will return the raw value of the node with no type +func (n ValueReference[T]) GetValueUntyped() any { + return n.Value +} + +func (n ValueReference[T]) GetReference() string { + return n.Reference +} + +func (n ValueReference[T]) SetReference(ref string) { + n.Reference = ref +} + +// IsReference will return true if the key node contains a $ref +func (n ValueReference[T]) IsReference() bool { + if n.Reference != "" { + return true + } + return false +} + +func (n ValueReference[T]) MarshalYAML() (interface{}, error) { + if n.IsReference() { + nodes := make([]*yaml.Node, 2) + nodes[0] = utils.CreateStringNode("$ref") + nodes[1] = utils.CreateStringNode(n.Reference) + m := utils.CreateEmptyMapNode() + m.Content = nodes + return m, nil + } + var h yaml.Node + e := n.ValueNode.Decode(&h) + return h, e +} + +// IsEmpty will return true if this reference has no key or value nodes assigned (it's been ignored) +func (n KeyReference[T]) IsEmpty() bool { + return n.KeyNode == nil +} + +// GetValueUntyped will return the raw value of the node with no type +func (n KeyReference[T]) GetValueUntyped() any { + return n.Value +} + +// GetKeyNode will return the yaml.Node containing the reference key node. +func (n KeyReference[T]) GetKeyNode() *yaml.Node { + return n.KeyNode +} + +// GenerateMapKey will return a string based on the line and column number of the node, e.g. 33:56 for line 33, col 56. +func (n KeyReference[T]) GenerateMapKey() string { + return fmt.Sprintf("%d:%d", n.KeyNode.Line, n.KeyNode.Column) +} + +// Mutate will set the reference value to what is supplied. This happens to both the Value and ValueNode, which means +// the root document is permanently mutated and changes will be reflected in any serialization of the root document. +func (n ValueReference[T]) Mutate(value T) ValueReference[T] { + n.ValueNode.Value = fmt.Sprintf("%v", value) + n.Value = value + return n +} + +// IsCircular will determine if the node in question, is part of a circular reference chain discovered by the index. +func IsCircular(node *yaml.Node, idx *index.SpecIndex) bool { + if idx == nil { + return false // no index! nothing we can do. + } + refs := idx.GetCircularReferences() + for i := range idx.GetCircularReferences() { + if refs[i].LoopPoint.Node == node { + return true + } + for k := range refs[i].Journey { + if refs[i].Journey[k].Node == node { + return true + } + isRef, _, refValue := utils.IsNodeRefValue(node) + if isRef && refs[i].Journey[k].Definition == refValue { + return true + } + } + } + // check mapped references in case we didn't find it. + _, nv := utils.FindKeyNode("$ref", node.Content) + if nv != nil { + ref := idx.GetMappedReferences()[nv.Value] + if ref != nil { + return ref.Circular + } + } + return false +} + +// GetCircularReferenceResult will check if a node is part of a circular reference chain and then return that +// index.CircularReferenceResult it was located in. Returns nil if not found. +func GetCircularReferenceResult(node *yaml.Node, idx *index.SpecIndex) *index.CircularReferenceResult { + if idx == nil { + return nil // no index! nothing we can do. + } + refs := idx.GetCircularReferences() + for i := range refs { + if refs[i].LoopPoint.Node == node { + return refs[i] + } + for k := range refs[i].Journey { + if refs[i].Journey[k].Node == node { + return refs[i] + } + isRef, _, refValue := utils.IsNodeRefValue(node) + if isRef && refs[i].Journey[k].Definition == refValue { + return refs[i] + } + } + } + // check mapped references in case we didn't find it. + _, nv := utils.FindKeyNode("$ref", node.Content) + if nv != nil { + for i := range refs { + if refs[i].LoopPoint.Definition == nv.Value { + return refs[i] + } + } + } + return nil +} + +func HashToString(hash [32]byte) string { + return fmt.Sprintf("%x", hash) +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/low/serializing.go b/vendor/github.com/pb33f/libopenapi/datamodel/low/serializing.go new file mode 100644 index 0000000000..e58d4df651 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/low/serializing.go @@ -0,0 +1,4 @@ +// Copyright 2023 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package low diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/low/v2/constants.go b/vendor/github.com/pb33f/libopenapi/datamodel/low/v2/constants.go new file mode 100644 index 0000000000..45e373775f --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/low/v2/constants.go @@ -0,0 +1,25 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package v2 + +const ( + DefinitionsLabel = "definitions" + SecurityDefinitionsLabel = "securityDefinitions" + ExamplesLabel = "examples" + HeadersLabel = "headers" + DefaultLabel = "default" + ItemsLabel = "items" + ParametersLabel = "parameters" + PathsLabel = "paths" + GetLabel = "get" + PostLabel = "post" + PatchLabel = "patch" + PutLabel = "put" + DeleteLabel = "delete" + OptionsLabel = "options" + HeadLabel = "head" + SecurityLabel = "security" + ScopesLabel = "scopes" + ResponsesLabel = "responses" +) diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/low/v2/definitions.go b/vendor/github.com/pb33f/libopenapi/datamodel/low/v2/definitions.go new file mode 100644 index 0000000000..226a9c41f0 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/low/v2/definitions.go @@ -0,0 +1,266 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package v2 + +import ( + "crypto/sha256" + "github.com/pb33f/libopenapi/datamodel/low" + "github.com/pb33f/libopenapi/datamodel/low/base" + "github.com/pb33f/libopenapi/index" + "gopkg.in/yaml.v3" + "sort" + "strings" +) + +// ParameterDefinitions is a low-level representation of a Swagger / OpenAPI 2 Parameters Definitions object. +// +// ParameterDefinitions holds parameters to be reused across operations. Parameter definitions can be +// referenced to the ones defined here. It does not define global operation parameters +// - https://swagger.io/specification/v2/#parametersDefinitionsObject +type ParameterDefinitions struct { + Definitions map[low.KeyReference[string]]low.ValueReference[*Parameter] +} + +// ResponsesDefinitions is a low-level representation of a Swagger / OpenAPI 2 Responses Definitions object. +// +// ResponsesDefinitions is an object to hold responses to be reused across operations. Response definitions can be +// referenced to the ones defined here. It does not define global operation responses +// - https://swagger.io/specification/v2/#responsesDefinitionsObject +type ResponsesDefinitions struct { + Definitions map[low.KeyReference[string]]low.ValueReference[*Response] +} + +// SecurityDefinitions is a low-level representation of a Swagger / OpenAPI 2 Security Definitions object. +// +// A declaration of the security schemes available to be used in the specification. This does not enforce the security +// schemes on the operations and only serves to provide the relevant details for each scheme +// - https://swagger.io/specification/v2/#securityDefinitionsObject +type SecurityDefinitions struct { + Definitions map[low.KeyReference[string]]low.ValueReference[*SecurityScheme] +} + +// Definitions is a low-level representation of a Swagger / OpenAPI 2 Definitions object +// +// An object to hold data types that can be consumed and produced by operations. These data types can be primitives, +// arrays or models. +// - https://swagger.io/specification/v2/#definitionsObject +type Definitions struct { + Schemas map[low.KeyReference[string]]low.ValueReference[*base.SchemaProxy] +} + +// FindSchema will attempt to locate a base.SchemaProxy instance using a name. +func (d *Definitions) FindSchema(schema string) *low.ValueReference[*base.SchemaProxy] { + return low.FindItemInMap[*base.SchemaProxy](schema, d.Schemas) +} + +// FindParameter will attempt to locate a Parameter instance using a name. +func (pd *ParameterDefinitions) FindParameter(parameter string) *low.ValueReference[*Parameter] { + return low.FindItemInMap[*Parameter](parameter, pd.Definitions) +} + +// FindResponse will attempt to locate a Response instance using a name. +func (r *ResponsesDefinitions) FindResponse(response string) *low.ValueReference[*Response] { + return low.FindItemInMap[*Response](response, r.Definitions) +} + +// FindSecurityDefinition will attempt to locate a SecurityScheme using a name. +func (s *SecurityDefinitions) FindSecurityDefinition(securityDef string) *low.ValueReference[*SecurityScheme] { + return low.FindItemInMap[*SecurityScheme](securityDef, s.Definitions) +} + +// Build will extract all definitions into SchemaProxy instances. +func (d *Definitions) Build(root *yaml.Node, idx *index.SpecIndex) error { + errorChan := make(chan error) + resultChan := make(chan definitionResult[*base.SchemaProxy]) + var defLabel *yaml.Node + totalDefinitions := 0 + for i := range root.Content { + if i%2 == 0 { + defLabel = root.Content[i] + continue + } + totalDefinitions++ + var buildFunc = func(label *yaml.Node, value *yaml.Node, idx *index.SpecIndex, + r chan definitionResult[*base.SchemaProxy], e chan error) { + + obj, err, _, rv := low.ExtractObjectRaw[*base.SchemaProxy](value, idx) + if err != nil { + e <- err + } + r <- definitionResult[*base.SchemaProxy]{k: label, v: low.ValueReference[*base.SchemaProxy]{ + Value: obj, ValueNode: value, Reference: rv, + }} + } + go buildFunc(defLabel, root.Content[i], idx, resultChan, errorChan) + } + + completedDefs := 0 + results := make(map[low.KeyReference[string]]low.ValueReference[*base.SchemaProxy]) + for completedDefs < totalDefinitions { + select { + case err := <-errorChan: + return err + case sch := <-resultChan: + completedDefs++ + results[low.KeyReference[string]{ + Value: sch.k.Value, + KeyNode: sch.k, + }] = sch.v + } + } + d.Schemas = results + return nil +} + +// Hash will return a consistent SHA256 Hash of the Definitions object +func (d *Definitions) Hash() [32]byte { + var f []string + keys := make([]string, len(d.Schemas)) + z := 0 + for k := range d.Schemas { + keys[z] = k.Value + z++ + } + sort.Strings(keys) + for k := range keys { + f = append(f, low.GenerateHashString(d.FindSchema(keys[k]).Value)) + } + return sha256.Sum256([]byte(strings.Join(f, "|"))) +} + +// Build will extract all ParameterDefinitions into Parameter instances. +func (pd *ParameterDefinitions) Build(root *yaml.Node, idx *index.SpecIndex) error { + errorChan := make(chan error) + resultChan := make(chan definitionResult[*Parameter]) + var defLabel *yaml.Node + totalDefinitions := 0 + for i := range root.Content { + if i%2 == 0 { + defLabel = root.Content[i] + continue + } + totalDefinitions++ + var buildFunc = func(label *yaml.Node, value *yaml.Node, idx *index.SpecIndex, + r chan definitionResult[*Parameter], e chan error) { + + obj, err, _, rv := low.ExtractObjectRaw[*Parameter](value, idx) + if err != nil { + e <- err + } + r <- definitionResult[*Parameter]{k: label, v: low.ValueReference[*Parameter]{Value: obj, + ValueNode: value, Reference: rv}} + } + go buildFunc(defLabel, root.Content[i], idx, resultChan, errorChan) + } + + completedDefs := 0 + results := make(map[low.KeyReference[string]]low.ValueReference[*Parameter]) + for completedDefs < totalDefinitions { + select { + case err := <-errorChan: + return err + case sch := <-resultChan: + completedDefs++ + results[low.KeyReference[string]{ + Value: sch.k.Value, + KeyNode: sch.k, + }] = sch.v + } + } + pd.Definitions = results + return nil +} + +// re-usable struct for holding results as k/v pairs. +type definitionResult[T any] struct { + k *yaml.Node + v low.ValueReference[T] +} + +// Build will extract all ResponsesDefinitions into Response instances. +func (r *ResponsesDefinitions) Build(root *yaml.Node, idx *index.SpecIndex) error { + errorChan := make(chan error) + resultChan := make(chan definitionResult[*Response]) + var defLabel *yaml.Node + totalDefinitions := 0 + for i := range root.Content { + if i%2 == 0 { + defLabel = root.Content[i] + continue + } + totalDefinitions++ + var buildFunc = func(label *yaml.Node, value *yaml.Node, idx *index.SpecIndex, + r chan definitionResult[*Response], e chan error) { + + obj, err, _, rv := low.ExtractObjectRaw[*Response](value, idx) + if err != nil { + e <- err + } + r <- definitionResult[*Response]{k: label, v: low.ValueReference[*Response]{Value: obj, + ValueNode: value, Reference: rv}} + } + go buildFunc(defLabel, root.Content[i], idx, resultChan, errorChan) + } + + completedDefs := 0 + results := make(map[low.KeyReference[string]]low.ValueReference[*Response]) + for completedDefs < totalDefinitions { + select { + case err := <-errorChan: + return err + case sch := <-resultChan: + completedDefs++ + results[low.KeyReference[string]{ + Value: sch.k.Value, + KeyNode: sch.k, + }] = sch.v + } + } + r.Definitions = results + return nil +} + +// Build will extract all SecurityDefinitions into SecurityScheme instances. +func (s *SecurityDefinitions) Build(root *yaml.Node, idx *index.SpecIndex) error { + errorChan := make(chan error) + resultChan := make(chan definitionResult[*SecurityScheme]) + var defLabel *yaml.Node + totalDefinitions := 0 + for i := range root.Content { + if i%2 == 0 { + defLabel = root.Content[i] + continue + } + totalDefinitions++ + var buildFunc = func(label *yaml.Node, value *yaml.Node, idx *index.SpecIndex, + r chan definitionResult[*SecurityScheme], e chan error) { + + obj, err, _, rv := low.ExtractObjectRaw[*SecurityScheme](value, idx) + if err != nil { + e <- err + } + r <- definitionResult[*SecurityScheme]{k: label, v: low.ValueReference[*SecurityScheme]{ + Value: obj, ValueNode: value, Reference: rv, + }} + } + go buildFunc(defLabel, root.Content[i], idx, resultChan, errorChan) + } + + completedDefs := 0 + results := make(map[low.KeyReference[string]]low.ValueReference[*SecurityScheme]) + for completedDefs < totalDefinitions { + select { + case err := <-errorChan: + return err + case sch := <-resultChan: + completedDefs++ + results[low.KeyReference[string]{ + Value: sch.k.Value, + KeyNode: sch.k, + }] = sch.v + } + } + s.Definitions = results + return nil +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/low/v2/examples.go b/vendor/github.com/pb33f/libopenapi/datamodel/low/v2/examples.go new file mode 100644 index 0000000000..03a63e6656 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/low/v2/examples.go @@ -0,0 +1,92 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package v2 + +import ( + "crypto/sha256" + "fmt" + "github.com/pb33f/libopenapi/datamodel/low" + "github.com/pb33f/libopenapi/index" + "gopkg.in/yaml.v3" + "sort" + "strings" +) + +// Examples represents a low-level Swagger / OpenAPI 2 Example object. +// Allows sharing examples for operation responses +// - https://swagger.io/specification/v2/#exampleObject +type Examples struct { + Values map[low.KeyReference[string]]low.ValueReference[any] +} + +// FindExample attempts to locate an example value, using a key label. +func (e *Examples) FindExample(name string) *low.ValueReference[any] { + return low.FindItemInMap[any](name, e.Values) +} + +// Build will extract all examples and will attempt to unmarshal content into a map or slice based on type. +func (e *Examples) Build(root *yaml.Node, _ *index.SpecIndex) error { + var keyNode, currNode *yaml.Node + var err error + e.Values = make(map[low.KeyReference[string]]low.ValueReference[any]) + for i := range root.Content { + if i%2 == 0 { + keyNode = root.Content[i] + continue + } + currNode = root.Content[i] + var n map[string]interface{} + err = currNode.Decode(&n) + if err != nil { + var k []interface{} + err = currNode.Decode(&k) + if err != nil { + // lets just default to interface + var j interface{} + _ = currNode.Decode(&j) + e.Values[low.KeyReference[string]{ + Value: keyNode.Value, + KeyNode: keyNode, + }] = low.ValueReference[any]{ + Value: j, + ValueNode: currNode, + } + continue + } + e.Values[low.KeyReference[string]{ + Value: keyNode.Value, + KeyNode: keyNode, + }] = low.ValueReference[any]{ + Value: k, + ValueNode: currNode, + } + continue + } + e.Values[low.KeyReference[string]{ + Value: keyNode.Value, + KeyNode: keyNode, + }] = low.ValueReference[any]{ + Value: n, + ValueNode: currNode, + } + + } + return nil +} + +// Hash will return a consistent SHA256 Hash of the Examples object +func (e *Examples) Hash() [32]byte { + var f []string + keys := make([]string, len(e.Values)) + z := 0 + for k := range e.Values { + keys[z] = k.Value + z++ + } + sort.Strings(keys) + for k := range keys { + f = append(f, fmt.Sprintf("%v", e.FindExample(keys[k]).Value)) + } + return sha256.Sum256([]byte(strings.Join(f, "|"))) +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/low/v2/header.go b/vendor/github.com/pb33f/libopenapi/datamodel/low/v2/header.go new file mode 100644 index 0000000000..e58c4f8668 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/low/v2/header.go @@ -0,0 +1,213 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package v2 + +import ( + "crypto/sha256" + "fmt" + "github.com/pb33f/libopenapi/datamodel/low" + "github.com/pb33f/libopenapi/index" + "github.com/pb33f/libopenapi/utils" + "gopkg.in/yaml.v3" + "sort" + "strings" +) + +// Header Represents a low-level Swagger / OpenAPI 2 Header object. +// +// A Header is essentially identical to a Parameter, except it does not contain 'name' or 'in' properties. +// - https://swagger.io/specification/v2/#headerObject +type Header struct { + Type low.NodeReference[string] + Format low.NodeReference[string] + Description low.NodeReference[string] + Items low.NodeReference[*Items] + CollectionFormat low.NodeReference[string] + Default low.NodeReference[any] + Maximum low.NodeReference[int] + ExclusiveMaximum low.NodeReference[bool] + Minimum low.NodeReference[int] + ExclusiveMinimum low.NodeReference[bool] + MaxLength low.NodeReference[int] + MinLength low.NodeReference[int] + Pattern low.NodeReference[string] + MaxItems low.NodeReference[int] + MinItems low.NodeReference[int] + UniqueItems low.NodeReference[bool] + Enum low.NodeReference[[]low.ValueReference[any]] + MultipleOf low.NodeReference[int] + Extensions map[low.KeyReference[string]]low.ValueReference[any] +} + +// FindExtension will attempt to locate an extension value using a name lookup. +func (h *Header) FindExtension(ext string) *low.ValueReference[any] { + return low.FindItemInMap[any](ext, h.Extensions) +} + +// GetExtensions returns all Header extensions and satisfies the low.HasExtensions interface. +func (h *Header) GetExtensions() map[low.KeyReference[string]]low.ValueReference[any] { + return h.Extensions +} + +// Build will build out items, extensions and default value from the supplied node. +func (h *Header) Build(root *yaml.Node, idx *index.SpecIndex) error { + h.Extensions = low.ExtractExtensions(root) + items, err := low.ExtractObject[*Items](ItemsLabel, root, idx) + if err != nil { + return err + } + h.Items = items + + _, ln, vn := utils.FindKeyNodeFull(DefaultLabel, root.Content) + if vn != nil { + var n map[string]interface{} + err = vn.Decode(&n) + if err != nil { + // if not a map, then try an array + var k []interface{} + err = vn.Decode(&k) + if err != nil { + // lets just default to interface + var j interface{} + _ = vn.Decode(&j) + h.Default = low.NodeReference[any]{ + Value: j, + KeyNode: ln, + ValueNode: vn, + } + return nil + } + h.Default = low.NodeReference[any]{ + Value: k, + KeyNode: ln, + ValueNode: vn, + } + return nil + } + h.Default = low.NodeReference[any]{ + Value: n, + KeyNode: ln, + ValueNode: vn, + } + return nil + } + return nil +} + +// Hash will return a consistent SHA256 Hash of the Header object +func (h *Header) Hash() [32]byte { + var f []string + if h.Description.Value != "" { + f = append(f, h.Description.Value) + } + if h.Type.Value != "" { + f = append(f, h.Type.Value) + } + if h.Format.Value != "" { + f = append(f, h.Format.Value) + } + if h.CollectionFormat.Value != "" { + f = append(f, h.CollectionFormat.Value) + } + if h.Default.Value != "" { + f = append(f, fmt.Sprintf("%x", sha256.Sum256([]byte(fmt.Sprint(h.Default.Value))))) + } + f = append(f, fmt.Sprint(h.Maximum.Value)) + f = append(f, fmt.Sprint(h.Minimum.Value)) + f = append(f, fmt.Sprint(h.ExclusiveMinimum.Value)) + f = append(f, fmt.Sprint(h.ExclusiveMaximum.Value)) + f = append(f, fmt.Sprint(h.MinLength.Value)) + f = append(f, fmt.Sprint(h.MaxLength.Value)) + f = append(f, fmt.Sprint(h.MinItems.Value)) + f = append(f, fmt.Sprint(h.MaxItems.Value)) + f = append(f, fmt.Sprint(h.MultipleOf.Value)) + f = append(f, fmt.Sprint(h.UniqueItems.Value)) + if h.Pattern.Value != "" { + f = append(f, fmt.Sprintf("%x", sha256.Sum256([]byte(fmt.Sprint(h.Pattern.Value))))) + } + + keys := make([]string, len(h.Extensions)) + z := 0 + for k := range h.Extensions { + keys[z] = fmt.Sprintf("%s-%x", k.Value, sha256.Sum256([]byte(fmt.Sprint(h.Extensions[k].Value)))) + z++ + } + sort.Strings(keys) + f = append(f, keys...) + + keys = make([]string, len(h.Enum.Value)) + z = 0 + for k := range h.Enum.Value { + keys[z] = fmt.Sprint(h.Enum.Value[k].Value) + z++ + } + sort.Strings(keys) + f = append(f, keys...) + if h.Items.Value != nil { + f = append(f, low.GenerateHashString(h.Items.Value)) + } + return sha256.Sum256([]byte(strings.Join(f, "|"))) +} + +// Getter methods to satisfy SwaggerHeader interface. + +func (h *Header) GetType() *low.NodeReference[string] { + return &h.Type +} +func (h *Header) GetDescription() *low.NodeReference[string] { + return &h.Description +} +func (h *Header) GetFormat() *low.NodeReference[string] { + return &h.Format +} +func (h *Header) GetItems() *low.NodeReference[any] { + i := low.NodeReference[any]{ + KeyNode: h.Items.KeyNode, + ValueNode: h.Items.ValueNode, + Value: h.Items.Value, + } + return &i +} +func (h *Header) GetCollectionFormat() *low.NodeReference[string] { + return &h.CollectionFormat +} +func (h *Header) GetDefault() *low.NodeReference[any] { + return &h.Default +} +func (h *Header) GetMaximum() *low.NodeReference[int] { + return &h.Maximum +} +func (h *Header) GetExclusiveMaximum() *low.NodeReference[bool] { + return &h.ExclusiveMaximum +} +func (h *Header) GetMinimum() *low.NodeReference[int] { + return &h.Minimum +} +func (h *Header) GetExclusiveMinimum() *low.NodeReference[bool] { + return &h.ExclusiveMinimum +} +func (h *Header) GetMaxLength() *low.NodeReference[int] { + return &h.MaxLength +} +func (h *Header) GetMinLength() *low.NodeReference[int] { + return &h.MinLength +} +func (h *Header) GetPattern() *low.NodeReference[string] { + return &h.Pattern +} +func (h *Header) GetMaxItems() *low.NodeReference[int] { + return &h.MaxItems +} +func (h *Header) GetMinItems() *low.NodeReference[int] { + return &h.MinItems +} +func (h *Header) GetUniqueItems() *low.NodeReference[bool] { + return &h.UniqueItems +} +func (h *Header) GetEnum() *low.NodeReference[[]low.ValueReference[any]] { + return &h.Enum +} +func (h *Header) GetMultipleOf() *low.NodeReference[int] { + return &h.MultipleOf +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/low/v2/items.go b/vendor/github.com/pb33f/libopenapi/datamodel/low/v2/items.go new file mode 100644 index 0000000000..307afa0d93 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/low/v2/items.go @@ -0,0 +1,209 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package v2 + +import ( + "crypto/sha256" + "fmt" + "github.com/pb33f/libopenapi/datamodel/low" + "github.com/pb33f/libopenapi/index" + "github.com/pb33f/libopenapi/utils" + "gopkg.in/yaml.v3" + "sort" + "strings" +) + +// Items is a low-level representation of a Swagger / OpenAPI 2 Items object. +// +// Items is a limited subset of JSON-Schema's items object. It is used by parameter definitions that are not +// located in "body". Items, is actually identical to a Header, except it does not have description. +// - https://swagger.io/specification/v2/#itemsObject +type Items struct { + Type low.NodeReference[string] + Format low.NodeReference[string] + CollectionFormat low.NodeReference[string] + Items low.NodeReference[*Items] + Default low.NodeReference[any] + Maximum low.NodeReference[int] + ExclusiveMaximum low.NodeReference[bool] + Minimum low.NodeReference[int] + ExclusiveMinimum low.NodeReference[bool] + MaxLength low.NodeReference[int] + MinLength low.NodeReference[int] + Pattern low.NodeReference[string] + MaxItems low.NodeReference[int] + MinItems low.NodeReference[int] + UniqueItems low.NodeReference[bool] + Enum low.NodeReference[[]low.ValueReference[any]] + MultipleOf low.NodeReference[int] + Extensions map[low.KeyReference[string]]low.ValueReference[any] +} + +// FindExtension will attempt to locate an extension value using a name lookup. +func (i *Items) FindExtension(ext string) *low.ValueReference[any] { + return low.FindItemInMap[any](ext, i.Extensions) +} + +// GetExtensions returns all Items extensions and satisfies the low.HasExtensions interface. +func (i *Items) GetExtensions() map[low.KeyReference[string]]low.ValueReference[any] { + return i.Extensions +} + +// Hash will return a consistent SHA256 Hash of the Items object +func (i *Items) Hash() [32]byte { + var f []string + if i.Type.Value != "" { + f = append(f, i.Type.Value) + } + if i.Format.Value != "" { + f = append(f, i.Format.Value) + } + if i.CollectionFormat.Value != "" { + f = append(f, i.CollectionFormat.Value) + } + if i.Default.Value != "" { + f = append(f, fmt.Sprintf("%x", sha256.Sum256([]byte(fmt.Sprint(i.Default.Value))))) + } + f = append(f, fmt.Sprint(i.Maximum.Value)) + f = append(f, fmt.Sprint(i.Minimum.Value)) + f = append(f, fmt.Sprint(i.ExclusiveMinimum.Value)) + f = append(f, fmt.Sprint(i.ExclusiveMaximum.Value)) + f = append(f, fmt.Sprint(i.MinLength.Value)) + f = append(f, fmt.Sprint(i.MaxLength.Value)) + f = append(f, fmt.Sprint(i.MinItems.Value)) + f = append(f, fmt.Sprint(i.MaxItems.Value)) + f = append(f, fmt.Sprint(i.MultipleOf.Value)) + f = append(f, fmt.Sprint(i.UniqueItems.Value)) + if i.Pattern.Value != "" { + f = append(f, fmt.Sprintf("%x", sha256.Sum256([]byte(fmt.Sprint(i.Pattern.Value))))) + } + keys := make([]string, len(i.Enum.Value)) + z := 0 + for k := range i.Enum.Value { + keys[z] = fmt.Sprint(i.Enum.Value[k].Value) + z++ + } + sort.Strings(keys) + f = append(f, keys...) + + if i.Items.Value != nil { + f = append(f, low.GenerateHashString(i.Items.Value)) + } + keys = make([]string, len(i.Extensions)) + z = 0 + for k := range i.Extensions { + keys[z] = fmt.Sprintf("%s-%x", k.Value, sha256.Sum256([]byte(fmt.Sprint(i.Extensions[k].Value)))) + z++ + } + sort.Strings(keys) + f = append(f, keys...) + return sha256.Sum256([]byte(strings.Join(f, "|"))) +} + +// Build will build out items and default value. +func (i *Items) Build(root *yaml.Node, idx *index.SpecIndex) error { + i.Extensions = low.ExtractExtensions(root) + items, iErr := low.ExtractObject[*Items](ItemsLabel, root, idx) + if iErr != nil { + return iErr + } + i.Items = items + + _, ln, vn := utils.FindKeyNodeFull(DefaultLabel, root.Content) + if vn != nil { + var n map[string]interface{} + err := vn.Decode(&n) + if err != nil { + // if not a map, then try an array + var k []interface{} + err = vn.Decode(&k) + if err != nil { + // lets just default to interface + var j interface{} + _ = vn.Decode(&j) + i.Default = low.NodeReference[any]{ + Value: j, + KeyNode: ln, + ValueNode: vn, + } + return nil + } + i.Default = low.NodeReference[any]{ + Value: k, + KeyNode: ln, + ValueNode: vn, + } + return nil + } + i.Default = low.NodeReference[any]{ + Value: n, + KeyNode: ln, + ValueNode: vn, + } + return nil + } + return nil +} + +// IsHeader compliance methods + +func (i *Items) GetType() *low.NodeReference[string] { + return &i.Type +} +func (i *Items) GetFormat() *low.NodeReference[string] { + return &i.Format +} +func (i *Items) GetItems() *low.NodeReference[any] { + k := low.NodeReference[any]{ + KeyNode: i.Items.KeyNode, + ValueNode: i.Items.ValueNode, + Value: i.Items.Value, + } + return &k +} +func (i *Items) GetCollectionFormat() *low.NodeReference[string] { + return &i.CollectionFormat +} +func (i *Items) GetDescription() *low.NodeReference[string] { + return nil // not implemented, but required to align with header contract +} +func (i *Items) GetDefault() *low.NodeReference[any] { + return &i.Default +} +func (i *Items) GetMaximum() *low.NodeReference[int] { + return &i.Maximum +} +func (i *Items) GetExclusiveMaximum() *low.NodeReference[bool] { + return &i.ExclusiveMaximum +} +func (i *Items) GetMinimum() *low.NodeReference[int] { + return &i.Minimum +} +func (i *Items) GetExclusiveMinimum() *low.NodeReference[bool] { + return &i.ExclusiveMinimum +} +func (i *Items) GetMaxLength() *low.NodeReference[int] { + return &i.MaxLength +} +func (i *Items) GetMinLength() *low.NodeReference[int] { + return &i.MinLength +} +func (i *Items) GetPattern() *low.NodeReference[string] { + return &i.Pattern +} +func (i *Items) GetMaxItems() *low.NodeReference[int] { + return &i.MaxItems +} +func (i *Items) GetMinItems() *low.NodeReference[int] { + return &i.MinItems +} +func (i *Items) GetUniqueItems() *low.NodeReference[bool] { + return &i.UniqueItems +} +func (i *Items) GetEnum() *low.NodeReference[[]low.ValueReference[any]] { + return &i.Enum +} +func (i *Items) GetMultipleOf() *low.NodeReference[int] { + return &i.MultipleOf +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/low/v2/operation.go b/vendor/github.com/pb33f/libopenapi/datamodel/low/v2/operation.go new file mode 100644 index 0000000000..2783bc9913 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/low/v2/operation.go @@ -0,0 +1,216 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package v2 + +import ( + "crypto/sha256" + "fmt" + "github.com/pb33f/libopenapi/datamodel/low" + "github.com/pb33f/libopenapi/datamodel/low/base" + "github.com/pb33f/libopenapi/index" + "gopkg.in/yaml.v3" + "sort" + "strings" +) + +// Operation represents a low-level Swagger / OpenAPI 2 Operation object. +// +// It describes a single API operation on a path. +// - https://swagger.io/specification/v2/#operationObject +type Operation struct { + Tags low.NodeReference[[]low.ValueReference[string]] + Summary low.NodeReference[string] + Description low.NodeReference[string] + ExternalDocs low.NodeReference[*base.ExternalDoc] + OperationId low.NodeReference[string] + Consumes low.NodeReference[[]low.ValueReference[string]] + Produces low.NodeReference[[]low.ValueReference[string]] + Parameters low.NodeReference[[]low.ValueReference[*Parameter]] + Responses low.NodeReference[*Responses] + Schemes low.NodeReference[[]low.ValueReference[string]] + Deprecated low.NodeReference[bool] + Security low.NodeReference[[]low.ValueReference[*base.SecurityRequirement]] + Extensions map[low.KeyReference[string]]low.ValueReference[any] +} + +// Build will extract external docs, extensions, parameters, responses and security requirements. +func (o *Operation) Build(root *yaml.Node, idx *index.SpecIndex) error { + o.Extensions = low.ExtractExtensions(root) + + // extract externalDocs + extDocs, dErr := low.ExtractObject[*base.ExternalDoc](base.ExternalDocsLabel, root, idx) + if dErr != nil { + return dErr + } + o.ExternalDocs = extDocs + + // extract parameters + params, ln, vn, pErr := low.ExtractArray[*Parameter](ParametersLabel, root, idx) + if pErr != nil { + return pErr + } + if params != nil { + o.Parameters = low.NodeReference[[]low.ValueReference[*Parameter]]{ + Value: params, + KeyNode: ln, + ValueNode: vn, + } + } + + // extract responses + respBody, respErr := low.ExtractObject[*Responses](ResponsesLabel, root, idx) + if respErr != nil { + return respErr + } + o.Responses = respBody + + // extract security + sec, sln, svn, sErr := low.ExtractArray[*base.SecurityRequirement](SecurityLabel, root, idx) + if sErr != nil { + return sErr + } + if sec != nil { + o.Security = low.NodeReference[[]low.ValueReference[*base.SecurityRequirement]]{ + Value: sec, + KeyNode: sln, + ValueNode: svn, + } + } + return nil +} + +// Hash will return a consistent SHA256 Hash of the Operation object +func (o *Operation) Hash() [32]byte { + var f []string + if !o.Summary.IsEmpty() { + f = append(f, o.Summary.Value) + } + if !o.Description.IsEmpty() { + f = append(f, o.Description.Value) + } + if !o.OperationId.IsEmpty() { + f = append(f, o.OperationId.Value) + } + if !o.Summary.IsEmpty() { + f = append(f, o.Summary.Value) + } + if !o.ExternalDocs.IsEmpty() { + f = append(f, low.GenerateHashString(o.ExternalDocs.Value)) + } + if !o.Responses.IsEmpty() { + f = append(f, low.GenerateHashString(o.Responses.Value)) + } + if !o.Deprecated.IsEmpty() { + f = append(f, fmt.Sprint(o.Deprecated.Value)) + } + var keys []string + keys = make([]string, len(o.Tags.Value)) + for k := range o.Tags.Value { + keys[k] = o.Tags.Value[k].Value + } + sort.Strings(keys) + f = append(f, keys...) + + keys = make([]string, len(o.Consumes.Value)) + for k := range o.Consumes.Value { + keys[k] = o.Consumes.Value[k].Value + } + sort.Strings(keys) + f = append(f, keys...) + + keys = make([]string, len(o.Produces.Value)) + for k := range o.Produces.Value { + keys[k] = o.Produces.Value[k].Value + } + sort.Strings(keys) + f = append(f, keys...) + + keys = make([]string, len(o.Schemes.Value)) + for k := range o.Schemes.Value { + keys[k] = o.Schemes.Value[k].Value + } + sort.Strings(keys) + f = append(f, keys...) + + keys = make([]string, len(o.Parameters.Value)) + for k := range o.Parameters.Value { + keys[k] = low.GenerateHashString(o.Parameters.Value[k].Value) + } + sort.Strings(keys) + f = append(f, keys...) + + keys = make([]string, len(o.Security.Value)) + for k := range o.Security.Value { + keys[k] = low.GenerateHashString(o.Security.Value[k].Value) + } + sort.Strings(keys) + f = append(f, keys...) + keys = make([]string, len(o.Extensions)) + z := 0 + for k := range o.Extensions { + keys[z] = fmt.Sprintf("%s-%x", k.Value, sha256.Sum256([]byte(fmt.Sprint(o.Extensions[k].Value)))) + z++ + } + sort.Strings(keys) + f = append(f, keys...) + return sha256.Sum256([]byte(strings.Join(f, "|"))) +} + +// methods to satisfy swagger operations interface + +func (o *Operation) GetTags() low.NodeReference[[]low.ValueReference[string]] { + return o.Tags +} +func (o *Operation) GetSummary() low.NodeReference[string] { + return o.Summary +} +func (o *Operation) GetDescription() low.NodeReference[string] { + return o.Description +} +func (o *Operation) GetExternalDocs() low.NodeReference[any] { + return low.NodeReference[any]{ + ValueNode: o.ExternalDocs.ValueNode, + KeyNode: o.ExternalDocs.KeyNode, + Value: o.ExternalDocs.Value, + } +} +func (o *Operation) GetOperationId() low.NodeReference[string] { + return o.OperationId +} +func (o *Operation) GetDeprecated() low.NodeReference[bool] { + return o.Deprecated +} +func (o *Operation) GetExtensions() map[low.KeyReference[string]]low.ValueReference[any] { + return o.Extensions +} +func (o *Operation) GetResponses() low.NodeReference[any] { + return low.NodeReference[any]{ + ValueNode: o.Responses.ValueNode, + KeyNode: o.Responses.KeyNode, + Value: o.Responses.Value, + } +} +func (o *Operation) GetParameters() low.NodeReference[any] { + return low.NodeReference[any]{ + ValueNode: o.Parameters.ValueNode, + KeyNode: o.Parameters.KeyNode, + Value: o.Parameters.Value, + } +} +func (o *Operation) GetSecurity() low.NodeReference[any] { + return low.NodeReference[any]{ + ValueNode: o.Security.ValueNode, + KeyNode: o.Security.KeyNode, + Value: o.Security.Value, + } +} +func (o *Operation) GetSchemes() low.NodeReference[[]low.ValueReference[string]] { + return o.Schemes +} +func (o *Operation) GetProduces() low.NodeReference[[]low.ValueReference[string]] { + return o.Produces +} +func (o *Operation) GetConsumes() low.NodeReference[[]low.ValueReference[string]] { + return o.Consumes +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/low/v2/parameter.go b/vendor/github.com/pb33f/libopenapi/datamodel/low/v2/parameter.go new file mode 100644 index 0000000000..159532db01 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/low/v2/parameter.go @@ -0,0 +1,282 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package v2 + +import ( + "crypto/sha256" + "fmt" + "github.com/pb33f/libopenapi/datamodel/low" + "github.com/pb33f/libopenapi/datamodel/low/base" + "github.com/pb33f/libopenapi/index" + "github.com/pb33f/libopenapi/utils" + "gopkg.in/yaml.v3" + "sort" + "strings" +) + +// Parameter represents a low-level Swagger / OpenAPI 2 Parameter object. +// +// A unique parameter is defined by a combination of a name and location. +// +// There are five possible parameter types. +// +// Path +// Used together with Path Templating, where the parameter value is actually part of the operation's URL. +// This does not include the host or base path of the API. For example, in /items/{itemId}, the path parameter is itemId. +// Query +// Parameters that are appended to the URL. For example, in /items?id=###, the query parameter is id. +// Header +// Custom headers that are expected as part of the request. +// Body +// The payload that's appended to the HTTP request. Since there can only be one payload, there can only be one body parameter. +// The name of the body parameter has no effect on the parameter itself and is used for documentation purposes only. +// Since Form parameters are also in the payload, body and form parameters cannot exist together for the same operation. +// Form +// Used to describe the payload of an HTTP request when either application/x-www-form-urlencoded, multipart/form-data +// or both are used as the content type of the request (in Swagger's definition, the consumes property of an operation). +// This is the only parameter type that can be used to send files, thus supporting the file type. Since form parameters +// are sent in the payload, they cannot be declared together with a body parameter for the same operation. Form +// parameters have a different format based on the content-type used (for further details, +// consult http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4): +// application/x-www-form-urlencoded - Similar to the format of Query parameters but as a payload. For example, +// foo=1&bar=swagger - both foo and bar are form parameters. This is normally used for simple parameters that are +// being transferred. +// multipart/form-data - each parameter takes a section in the payload with an internal header. For example, for +// the header Content-Disposition: form-data; name="submit-name" the name of the parameter is +// submit-name. This type of form parameters is more commonly used for file transfers +// https://swagger.io/specification/v2/#parameterObject +type Parameter struct { + Name low.NodeReference[string] + In low.NodeReference[string] + Type low.NodeReference[string] + Format low.NodeReference[string] + Description low.NodeReference[string] + Required low.NodeReference[bool] + AllowEmptyValue low.NodeReference[bool] + Schema low.NodeReference[*base.SchemaProxy] + Items low.NodeReference[*Items] + CollectionFormat low.NodeReference[string] + Default low.NodeReference[any] + Maximum low.NodeReference[int] + ExclusiveMaximum low.NodeReference[bool] + Minimum low.NodeReference[int] + ExclusiveMinimum low.NodeReference[bool] + MaxLength low.NodeReference[int] + MinLength low.NodeReference[int] + Pattern low.NodeReference[string] + MaxItems low.NodeReference[int] + MinItems low.NodeReference[int] + UniqueItems low.NodeReference[bool] + Enum low.NodeReference[[]low.ValueReference[any]] + MultipleOf low.NodeReference[int] + Extensions map[low.KeyReference[string]]low.ValueReference[any] +} + +// FindExtension attempts to locate a extension value given a name. +func (p *Parameter) FindExtension(ext string) *low.ValueReference[any] { + return low.FindItemInMap[any](ext, p.Extensions) +} + +// GetExtensions returns all Parameter extensions and satisfies the low.HasExtensions interface. +func (p *Parameter) GetExtensions() map[low.KeyReference[string]]low.ValueReference[any] { + return p.Extensions +} + +// Build will extract out extensions, schema, items and default value +func (p *Parameter) Build(root *yaml.Node, idx *index.SpecIndex) error { + p.Extensions = low.ExtractExtensions(root) + sch, sErr := base.ExtractSchema(root, idx) + if sErr != nil { + return sErr + } + if sch != nil { + p.Schema = *sch + } + items, iErr := low.ExtractObject[*Items](ItemsLabel, root, idx) + if iErr != nil { + return iErr + } + p.Items = items + + _, ln, vn := utils.FindKeyNodeFull(DefaultLabel, root.Content) + if vn != nil { + var n map[string]interface{} + err := vn.Decode(&n) + if err != nil { + var k []interface{} + err = vn.Decode(&k) + if err != nil { + var j interface{} + _ = vn.Decode(&j) + p.Default = low.NodeReference[any]{ + Value: j, + KeyNode: ln, + ValueNode: vn, + } + return nil + } + p.Default = low.NodeReference[any]{ + Value: k, + KeyNode: ln, + ValueNode: vn, + } + return nil + } + p.Default = low.NodeReference[any]{ + Value: n, + KeyNode: ln, + ValueNode: vn, + } + return nil + } + return nil +} + +// Hash will return a consistent SHA256 Hash of the Parameter object +func (p *Parameter) Hash() [32]byte { + var f []string + if p.Name.Value != "" { + f = append(f, p.Name.Value) + } + if p.In.Value != "" { + f = append(f, p.In.Value) + } + if p.Type.Value != "" { + f = append(f, p.Type.Value) + } + if p.Format.Value != "" { + f = append(f, p.Format.Value) + } + if p.Description.Value != "" { + f = append(f, p.Description.Value) + } + f = append(f, fmt.Sprint(p.Required.Value)) + f = append(f, fmt.Sprint(p.AllowEmptyValue.Value)) + if p.Schema.Value != nil { + f = append(f, low.GenerateHashString(p.Schema.Value.Schema())) + } + if p.CollectionFormat.Value != "" { + f = append(f, p.CollectionFormat.Value) + } + if p.Default.Value != "" { + f = append(f, fmt.Sprintf("%x", sha256.Sum256([]byte(fmt.Sprint(p.Default.Value))))) + } + f = append(f, fmt.Sprint(p.Maximum.Value)) + f = append(f, fmt.Sprint(p.Minimum.Value)) + f = append(f, fmt.Sprint(p.ExclusiveMinimum.Value)) + f = append(f, fmt.Sprint(p.ExclusiveMaximum.Value)) + f = append(f, fmt.Sprint(p.MinLength.Value)) + f = append(f, fmt.Sprint(p.MaxLength.Value)) + f = append(f, fmt.Sprint(p.MinItems.Value)) + f = append(f, fmt.Sprint(p.MaxItems.Value)) + f = append(f, fmt.Sprint(p.MultipleOf.Value)) + f = append(f, fmt.Sprint(p.UniqueItems.Value)) + if p.Pattern.Value != "" { + f = append(f, fmt.Sprintf("%x", sha256.Sum256([]byte(fmt.Sprint(p.Pattern.Value))))) + } + + keys := make([]string, len(p.Enum.Value)) + z := 0 + for k := range p.Enum.Value { + keys[z] = fmt.Sprint(p.Enum.Value[k].Value) + z++ + } + sort.Strings(keys) + f = append(f, keys...) + + keys = make([]string, len(p.Extensions)) + z = 0 + for k := range p.Extensions { + keys[z] = fmt.Sprintf("%s-%x", k.Value, sha256.Sum256([]byte(fmt.Sprint(p.Extensions[k].Value)))) + z++ + } + sort.Strings(keys) + f = append(f, keys...) + if p.Items.Value != nil { + f = append(f, fmt.Sprintf("%x", p.Items.Value.Hash())) + } + return sha256.Sum256([]byte(strings.Join(f, "|"))) +} + +// Getters used by what-changed feature to satisfy the SwaggerParameter interface. + +func (p *Parameter) GetName() *low.NodeReference[string] { + return &p.Name +} +func (p *Parameter) GetIn() *low.NodeReference[string] { + return &p.In +} +func (p *Parameter) GetType() *low.NodeReference[string] { + return &p.Type +} +func (p *Parameter) GetDescription() *low.NodeReference[string] { + return &p.Description +} +func (p *Parameter) GetRequired() *low.NodeReference[bool] { + return &p.Required +} +func (p *Parameter) GetAllowEmptyValue() *low.NodeReference[bool] { + return &p.AllowEmptyValue +} +func (p *Parameter) GetSchema() *low.NodeReference[any] { + i := low.NodeReference[any]{ + KeyNode: p.Schema.KeyNode, + ValueNode: p.Schema.ValueNode, + Value: p.Schema.Value, + } + return &i +} +func (p *Parameter) GetFormat() *low.NodeReference[string] { + return &p.Format +} +func (p *Parameter) GetItems() *low.NodeReference[any] { + i := low.NodeReference[any]{ + KeyNode: p.Items.KeyNode, + ValueNode: p.Items.ValueNode, + Value: p.Items.Value, + } + return &i +} +func (p *Parameter) GetCollectionFormat() *low.NodeReference[string] { + return &p.CollectionFormat +} +func (p *Parameter) GetDefault() *low.NodeReference[any] { + return &p.Default +} +func (p *Parameter) GetMaximum() *low.NodeReference[int] { + return &p.Maximum +} +func (p *Parameter) GetExclusiveMaximum() *low.NodeReference[bool] { + return &p.ExclusiveMaximum +} +func (p *Parameter) GetMinimum() *low.NodeReference[int] { + return &p.Minimum +} +func (p *Parameter) GetExclusiveMinimum() *low.NodeReference[bool] { + return &p.ExclusiveMinimum +} +func (p *Parameter) GetMaxLength() *low.NodeReference[int] { + return &p.MaxLength +} +func (p *Parameter) GetMinLength() *low.NodeReference[int] { + return &p.MinLength +} +func (p *Parameter) GetPattern() *low.NodeReference[string] { + return &p.Pattern +} +func (p *Parameter) GetMaxItems() *low.NodeReference[int] { + return &p.MaxItems +} +func (p *Parameter) GetMinItems() *low.NodeReference[int] { + return &p.MinItems +} +func (p *Parameter) GetUniqueItems() *low.NodeReference[bool] { + return &p.UniqueItems +} +func (p *Parameter) GetEnum() *low.NodeReference[[]low.ValueReference[any]] { + return &p.Enum +} +func (p *Parameter) GetMultipleOf() *low.NodeReference[int] { + return &p.MultipleOf +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/low/v2/path_item.go b/vendor/github.com/pb33f/libopenapi/datamodel/low/v2/path_item.go new file mode 100644 index 0000000000..649cccd95c --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/low/v2/path_item.go @@ -0,0 +1,230 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package v2 + +import ( + "crypto/sha256" + "fmt" + "github.com/pb33f/libopenapi/datamodel/low" + "github.com/pb33f/libopenapi/index" + "gopkg.in/yaml.v3" + "sort" + "strings" + "sync" +) + +// PathItem represents a low-level Swagger / OpenAPI 2 PathItem object. +// +// Describes the operations available on a single path. A Path Item may be empty, due to ACL constraints. +// The path itself is still exposed to the tooling, but will not know which operations and parameters +// are available. +// +// - https://swagger.io/specification/v2/#pathItemObject +type PathItem struct { + Ref low.NodeReference[string] + Get low.NodeReference[*Operation] + Put low.NodeReference[*Operation] + Post low.NodeReference[*Operation] + Delete low.NodeReference[*Operation] + Options low.NodeReference[*Operation] + Head low.NodeReference[*Operation] + Patch low.NodeReference[*Operation] + Parameters low.NodeReference[[]low.ValueReference[*Parameter]] + Extensions map[low.KeyReference[string]]low.ValueReference[any] +} + +// FindExtension will attempt to locate an extension given a name. +func (p *PathItem) FindExtension(ext string) *low.ValueReference[any] { + return low.FindItemInMap[any](ext, p.Extensions) +} + +// GetExtensions returns all PathItem extensions and satisfies the low.HasExtensions interface. +func (p *PathItem) GetExtensions() map[low.KeyReference[string]]low.ValueReference[any] { + return p.Extensions +} + +// Build will extract extensions, parameters and operations for all methods. Every method is handled +// asynchronously, in order to keep things moving quickly for complex operations. +func (p *PathItem) Build(root *yaml.Node, idx *index.SpecIndex) error { + p.Extensions = low.ExtractExtensions(root) + skip := false + var currentNode *yaml.Node + + var wg sync.WaitGroup + var errors []error + + var ops []low.NodeReference[*Operation] + + // extract parameters + params, ln, vn, pErr := low.ExtractArray[*Parameter](ParametersLabel, root, idx) + if pErr != nil { + return pErr + } + if params != nil { + p.Parameters = low.NodeReference[[]low.ValueReference[*Parameter]]{ + Value: params, + KeyNode: ln, + ValueNode: vn, + } + } + + for i, pathNode := range root.Content { + if strings.HasPrefix(strings.ToLower(pathNode.Value), "x-") { + skip = true + continue + } + // because (for some reason) the spec for swagger docs allows for a '$ref' property for path items. + // this is kinda nuts, because '$ref' is a reserved keyword for JSON references, which is ALSO used + // in swagger. Why this choice was made, I do not know. + if strings.Contains(strings.ToLower(pathNode.Value), "$ref") { + rn := root.Content[i+1] + p.Ref = low.NodeReference[string]{ + Value: rn.Value, + ValueNode: rn, + KeyNode: pathNode, + } + skip = true + continue + } + if skip { + skip = false + continue + } + if i%2 == 0 { + currentNode = pathNode + continue + } + + // the only thing we now care about is handling operations, filter out anything that's not a verb. + switch currentNode.Value { + case GetLabel: + break + case PostLabel: + break + case PutLabel: + break + case PatchLabel: + break + case DeleteLabel: + break + case HeadLabel: + break + case OptionsLabel: + break + default: + continue // ignore everything else. + } + + var op Operation + + wg.Add(1) + + go low.BuildModelAsync(pathNode, &op, &wg, &errors) + + opRef := low.NodeReference[*Operation]{ + Value: &op, + KeyNode: currentNode, + ValueNode: pathNode, + } + + ops = append(ops, opRef) + + switch currentNode.Value { + case GetLabel: + p.Get = opRef + case PostLabel: + p.Post = opRef + case PutLabel: + p.Put = opRef + case PatchLabel: + p.Patch = opRef + case DeleteLabel: + p.Delete = opRef + case HeadLabel: + p.Head = opRef + case OptionsLabel: + p.Options = opRef + } + } + + //all operations have been superficially built, + //now we need to build out the operation, we will do this asynchronously for speed. + opBuildChan := make(chan bool) + opErrorChan := make(chan error) + + var buildOpFunc = func(op low.NodeReference[*Operation], ch chan<- bool, errCh chan<- error) { + er := op.Value.Build(op.ValueNode, idx) + if er != nil { + errCh <- er + } + ch <- true + } + + if len(ops) <= 0 { + return nil // nothing to do. + } + + for _, op := range ops { + go buildOpFunc(op, opBuildChan, opErrorChan) + } + + n := 0 + total := len(ops) + for n < total { + select { + case buildError := <-opErrorChan: + return buildError + case <-opBuildChan: + n++ + } + } + + // make sure we don't exit before the path is finished building. + if len(ops) > 0 { + wg.Wait() + } + + return nil +} + +// Hash will return a consistent SHA256 Hash of the PathItem object +func (p *PathItem) Hash() [32]byte { + var f []string + if !p.Get.IsEmpty() { + f = append(f, fmt.Sprintf("%s-%s", GetLabel, low.GenerateHashString(p.Get.Value))) + } + if !p.Put.IsEmpty() { + f = append(f, fmt.Sprintf("%s-%s", PutLabel, low.GenerateHashString(p.Put.Value))) + } + if !p.Post.IsEmpty() { + f = append(f, fmt.Sprintf("%s-%s", PostLabel, low.GenerateHashString(p.Post.Value))) + } + if !p.Delete.IsEmpty() { + f = append(f, fmt.Sprintf("%s-%s", DeleteLabel, low.GenerateHashString(p.Delete.Value))) + } + if !p.Options.IsEmpty() { + f = append(f, fmt.Sprintf("%s-%s", OptionsLabel, low.GenerateHashString(p.Options.Value))) + } + if !p.Head.IsEmpty() { + f = append(f, fmt.Sprintf("%s-%s", HeadLabel, low.GenerateHashString(p.Head.Value))) + } + if !p.Patch.IsEmpty() { + f = append(f, fmt.Sprintf("%s-%s", PatchLabel, low.GenerateHashString(p.Patch.Value))) + } + keys := make([]string, len(p.Parameters.Value)) + for k := range p.Parameters.Value { + keys[k] = low.GenerateHashString(p.Parameters.Value[k].Value) + } + sort.Strings(keys) + f = append(f, keys...) + keys = make([]string, len(p.Extensions)) + z := 0 + for k := range p.Extensions { + keys[z] = fmt.Sprintf("%s-%x", k.Value, sha256.Sum256([]byte(fmt.Sprint(p.Extensions[k].Value)))) + z++ + } + sort.Strings(keys) + f = append(f, keys...) + return sha256.Sum256([]byte(strings.Join(f, "|"))) +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/low/v2/paths.go b/vendor/github.com/pb33f/libopenapi/datamodel/low/v2/paths.go new file mode 100644 index 0000000000..7cf19bfc96 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/low/v2/paths.go @@ -0,0 +1,142 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package v2 + +import ( + "crypto/sha256" + "fmt" + "github.com/pb33f/libopenapi/datamodel/low" + "github.com/pb33f/libopenapi/index" + "gopkg.in/yaml.v3" + "sort" + "strings" +) + +// Paths represents a low-level Swagger / OpenAPI Paths object. +type Paths struct { + PathItems map[low.KeyReference[string]]low.ValueReference[*PathItem] + Extensions map[low.KeyReference[string]]low.ValueReference[any] +} + +// GetExtensions returns all Paths extensions and satisfies the low.HasExtensions interface. +func (p *Paths) GetExtensions() map[low.KeyReference[string]]low.ValueReference[any] { + return p.Extensions +} + +// FindPath attempts to locate a PathItem instance, given a path key. +func (p *Paths) FindPath(path string) *low.ValueReference[*PathItem] { + for k, j := range p.PathItems { + if k.Value == path { + return &j + } + } + return nil +} + +// FindPathAndKey attempts to locate a PathItem instance, given a path key. +func (p *Paths) FindPathAndKey(path string) (*low.KeyReference[string], *low.ValueReference[*PathItem]) { + for k, j := range p.PathItems { + if k.Value == path { + return &k, &j + } + } + return nil, nil +} + +// FindExtension will attempt to locate an extension value given a name. +func (p *Paths) FindExtension(ext string) *low.ValueReference[any] { + return low.FindItemInMap[any](ext, p.Extensions) +} + +// Build will extract extensions and paths from node. +func (p *Paths) Build(root *yaml.Node, idx *index.SpecIndex) error { + p.Extensions = low.ExtractExtensions(root) + skip := false + var currentNode *yaml.Node + + pathsMap := make(map[low.KeyReference[string]]low.ValueReference[*PathItem]) + + // build each new path, in a new thread. + type pathBuildResult struct { + k low.KeyReference[string] + v low.ValueReference[*PathItem] + } + + bChan := make(chan pathBuildResult) + eChan := make(chan error) + var buildPathItem = func(cNode, pNode *yaml.Node, b chan<- pathBuildResult, e chan<- error) { + path := new(PathItem) + _ = low.BuildModel(pNode, path) + err := path.Build(pNode, idx) + if err != nil { + e <- err + return + } + b <- pathBuildResult{ + k: low.KeyReference[string]{ + Value: cNode.Value, + KeyNode: cNode, + }, + v: low.ValueReference[*PathItem]{ + Value: path, + ValueNode: pNode, + }, + } + } + pathCount := 0 + for i, pathNode := range root.Content { + if strings.HasPrefix(strings.ToLower(pathNode.Value), "x-") { + skip = true + continue + } + if skip { + skip = false + continue + } + if i%2 == 0 { + currentNode = pathNode + continue + } + pathCount++ + go buildPathItem(currentNode, pathNode, bChan, eChan) + } + completedItems := 0 + for completedItems < pathCount { + select { + case err := <-eChan: + return err + case res := <-bChan: + completedItems++ + pathsMap[res.k] = res.v + } + } + p.PathItems = pathsMap + return nil +} + +// Hash will return a consistent SHA256 Hash of the PathItem object +func (p *Paths) Hash() [32]byte { + var f []string + l := make([]string, len(p.PathItems)) + keys := make(map[string]low.ValueReference[*PathItem]) + z := 0 + for k := range p.PathItems { + keys[k.Value] = p.PathItems[k] + l[z] = k.Value + z++ + } + sort.Strings(l) + for k := range l { + f = append(f, low.GenerateHashString(keys[l[k]].Value)) + } + ekeys := make([]string, len(p.Extensions)) + z = 0 + for k := range p.Extensions { + ekeys[z] = fmt.Sprintf("%s-%x", k.Value, sha256.Sum256([]byte(fmt.Sprint(p.Extensions[k].Value)))) + z++ + } + sort.Strings(ekeys) + f = append(f, ekeys...) + return sha256.Sum256([]byte(strings.Join(f, "|"))) +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/low/v2/response.go b/vendor/github.com/pb33f/libopenapi/datamodel/low/v2/response.go new file mode 100644 index 0000000000..cde0cf1028 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/low/v2/response.go @@ -0,0 +1,100 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package v2 + +import ( + "crypto/sha256" + "fmt" + "github.com/pb33f/libopenapi/datamodel/low" + "github.com/pb33f/libopenapi/datamodel/low/base" + "github.com/pb33f/libopenapi/index" + "gopkg.in/yaml.v3" + "sort" + "strings" +) + +// Response is a representation of a high-level Swagger / OpenAPI 2 Response object, backed by a low-level one. +// +// Response describes a single response from an API Operation +// - https://swagger.io/specification/v2/#responseObject +type Response struct { + Description low.NodeReference[string] + Schema low.NodeReference[*base.SchemaProxy] + Headers low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*Header]] + Examples low.NodeReference[*Examples] + Extensions map[low.KeyReference[string]]low.ValueReference[any] +} + +// FindExtension will attempt to locate an extension value given a key to lookup. +func (r *Response) FindExtension(ext string) *low.ValueReference[any] { + return low.FindItemInMap[any](ext, r.Extensions) +} + +// GetExtensions returns all Response extensions and satisfies the low.HasExtensions interface. +func (r *Response) GetExtensions() map[low.KeyReference[string]]low.ValueReference[any] { + return r.Extensions +} + +// FindHeader will attempt to locate a Header value, given a key +func (r *Response) FindHeader(hType string) *low.ValueReference[*Header] { + return low.FindItemInMap[*Header](hType, r.Headers.Value) +} + +// Build will extract schema, extensions, examples and headers from node +func (r *Response) Build(root *yaml.Node, idx *index.SpecIndex) error { + r.Extensions = low.ExtractExtensions(root) + s, err := base.ExtractSchema(root, idx) + if err != nil { + return err + } + if s != nil { + r.Schema = *s + } + + // extract examples + examples, expErr := low.ExtractObject[*Examples](ExamplesLabel, root, idx) + if expErr != nil { + return expErr + } + r.Examples = examples + + //extract headers + headers, lN, kN, err := low.ExtractMap[*Header](HeadersLabel, root, idx) + if err != nil { + return err + } + if headers != nil { + r.Headers = low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*Header]]{ + Value: headers, + KeyNode: lN, + ValueNode: kN, + } + } + return nil +} + +// Hash will return a consistent SHA256 Hash of the Response object +func (r *Response) Hash() [32]byte { + var f []string + if r.Description.Value != "" { + f = append(f, r.Description.Value) + } + if !r.Schema.IsEmpty() { + f = append(f, low.GenerateHashString(r.Schema.Value)) + } + if !r.Examples.IsEmpty() { + for k := range r.Examples.Value.Values { + f = append(f, low.GenerateHashString(r.Examples.Value.Values[k].Value)) + } + } + keys := make([]string, len(r.Extensions)) + z := 0 + for k := range r.Extensions { + keys[z] = fmt.Sprintf("%s-%x", k.Value, sha256.Sum256([]byte(fmt.Sprint(r.Extensions[k].Value)))) + z++ + } + sort.Strings(keys) + f = append(f, keys...) + return sha256.Sum256([]byte(strings.Join(f, "|"))) +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/low/v2/responses.go b/vendor/github.com/pb33f/libopenapi/datamodel/low/v2/responses.go new file mode 100644 index 0000000000..339837e467 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/low/v2/responses.go @@ -0,0 +1,118 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package v2 + +import ( + "crypto/sha256" + "fmt" + "github.com/pb33f/libopenapi/datamodel/low" + "github.com/pb33f/libopenapi/index" + "github.com/pb33f/libopenapi/utils" + "gopkg.in/yaml.v3" + "sort" + "strings" +) + +// Responses is a low-level representation of a Swagger / OpenAPI 2 Responses object. +type Responses struct { + Codes map[low.KeyReference[string]]low.ValueReference[*Response] + Default low.NodeReference[*Response] + Extensions map[low.KeyReference[string]]low.ValueReference[any] +} + +// GetExtensions returns all Responses extensions and satisfies the low.HasExtensions interface. +func (r *Responses) GetExtensions() map[low.KeyReference[string]]low.ValueReference[any] { + return r.Extensions +} + +// Build will extract default value and extensions from node. +func (r *Responses) Build(root *yaml.Node, idx *index.SpecIndex) error { + r.Extensions = low.ExtractExtensions(root) + + if utils.IsNodeMap(root) { + codes, err := low.ExtractMapNoLookup[*Response](root, idx) + if err != nil { + return err + } + if codes != nil { + r.Codes = codes + } + def := r.getDefault() + if def != nil { + // default is bundled into codes, pull it out + r.Default = *def + // remove default from codes + r.deleteCode(DefaultLabel) + } + } else { + return fmt.Errorf("responses build failed: vn node is not a map! line %d, col %d", + root.Line, root.Column) + } + return nil +} + +func (r *Responses) getDefault() *low.NodeReference[*Response] { + for n, o := range r.Codes { + if strings.ToLower(n.Value) == DefaultLabel { + return &low.NodeReference[*Response]{ + ValueNode: o.ValueNode, + KeyNode: n.KeyNode, + Value: o.Value, + } + } + } + return nil +} + +// used to remove default from codes extracted by Build() +func (r *Responses) deleteCode(code string) { + var key *low.KeyReference[string] + if r.Codes != nil { + for k := range r.Codes { + if k.Value == code { + key = &k + break + } + } + } + // should never be nil, but, you never know... science and all that! + if key != nil { + delete(r.Codes, *key) + } +} + +// FindResponseByCode will attempt to locate a Response instance using an HTTP response code string. +func (r *Responses) FindResponseByCode(code string) *low.ValueReference[*Response] { + return low.FindItemInMap[*Response](code, r.Codes) +} + +// Hash will return a consistent SHA256 Hash of the Examples object +func (r *Responses) Hash() [32]byte { + var f []string + var keys []string + keys = make([]string, len(r.Codes)) + cmap := make(map[string]*Response, len(keys)) + z := 0 + for k := range r.Codes { + keys[z] = k.Value + cmap[k.Value] = r.Codes[k].Value + z++ + } + sort.Strings(keys) + for k := range keys { + f = append(f, fmt.Sprintf("%s-%s", keys[k], low.GenerateHashString(cmap[keys[k]]))) + } + if !r.Default.IsEmpty() { + f = append(f, low.GenerateHashString(r.Default.Value)) + } + keys = make([]string, len(r.Extensions)) + z = 0 + for k := range r.Extensions { + keys[z] = fmt.Sprintf("%s-%x", k.Value, sha256.Sum256([]byte(fmt.Sprint(r.Extensions[k].Value)))) + z++ + } + sort.Strings(keys) + f = append(f, keys...) + return sha256.Sum256([]byte(strings.Join(f, "|"))) +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/low/v2/scopes.go b/vendor/github.com/pb33f/libopenapi/datamodel/low/v2/scopes.go new file mode 100644 index 0000000000..1908ba2a5d --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/low/v2/scopes.go @@ -0,0 +1,84 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package v2 + +import ( + "crypto/sha256" + "fmt" + "github.com/pb33f/libopenapi/datamodel/low" + "github.com/pb33f/libopenapi/index" + "github.com/pb33f/libopenapi/utils" + "gopkg.in/yaml.v3" + "sort" + "strings" +) + +// Scopes is a low-level representation of a Swagger / OpenAPI 2 OAuth2 Scopes object. +// +// Scopes lists the available scopes for an OAuth2 security scheme. +// - https://swagger.io/specification/v2/#scopesObject +type Scopes struct { + Values map[low.KeyReference[string]]low.ValueReference[string] + Extensions map[low.KeyReference[string]]low.ValueReference[any] +} + +// GetExtensions returns all Scopes extensions and satisfies the low.HasExtensions interface. +func (s *Scopes) GetExtensions() map[low.KeyReference[string]]low.ValueReference[any] { + return s.Extensions +} + +// FindScope will attempt to locate a scope string using a key. +func (s *Scopes) FindScope(scope string) *low.ValueReference[string] { + return low.FindItemInMap[string](scope, s.Values) +} + +// Build will extract scope values and extensions from node. +func (s *Scopes) Build(root *yaml.Node, idx *index.SpecIndex) error { + s.Extensions = low.ExtractExtensions(root) + valueMap := make(map[low.KeyReference[string]]low.ValueReference[string]) + if utils.IsNodeMap(root) { + for k := range root.Content { + if k%2 == 0 { + if strings.Contains(root.Content[k].Value, "x-") { + continue + } + valueMap[low.KeyReference[string]{ + Value: root.Content[k].Value, + KeyNode: root.Content[k], + }] = low.ValueReference[string]{ + Value: root.Content[k+1].Value, + ValueNode: root.Content[k+1], + } + } + } + s.Values = valueMap + } + return nil +} + +// Hash will return a consistent SHA256 Hash of the Scopes object +func (s *Scopes) Hash() [32]byte { + var f []string + vals := make(map[string]low.ValueReference[string], len(s.Values)) + keys := make([]string, len(s.Values)) + z := 0 + for k := range s.Values { + keys[z] = k.Value + vals[k.Value] = s.Values[k] + z++ + } + sort.Strings(keys) + for k := range keys { + f = append(f, fmt.Sprintf("%s-%s", keys[k], vals[keys[k]].Value)) + } + keys = make([]string, len(s.Extensions)) + z = 0 + for k := range s.Extensions { + keys[z] = fmt.Sprintf("%s-%x", k.Value, sha256.Sum256([]byte(fmt.Sprint(s.Extensions[k].Value)))) + z++ + } + sort.Strings(keys) + f = append(f, keys...) + return sha256.Sum256([]byte(strings.Join(f, "|"))) +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/low/v2/security_scheme.go b/vendor/github.com/pb33f/libopenapi/datamodel/low/v2/security_scheme.go new file mode 100644 index 0000000000..952f8b6e52 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/low/v2/security_scheme.go @@ -0,0 +1,87 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package v2 + +import ( + "crypto/sha256" + "fmt" + "github.com/pb33f/libopenapi/datamodel/low" + "github.com/pb33f/libopenapi/index" + "gopkg.in/yaml.v3" + "sort" + "strings" +) + +// SecurityScheme is a low-level representation of a Swagger / OpenAPI 2 SecurityScheme object. +// +// SecurityScheme allows the definition of a security scheme that can be used by the operations. Supported schemes are +// basic authentication, an API key (either as a header or as a query parameter) and OAuth2's common flows +// (implicit, password, application and access code) +// - https://swagger.io/specification/v2/#securityDefinitionsObject +type SecurityScheme struct { + Type low.NodeReference[string] + Description low.NodeReference[string] + Name low.NodeReference[string] + In low.NodeReference[string] + Flow low.NodeReference[string] + AuthorizationUrl low.NodeReference[string] + TokenUrl low.NodeReference[string] + Scopes low.NodeReference[*Scopes] + Extensions map[low.KeyReference[string]]low.ValueReference[any] +} + +// GetExtensions returns all SecurityScheme extensions and satisfies the low.HasExtensions interface. +func (ss *SecurityScheme) GetExtensions() map[low.KeyReference[string]]low.ValueReference[any] { + return ss.Extensions +} + +// Build will extract extensions and scopes from the node. +func (ss *SecurityScheme) Build(root *yaml.Node, idx *index.SpecIndex) error { + ss.Extensions = low.ExtractExtensions(root) + + scopes, sErr := low.ExtractObject[*Scopes](ScopesLabel, root, idx) + if sErr != nil { + return sErr + } + ss.Scopes = scopes + return nil +} + +// Hash will return a consistent SHA256 Hash of the SecurityScheme object +func (ss *SecurityScheme) Hash() [32]byte { + var f []string + if !ss.Type.IsEmpty() { + f = append(f, ss.Type.Value) + } + if !ss.Description.IsEmpty() { + f = append(f, ss.Description.Value) + } + if !ss.Name.IsEmpty() { + f = append(f, ss.Name.Value) + } + if !ss.In.IsEmpty() { + f = append(f, ss.In.Value) + } + if !ss.Flow.IsEmpty() { + f = append(f, ss.Flow.Value) + } + if !ss.AuthorizationUrl.IsEmpty() { + f = append(f, ss.AuthorizationUrl.Value) + } + if !ss.TokenUrl.IsEmpty() { + f = append(f, ss.TokenUrl.Value) + } + if !ss.Scopes.IsEmpty() { + f = append(f, low.GenerateHashString(ss.Scopes.Value)) + } + keys := make([]string, len(ss.Extensions)) + z := 0 + for k := range ss.Extensions { + keys[z] = fmt.Sprintf("%s-%x", k.Value, sha256.Sum256([]byte(fmt.Sprint(ss.Extensions[k].Value)))) + z++ + } + sort.Strings(keys) + f = append(f, keys...) + return sha256.Sum256([]byte(strings.Join(f, "|"))) +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/low/v2/swagger.go b/vendor/github.com/pb33f/libopenapi/datamodel/low/v2/swagger.go new file mode 100644 index 0000000000..561864cd6f --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/low/v2/swagger.go @@ -0,0 +1,297 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +// Package v2 represents all Swagger / OpenAPI 2 low-level models. +// +// Low-level models are more difficult to navigate than higher-level models, however they are packed with all the +// raw AST and node data required to perform any kind of analysis on the underlying data. +// +// Every property is wrapped in a NodeReference or a KeyReference or a ValueReference. +// +// IMPORTANT: As a general rule, Swagger / OpenAPI 2 should be avoided for new projects. +package v2 + +import ( + "github.com/pb33f/libopenapi/datamodel" + "github.com/pb33f/libopenapi/datamodel/low" + "github.com/pb33f/libopenapi/datamodel/low/base" + "github.com/pb33f/libopenapi/index" + "github.com/pb33f/libopenapi/resolver" + "gopkg.in/yaml.v3" +) + +// processes a property of a Swagger document asynchronously using bool and error channels for signals. +type documentFunction func(root *yaml.Node, doc *Swagger, idx *index.SpecIndex, c chan<- bool, e chan<- error) + +// Swagger represents a high-level Swagger / OpenAPI 2 document. An instance of Swagger is the root of the specification. +type Swagger struct { + + // Swagger is the version of Swagger / OpenAPI being used, extracted from the 'swagger: 2.x' definition. + Swagger low.ValueReference[string] + + // Info represents a specification Info definition. + // Provides metadata about the API. The metadata can be used by the clients if needed. + // - https://swagger.io/specification/v2/#infoObject + Info low.NodeReference[*base.Info] + + // Host is The host (name or ip) serving the API. This MUST be the host only and does not include the scheme nor + // sub-paths. It MAY include a port. If the host is not included, the host serving the documentation is to be used + // (including the port). The host does not support path templating. + Host low.NodeReference[string] + + // BasePath is The base path on which the API is served, which is relative to the host. If it is not included, + // the API is served directly under the host. The value MUST start with a leading slash (/). + // The basePath does not support path templating. + BasePath low.NodeReference[string] + + // Schemes represents the transfer protocol of the API. Requirements MUST be from the list: "http", "https", "ws", "wss". + // If the schemes is not included, the default scheme to be used is the one used to access + // the Swagger definition itself. + Schemes low.NodeReference[[]low.ValueReference[string]] + + // Consumes is a list of MIME types the APIs can consume. This is global to all APIs but can be overridden on + // specific API calls. Value MUST be as described under Mime Types. + Consumes low.NodeReference[[]low.ValueReference[string]] + + // Produces is a list of MIME types the APIs can produce. This is global to all APIs but can be overridden on + // specific API calls. Value MUST be as described under Mime Types. + Produces low.NodeReference[[]low.ValueReference[string]] + + // Paths are the paths and operations for the API. Perhaps the most important part of the specification. + // - https://swagger.io/specification/v2/#pathsObject + Paths low.NodeReference[*Paths] + + // Definitions is an object to hold data types produced and consumed by operations. It's composed of Schema instances + // - https://swagger.io/specification/v2/#definitionsObject + Definitions low.NodeReference[*Definitions] + + // SecurityDefinitions represents security scheme definitions that can be used across the specification. + // - https://swagger.io/specification/v2/#securityDefinitionsObject + SecurityDefinitions low.NodeReference[*SecurityDefinitions] + + // Parameters is an object to hold parameters that can be used across operations. + // This property does not define global parameters for all operations. + // - https://swagger.io/specification/v2/#parametersDefinitionsObject + Parameters low.NodeReference[*ParameterDefinitions] + + // Responses is an object to hold responses that can be used across operations. + // This property does not define global responses for all operations. + // - https://swagger.io/specification/v2/#responsesDefinitionsObject + Responses low.NodeReference[*ResponsesDefinitions] + + // Security is a declaration of which security schemes are applied for the API as a whole. The list of values + // describes alternative security schemes that can be used (that is, there is a logical OR between the security + // requirements). Individual operations can override this definition. + // - https://swagger.io/specification/v2/#securityRequirementObject + Security low.NodeReference[[]low.ValueReference[*base.SecurityRequirement]] + + // Tags are A list of tags used by the specification with additional metadata. + // The order of the tags can be used to reflect on their order by the parsing tools. Not all tags that are used + // by the Operation Object must be declared. The tags that are not declared may be organized randomly or based + // on the tools' logic. Each tag name in the list MUST be unique. + // - https://swagger.io/specification/v2/#tagObject + Tags low.NodeReference[[]low.ValueReference[*base.Tag]] + + // ExternalDocs is an instance of base.ExternalDoc for.. well, obvious really, innit mate? + ExternalDocs low.NodeReference[*base.ExternalDoc] + + // Extensions contains all custom extensions defined for the top-level document. + Extensions map[low.KeyReference[string]]low.ValueReference[any] + + // Index is a reference to the index.SpecIndex that was created for the document and used + // as a guide when building out the Document. Ideal if further processing is required on the model and + // the original details are required to continue the work. + // + // This property is not a part of the OpenAPI schema, this is custom to libopenapi. + Index *index.SpecIndex + + // SpecInfo is a reference to the datamodel.SpecInfo instance created when the specification was read. + // + // This property is not a part of the OpenAPI schema, this is custom to libopenapi. + SpecInfo *datamodel.SpecInfo +} + +// FindExtension locates an extension from the root of the Swagger document. +func (s *Swagger) FindExtension(ext string) *low.ValueReference[any] { + return low.FindItemInMap[any](ext, s.Extensions) +} + +// GetExtensions returns all Swagger/Top level extensions and satisfies the low.HasExtensions interface. +func (s *Swagger) GetExtensions() map[low.KeyReference[string]]low.ValueReference[any] { + return s.Extensions +} + +// CreateDocumentFromConfig will create a new Swagger document from the provided SpecInfo and DocumentConfiguration. +func CreateDocumentFromConfig(info *datamodel.SpecInfo, + configuration *datamodel.DocumentConfiguration) (*Swagger, []error) { + return createDocument(info, configuration) +} + +// CreateDocument will create a new Swagger document from the provided SpecInfo. +// +// Deprecated: Use CreateDocumentFromConfig instead. +func CreateDocument(info *datamodel.SpecInfo) (*Swagger, []error) { + return createDocument(info, &datamodel.DocumentConfiguration{ + AllowRemoteReferences: true, + AllowFileReferences: true, + }) +} + +func createDocument(info *datamodel.SpecInfo, config *datamodel.DocumentConfiguration) (*Swagger, []error) { + doc := Swagger{Swagger: low.ValueReference[string]{Value: info.Version, ValueNode: info.RootNode}} + doc.Extensions = low.ExtractExtensions(info.RootNode.Content[0]) + + // build an index + idx := index.NewSpecIndexWithConfig(info.RootNode, &index.SpecIndexConfig{ + BaseURL: config.BaseURL, + AllowRemoteLookup: config.AllowRemoteReferences, + AllowFileLookup: config.AllowFileReferences, + }) + doc.Index = idx + doc.SpecInfo = info + + var errors []error + + // build out swagger scalar variables. + _ = low.BuildModel(info.RootNode.Content[0], &doc) + + // extract externalDocs + extDocs, err := low.ExtractObject[*base.ExternalDoc](base.ExternalDocsLabel, info.RootNode, idx) + if err != nil { + errors = append(errors, err) + } + + doc.ExternalDocs = extDocs + + // create resolver and check for circular references. + resolve := resolver.NewResolver(idx) + resolvingErrors := resolve.CheckForCircularReferences() + + if len(resolvingErrors) > 0 { + for r := range resolvingErrors { + errors = append(errors, resolvingErrors[r]) + } + } + + extractionFuncs := []documentFunction{ + extractInfo, + extractPaths, + extractDefinitions, + extractParamDefinitions, + extractResponsesDefinitions, + extractSecurityDefinitions, + extractTags, + extractSecurity, + } + doneChan := make(chan bool) + errChan := make(chan error) + for i := range extractionFuncs { + go extractionFuncs[i](info.RootNode.Content[0], &doc, idx, doneChan, errChan) + } + completedExtractions := 0 + for completedExtractions < len(extractionFuncs) { + select { + case <-doneChan: + completedExtractions++ + case e := <-errChan: + completedExtractions++ + errors = append(errors, e) + } + } + + return &doc, errors +} + +func (s *Swagger) GetExternalDocs() *low.NodeReference[any] { + return &low.NodeReference[any]{ + KeyNode: s.ExternalDocs.KeyNode, + ValueNode: s.ExternalDocs.ValueNode, + Value: s.ExternalDocs.Value, + } +} + +func extractInfo(root *yaml.Node, doc *Swagger, idx *index.SpecIndex, c chan<- bool, e chan<- error) { + info, err := low.ExtractObject[*base.Info](base.InfoLabel, root, idx) + if err != nil { + e <- err + return + } + doc.Info = info + c <- true +} + +func extractPaths(root *yaml.Node, doc *Swagger, idx *index.SpecIndex, c chan<- bool, e chan<- error) { + paths, err := low.ExtractObject[*Paths](PathsLabel, root, idx) + if err != nil { + e <- err + return + } + doc.Paths = paths + c <- true +} +func extractDefinitions(root *yaml.Node, doc *Swagger, idx *index.SpecIndex, c chan<- bool, e chan<- error) { + def, err := low.ExtractObject[*Definitions](DefinitionsLabel, root, idx) + if err != nil { + e <- err + return + } + doc.Definitions = def + c <- true +} +func extractParamDefinitions(root *yaml.Node, doc *Swagger, idx *index.SpecIndex, c chan<- bool, e chan<- error) { + param, err := low.ExtractObject[*ParameterDefinitions](ParametersLabel, root, idx) + if err != nil { + e <- err + return + } + doc.Parameters = param + c <- true +} + +func extractResponsesDefinitions(root *yaml.Node, doc *Swagger, idx *index.SpecIndex, c chan<- bool, e chan<- error) { + resp, err := low.ExtractObject[*ResponsesDefinitions](ResponsesLabel, root, idx) + if err != nil { + e <- err + return + } + doc.Responses = resp + c <- true +} + +func extractSecurityDefinitions(root *yaml.Node, doc *Swagger, idx *index.SpecIndex, c chan<- bool, e chan<- error) { + sec, err := low.ExtractObject[*SecurityDefinitions](SecurityDefinitionsLabel, root, idx) + if err != nil { + e <- err + return + } + doc.SecurityDefinitions = sec + c <- true +} + +func extractTags(root *yaml.Node, doc *Swagger, idx *index.SpecIndex, c chan<- bool, e chan<- error) { + tags, ln, vn, err := low.ExtractArray[*base.Tag](base.TagsLabel, root, idx) + if err != nil { + e <- err + return + } + doc.Tags = low.NodeReference[[]low.ValueReference[*base.Tag]]{ + Value: tags, + KeyNode: ln, + ValueNode: vn, + } + c <- true +} + +func extractSecurity(root *yaml.Node, doc *Swagger, idx *index.SpecIndex, c chan<- bool, e chan<- error) { + sec, ln, vn, err := low.ExtractArray[*base.SecurityRequirement](SecurityLabel, root, idx) + if err != nil { + e <- err + return + } + doc.Security = low.NodeReference[[]low.ValueReference[*base.SecurityRequirement]]{ + Value: sec, + KeyNode: ln, + ValueNode: vn, + } + c <- true +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/low/v3/callback.go b/vendor/github.com/pb33f/libopenapi/datamodel/low/v3/callback.go new file mode 100644 index 0000000000..483ddbb08c --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/low/v3/callback.go @@ -0,0 +1,101 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package v3 + +import ( + "crypto/sha256" + "fmt" + "github.com/pb33f/libopenapi/datamodel/low" + "github.com/pb33f/libopenapi/index" + "gopkg.in/yaml.v3" + "sort" + "strings" +) + +// Callback represents a low-level Callback object for OpenAPI 3+. +// +// A map of possible out-of band callbacks related to the parent operation. Each value in the map is a +// PathItem Object that describes a set of requests that may be initiated by the API provider and the expected +// responses. The key value used to identify the path item object is an expression, evaluated at runtime, +// that identifies a URL to use for the callback operation. +// - https://spec.openapis.org/oas/v3.1.0#callback-object +type Callback struct { + Expression low.ValueReference[map[low.KeyReference[string]]low.ValueReference[*PathItem]] + Extensions map[low.KeyReference[string]]low.ValueReference[any] + *low.Reference +} + +// GetExtensions returns all Callback extensions and satisfies the low.HasExtensions interface. +func (cb *Callback) GetExtensions() map[low.KeyReference[string]]low.ValueReference[any] { + return cb.Extensions +} + +// FindExpression will locate a string expression and return a ValueReference containing the located PathItem +func (cb *Callback) FindExpression(exp string) *low.ValueReference[*PathItem] { + return low.FindItemInMap[*PathItem](exp, cb.Expression.Value) +} + +// Build will extract extensions, expressions and PathItem objects for Callback +func (cb *Callback) Build(root *yaml.Node, idx *index.SpecIndex) error { + cb.Reference = new(low.Reference) + cb.Extensions = low.ExtractExtensions(root) + + // handle callback + var currentCB *yaml.Node + callbacks := make(map[low.KeyReference[string]]low.ValueReference[*PathItem]) + + for i, callbackNode := range root.Content { + if i%2 == 0 { + currentCB = callbackNode + continue + } + if strings.HasPrefix(currentCB.Value, "x-") { + continue // ignore extension. + } + callback, eErr, _, rv := low.ExtractObjectRaw[*PathItem](callbackNode, idx) + if eErr != nil { + return eErr + } + callbacks[low.KeyReference[string]{ + Value: currentCB.Value, + KeyNode: currentCB, + }] = low.ValueReference[*PathItem]{ + Value: callback, + ValueNode: callbackNode, + Reference: rv, + } + } + if len(callbacks) > 0 { + cb.Expression = low.ValueReference[map[low.KeyReference[string]]low.ValueReference[*PathItem]]{ + Value: callbacks, + ValueNode: root, + } + } + return nil +} + +// Hash will return a consistent SHA256 Hash of the Callback object +func (cb *Callback) Hash() [32]byte { + var f []string + var keys []string + keys = make([]string, len(cb.Expression.Value)) + z := 0 + for k := range cb.Expression.Value { + keys[z] = low.GenerateHashString(cb.Expression.Value[k].Value) + z++ + } + sort.Strings(keys) + f = append(f, keys...) + + keys = make([]string, len(cb.Extensions)) + z = 0 + for k := range cb.Extensions { + keys[z] = fmt.Sprintf("%s-%x", k.Value, sha256.Sum256([]byte(fmt.Sprint(cb.Extensions[k].Value)))) + z++ + } + sort.Strings(keys) + f = append(f, keys...) + + return sha256.Sum256([]byte(strings.Join(f, "|"))) +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/low/v3/components.go b/vendor/github.com/pb33f/libopenapi/datamodel/low/v3/components.go new file mode 100644 index 0000000000..05d52952f9 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/low/v3/components.go @@ -0,0 +1,284 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package v3 + +import ( + "crypto/sha256" + "fmt" + "github.com/pb33f/libopenapi/datamodel/low" + "github.com/pb33f/libopenapi/datamodel/low/base" + "github.com/pb33f/libopenapi/index" + "github.com/pb33f/libopenapi/utils" + "gopkg.in/yaml.v3" + "sort" + "strings" +) + +// Components represents a low-level OpenAPI 3+ Components Object, that is backed by a low-level one. +// +// Holds a set of reusable objects for different aspects of the OAS. All objects defined within the components object +// will have no effect on the API unless they are explicitly referenced from properties outside the components object. +// - https://spec.openapis.org/oas/v3.1.0#components-object +type Components struct { + Schemas low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*base.SchemaProxy]] + Responses low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*Response]] + Parameters low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*Parameter]] + Examples low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*base.Example]] + RequestBodies low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*RequestBody]] + Headers low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*Header]] + SecuritySchemes low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*SecurityScheme]] + Links low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*Link]] + Callbacks low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*Callback]] + Extensions map[low.KeyReference[string]]low.ValueReference[any] + *low.Reference +} + +// GetExtensions returns all Components extensions and satisfies the low.HasExtensions interface. +func (co *Components) GetExtensions() map[low.KeyReference[string]]low.ValueReference[any] { + return co.Extensions +} + +// Hash will return a consistent SHA256 Hash of the Encoding object +func (co *Components) Hash() [32]byte { + var f []string + generateHashForObjectMap(co.Schemas.Value, &f) + generateHashForObjectMap(co.Responses.Value, &f) + generateHashForObjectMap(co.Parameters.Value, &f) + generateHashForObjectMap(co.Examples.Value, &f) + generateHashForObjectMap(co.RequestBodies.Value, &f) + generateHashForObjectMap(co.Headers.Value, &f) + generateHashForObjectMap(co.SecuritySchemes.Value, &f) + generateHashForObjectMap(co.Links.Value, &f) + generateHashForObjectMap(co.Callbacks.Value, &f) + keys := make([]string, len(co.Extensions)) + z := 0 + for k := range co.Extensions { + keys[z] = fmt.Sprintf("%s-%x", k.Value, sha256.Sum256([]byte(fmt.Sprint(co.Extensions[k].Value)))) + z++ + } + sort.Strings(keys) + f = append(f, keys...) + return sha256.Sum256([]byte(strings.Join(f, "|"))) +} + +func generateHashForObjectMap[T any](collection map[low.KeyReference[string]]low.ValueReference[T], hash *[]string) { + if collection == nil { + return + } + l := make([]string, len(collection)) + keys := make(map[string]low.ValueReference[T]) + z := 0 + for k := range collection { + keys[k.Value] = collection[k] + l[z] = k.Value + z++ + } + sort.Strings(l) + for k := range l { + *hash = append(*hash, low.GenerateHashString(keys[l[k]].Value)) + } +} + +// FindExtension attempts to locate an extension with the supplied key +func (co *Components) FindExtension(ext string) *low.ValueReference[any] { + return low.FindItemInMap[any](ext, co.Extensions) +} + +// FindSchema attempts to locate a SchemaProxy from 'schemas' with a specific name +func (co *Components) FindSchema(schema string) *low.ValueReference[*base.SchemaProxy] { + return low.FindItemInMap[*base.SchemaProxy](schema, co.Schemas.Value) +} + +// FindResponse attempts to locate a Response from 'responses' with a specific name +func (co *Components) FindResponse(response string) *low.ValueReference[*Response] { + return low.FindItemInMap[*Response](response, co.Responses.Value) +} + +// FindParameter attempts to locate a Parameter from 'parameters' with a specific name +func (co *Components) FindParameter(response string) *low.ValueReference[*Parameter] { + return low.FindItemInMap[*Parameter](response, co.Parameters.Value) +} + +// FindSecurityScheme attempts to locate a SecurityScheme from 'securitySchemes' with a specific name +func (co *Components) FindSecurityScheme(sScheme string) *low.ValueReference[*SecurityScheme] { + return low.FindItemInMap[*SecurityScheme](sScheme, co.SecuritySchemes.Value) +} + +// FindExample attempts tp +func (co *Components) FindExample(example string) *low.ValueReference[*base.Example] { + return low.FindItemInMap[*base.Example](example, co.Examples.Value) +} + +func (co *Components) FindRequestBody(requestBody string) *low.ValueReference[*RequestBody] { + return low.FindItemInMap[*RequestBody](requestBody, co.RequestBodies.Value) +} + +func (co *Components) FindHeader(header string) *low.ValueReference[*Header] { + return low.FindItemInMap[*Header](header, co.Headers.Value) +} + +func (co *Components) FindLink(link string) *low.ValueReference[*Link] { + return low.FindItemInMap[*Link](link, co.Links.Value) +} + +func (co *Components) FindCallback(callback string) *low.ValueReference[*Callback] { + return low.FindItemInMap[*Callback](callback, co.Callbacks.Value) +} + +func (co *Components) Build(root *yaml.Node, idx *index.SpecIndex) error { + co.Reference = new(low.Reference) + co.Extensions = low.ExtractExtensions(root) + + // build out components asynchronously for speed. There could be some significant weight here. + skipChan := make(chan bool) + errorChan := make(chan error) + paramChan := make(chan low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*Parameter]]) + schemaChan := make(chan low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*base.SchemaProxy]]) + responsesChan := make(chan low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*Response]]) + examplesChan := make(chan low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*base.Example]]) + requestBodiesChan := make(chan low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*RequestBody]]) + headersChan := make(chan low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*Header]]) + securitySchemesChan := make(chan low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*SecurityScheme]]) + linkChan := make(chan low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*Link]]) + callbackChan := make(chan low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*Callback]]) + + go extractComponentValues[*base.SchemaProxy](SchemasLabel, root, skipChan, errorChan, schemaChan, idx) + go extractComponentValues[*Parameter](ParametersLabel, root, skipChan, errorChan, paramChan, idx) + go extractComponentValues[*Response](ResponsesLabel, root, skipChan, errorChan, responsesChan, idx) + go extractComponentValues[*base.Example](base.ExamplesLabel, root, skipChan, errorChan, examplesChan, idx) + go extractComponentValues[*RequestBody](RequestBodiesLabel, root, skipChan, errorChan, requestBodiesChan, idx) + go extractComponentValues[*Header](HeadersLabel, root, skipChan, errorChan, headersChan, idx) + go extractComponentValues[*SecurityScheme](SecuritySchemesLabel, root, skipChan, errorChan, securitySchemesChan, idx) + go extractComponentValues[*Link](LinksLabel, root, skipChan, errorChan, linkChan, idx) + go extractComponentValues[*Callback](CallbacksLabel, root, skipChan, errorChan, callbackChan, idx) + + n := 0 + total := 9 + + for n < total { + select { + case buildError := <-errorChan: + return buildError + case <-skipChan: + n++ + case params := <-paramChan: + co.Parameters = params + n++ + case schemas := <-schemaChan: + co.Schemas = schemas + n++ + case responses := <-responsesChan: + co.Responses = responses + n++ + case examples := <-examplesChan: + co.Examples = examples + n++ + case reqBody := <-requestBodiesChan: + co.RequestBodies = reqBody + n++ + case headers := <-headersChan: + co.Headers = headers + n++ + case sScheme := <-securitySchemesChan: + co.SecuritySchemes = sScheme + n++ + case links := <-linkChan: + co.Links = links + n++ + case callbacks := <-callbackChan: + co.Callbacks = callbacks + n++ + } + } + return nil +} + +type componentBuildResult[T any] struct { + k low.KeyReference[string] + v low.ValueReference[T] +} + +func extractComponentValues[T low.Buildable[N], N any](label string, root *yaml.Node, + skip chan bool, errorChan chan<- error, resultChan chan<- low.NodeReference[map[low.KeyReference[string]]low.ValueReference[T]], idx *index.SpecIndex) { + _, nodeLabel, nodeValue := utils.FindKeyNodeFullTop(label, root.Content) + if nodeValue == nil { + skip <- true + return + } + var currentLabel *yaml.Node + componentValues := make(map[low.KeyReference[string]]low.ValueReference[T]) + if utils.IsNodeArray(nodeValue) { + errorChan <- fmt.Errorf("node is array, cannot be used in components: line %d, column %d", nodeValue.Line, nodeValue.Column) + return + } + + // for every component, build in a new thread! + bChan := make(chan componentBuildResult[T]) + eChan := make(chan error) + var buildComponent = func(parentLabel string, label *yaml.Node, value *yaml.Node, c chan componentBuildResult[T], ec chan<- error) { + var n T = new(N) + + // if this is a reference, extract it (although components with references is an antipattern) + // If you're building components as references... pls... stop, this code should not need to be here. + // TODO: check circular crazy on this. It may explode + var err error + if h, _, _ := utils.IsNodeRefValue(value); h && parentLabel != SchemasLabel { + value, err = low.LocateRefNode(value, idx) + } + if err != nil { + ec <- err + return + } + + // build. + _ = low.BuildModel(value, n) + err = n.Build(value, idx) + if err != nil { + ec <- err + return + } + c <- componentBuildResult[T]{ + k: low.KeyReference[string]{ + KeyNode: label, + Value: label.Value, + }, + v: low.ValueReference[T]{ + Value: n, + ValueNode: value, + }, + } + } + totalComponents := 0 + for i, v := range nodeValue.Content { + // always ignore extensions + if i%2 == 0 { + currentLabel = v + continue + } + // only check for lowercase extensions as 'X-' is still valid as a key (annoyingly). + if strings.HasPrefix(currentLabel.Value, "x-") { + continue + } + totalComponents++ + go buildComponent(label, currentLabel, v, bChan, eChan) + } + + completedComponents := 0 + for completedComponents < totalComponents { + select { + case e := <-eChan: + errorChan <- e + case r := <-bChan: + componentValues[r.k] = r.v + completedComponents++ + } + } + + results := low.NodeReference[map[low.KeyReference[string]]low.ValueReference[T]]{ + KeyNode: nodeLabel, + ValueNode: nodeValue, + Value: componentValues, + } + resultChan <- results +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/low/v3/constants.go b/vendor/github.com/pb33f/libopenapi/datamodel/low/v3/constants.go new file mode 100644 index 0000000000..14740d66ed --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/low/v3/constants.go @@ -0,0 +1,140 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package v3 + +// Label definitions used to look up vales in yaml.Node tree. +const ( + ComponentsLabel = "components" + SchemasLabel = "schemas" + EncodingLabel = "encoding" + HeadersLabel = "headers" + ExpressionLabel = "expression" + InfoLabel = "info" + SwaggerLabel = "swagger" + ParametersLabel = "parameters" + RequestBodyLabel = "requestBody" + RequestBodiesLabel = "requestBodies" + ResponsesLabel = "responses" + CallbacksLabel = "callbacks" + ContentLabel = "content" + PathsLabel = "paths" + PathLabel = "path" + WebhooksLabel = "webhooks" + JSONSchemaDialectLabel = "jsonSchemaDialect" + JSONSchemaLabel = "$schema" + GetLabel = "get" + PostLabel = "post" + PatchLabel = "patch" + PutLabel = "put" + DeleteLabel = "delete" + OptionsLabel = "options" + HeadLabel = "head" + TraceLabel = "trace" + LinksLabel = "links" + DefaultLabel = "default" + SecurityLabel = "security" + SecuritySchemesLabel = "securitySchemes" + OAuthFlowsLabel = "flows" + VariablesLabel = "variables" + ServersLabel = "servers" + ServerLabel = "server" + ImplicitLabel = "implicit" + PasswordLabel = "password" + ClientCredentialsLabel = "clientCredentials" + AuthorizationCodeLabel = "authorizationCode" + DescriptionLabel = "description" + URLLabel = "url" + NameLabel = "name" + EmailLabel = "email" + TitleLabel = "title" + TermsOfServiceLabel = "termsOfService" + VersionLabel = "version" + OpenAPILabel = "openapi" + HostLabel = "host" + BasePathLabel = "basePath" + LicenseLabel = "license" + ContactLabel = "contact" + NamespaceLabel = "namespace" + PrefixLabel = "prefix" + AttributeLabel = "attribute" + WrappedLabel = "wrapped" + PropertyNameLabel = "propertyName" + SummaryLabel = "summary" + ValueLabel = "value" + ExternalValue = "externalValue" + SchemaDialectLabel = "$schema" + ExclusiveMaximumLabel = "exclusiveMaximum" + ExclusiveMinimumLabel = "exclusiveMinimum" + TypeLabel = "type" + TagsLabel = "tags" + MultipleOfLabel = "multipleOf" + MaximumLabel = "maximum" + MinimumLabel = "minimum" + MaxLengthLabel = "maxLength" + MinLengthLabel = "minLength" + PatternLabel = "pattern" + FormatLabel = "format" + MaxItemsLabel = "maxItems" + ExamplesLabel = "examples" + MinItemsLabel = "minItems" + UniqueItemsLabel = "uniqueItems" + MaxPropertiesLabel = "maxProperties" + MinPropertiesLabel = "minProperties" + RequiredLabel = "required" + EnumLabel = "enum" + SchemaLabel = "schema" + NotLabel = "not" + ItemsLabel = "items" + PropertiesLabel = "properties" + AllOfLabel = "allOf" + AnyOfLabel = "anyOf" + OneOfLabel = "oneOf" + AdditionalPropertiesLabel = "additionalProperties" + ContentEncodingLabel = "contentEncoding" + ContentMediaType = "contentMediaType" + NullableLabel = "nullable" + ReadOnlyLabel = "readOnly" + WriteOnlyLabel = "writeOnly" + XMLLabel = "xml" + DeprecatedLabel = "deprecated" + ExampleLabel = "example" + RefLabel = "$ref" + DiscriminatorLabel = "discriminator" + ExternalDocsLabel = "externalDocs" + InLabel = "in" + AllowEmptyValueLabel = "allowEmptyValue" + StyleLabel = "style" + CollectionFormatLabel = "collectionFormat" + AllowReservedLabel = "allowReserved" + ExplodeLabel = "explode" + ContentTypeLabel = "contentType" + SecurityDefinitionLabel = "securityDefinition" + Scopes = "scopes" + AuthorizationUrlLabel = "authorizationUrl" + TokenUrlLabel = "tokenUrl" + RefreshUrlLabel = "refreshUrl" + FlowLabel = "flow" + FlowsLabel = "flows" + SchemeLabel = "scheme" + OpenIdConnectUrlLabel = "openIdConnectUrl" + ScopesLabel = "scopes" + OperationRefLabel = "operationRef" + OperationIdLabel = "operationId" + CodesLabel = "codes" + ProducesLabel = "produces" + ConsumesLabel = "consumes" + SchemesLabel = "schemes" + IfLabel = "if" + ElseLabel = "else" + ThenLabel = "then" + PropertyNamesLabel = "propertyNames" + ContainsLabel = "contains" + MinContainsLabel = "minContains" + MaxContainsLabel = "maxContains" + UnevaluatedItemsLabel = "unevaluatedItems" + UnevaluatedPropertiesLabel = "unevaluatedProperties" + DependentSchemasLabel = "dependentSchemas" + PatternPropertiesLabel = "patternProperties" + AnchorLabel = "$anchor" +) diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/low/v3/create_document.go b/vendor/github.com/pb33f/libopenapi/datamodel/low/v3/create_document.go new file mode 100644 index 0000000000..9b6724c9a5 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/low/v3/create_document.go @@ -0,0 +1,245 @@ +package v3 + +import ( + "errors" + "os" + "sync" + + "github.com/pb33f/libopenapi/datamodel" + "github.com/pb33f/libopenapi/datamodel/low" + "github.com/pb33f/libopenapi/datamodel/low/base" + "github.com/pb33f/libopenapi/index" + "github.com/pb33f/libopenapi/resolver" + "github.com/pb33f/libopenapi/utils" +) + +// CreateDocument will create a new Document instance from the provided SpecInfo. +// +// Deprecated: Use CreateDocumentFromConfig instead. This function will be removed in a later version, it +// defaults to allowing file and remote references, and does not support relative file references. +func CreateDocument(info *datamodel.SpecInfo) (*Document, []error) { + config := datamodel.DocumentConfiguration{ + AllowFileReferences: true, + AllowRemoteReferences: true, + } + return createDocument(info, &config) +} + +// CreateDocumentFromConfig Create a new document from the provided SpecInfo and DocumentConfiguration pointer. +func CreateDocumentFromConfig(info *datamodel.SpecInfo, config *datamodel.DocumentConfiguration) (*Document, []error) { + return createDocument(info, config) +} + +func createDocument(info *datamodel.SpecInfo, config *datamodel.DocumentConfiguration) (*Document, []error) { + _, labelNode, versionNode := utils.FindKeyNodeFull(OpenAPILabel, info.RootNode.Content) + var version low.NodeReference[string] + if versionNode == nil { + return nil, []error{errors.New("no openapi version/tag found, cannot create document")} + } + version = low.NodeReference[string]{Value: versionNode.Value, KeyNode: labelNode, ValueNode: versionNode} + doc := Document{Version: version} + + // get current working directory as a basePath + cwd, _ := os.Getwd() + + // If basePath is provided override it + if config.BasePath != "" { + cwd = config.BasePath + } + // build an index + idx := index.NewSpecIndexWithConfig(info.RootNode, &index.SpecIndexConfig{ + BaseURL: config.BaseURL, + BasePath: cwd, + AllowFileLookup: config.AllowFileReferences, + AllowRemoteLookup: config.AllowRemoteReferences, + }) + doc.Index = idx + + var errs []error + + errs = idx.GetReferenceIndexErrors() + + // create resolver and check for circular references. + resolve := resolver.NewResolver(idx) + resolvingErrors := resolve.CheckForCircularReferences() + + if len(resolvingErrors) > 0 { + for r := range resolvingErrors { + errs = append(errs, resolvingErrors[r]) + } + } + + var wg sync.WaitGroup + + doc.Extensions = low.ExtractExtensions(info.RootNode.Content[0]) + + // if set, extract jsonSchemaDialect (3.1) + _, dialectLabel, dialectNode := utils.FindKeyNodeFull(JSONSchemaDialectLabel, info.RootNode.Content) + if dialectNode != nil { + doc.JsonSchemaDialect = low.NodeReference[string]{ + Value: dialectNode.Value, KeyNode: dialectLabel, ValueNode: dialectNode, + } + } + + runExtraction := func(info *datamodel.SpecInfo, doc *Document, idx *index.SpecIndex, + runFunc func(i *datamodel.SpecInfo, d *Document, idx *index.SpecIndex) error, + ers *[]error, + wg *sync.WaitGroup, + ) { + if er := runFunc(info, doc, idx); er != nil { + *ers = append(*ers, er) + } + wg.Done() + } + extractionFuncs := []func(i *datamodel.SpecInfo, d *Document, idx *index.SpecIndex) error{ + extractInfo, + extractServers, + extractTags, + extractComponents, + extractSecurity, + extractExternalDocs, + extractPaths, + extractWebhooks, + } + + wg.Add(len(extractionFuncs)) + for _, f := range extractionFuncs { + go runExtraction(info, &doc, idx, f, &errs, &wg) + } + wg.Wait() + return &doc, errs +} + +func extractInfo(info *datamodel.SpecInfo, doc *Document, idx *index.SpecIndex) error { + _, ln, vn := utils.FindKeyNodeFullTop(base.InfoLabel, info.RootNode.Content[0].Content) + if vn != nil { + ir := base.Info{} + _ = low.BuildModel(vn, &ir) + _ = ir.Build(vn, idx) + nr := low.NodeReference[*base.Info]{Value: &ir, ValueNode: vn, KeyNode: ln} + doc.Info = nr + } + return nil +} + +func extractSecurity(info *datamodel.SpecInfo, doc *Document, idx *index.SpecIndex) error { + sec, ln, vn, err := low.ExtractArray[*base.SecurityRequirement](SecurityLabel, info.RootNode.Content[0], idx) + if err != nil { + return err + } + if vn != nil && ln != nil { + doc.Security = low.NodeReference[[]low.ValueReference[*base.SecurityRequirement]]{ + Value: sec, + KeyNode: ln, + ValueNode: vn, + } + } + return nil +} + +func extractExternalDocs(info *datamodel.SpecInfo, doc *Document, idx *index.SpecIndex) error { + extDocs, dErr := low.ExtractObject[*base.ExternalDoc](base.ExternalDocsLabel, info.RootNode.Content[0], idx) + if dErr != nil { + return dErr + } + doc.ExternalDocs = extDocs + return nil +} + +func extractComponents(info *datamodel.SpecInfo, doc *Document, idx *index.SpecIndex) error { + _, ln, vn := utils.FindKeyNodeFullTop(ComponentsLabel, info.RootNode.Content[0].Content) + if vn != nil { + ir := Components{} + _ = low.BuildModel(vn, &ir) + err := ir.Build(vn, idx) + if err != nil { + return err + } + nr := low.NodeReference[*Components]{Value: &ir, ValueNode: vn, KeyNode: ln} + doc.Components = nr + } + return nil +} + +func extractServers(info *datamodel.SpecInfo, doc *Document, idx *index.SpecIndex) error { + _, ln, vn := utils.FindKeyNodeFull(ServersLabel, info.RootNode.Content[0].Content) + if vn != nil { + if utils.IsNodeArray(vn) { + var servers []low.ValueReference[*Server] + for _, srvN := range vn.Content { + if utils.IsNodeMap(srvN) { + srvr := Server{} + _ = low.BuildModel(srvN, &srvr) + _ = srvr.Build(srvN, idx) + servers = append(servers, low.ValueReference[*Server]{ + Value: &srvr, + ValueNode: srvN, + }) + } + } + doc.Servers = low.NodeReference[[]low.ValueReference[*Server]]{ + Value: servers, + KeyNode: ln, + ValueNode: vn, + } + } + } + return nil +} + +func extractTags(info *datamodel.SpecInfo, doc *Document, idx *index.SpecIndex) error { + _, ln, vn := utils.FindKeyNodeFull(base.TagsLabel, info.RootNode.Content[0].Content) + if vn != nil { + if utils.IsNodeArray(vn) { + var tags []low.ValueReference[*base.Tag] + for _, tagN := range vn.Content { + if utils.IsNodeMap(tagN) { + tag := base.Tag{} + _ = low.BuildModel(tagN, &tag) + if err := tag.Build(tagN, idx); err != nil { + return err + } + tags = append(tags, low.ValueReference[*base.Tag]{ + Value: &tag, + ValueNode: tagN, + }) + } + } + doc.Tags = low.NodeReference[[]low.ValueReference[*base.Tag]]{ + Value: tags, + KeyNode: ln, + ValueNode: vn, + } + } + } + return nil +} + +func extractPaths(info *datamodel.SpecInfo, doc *Document, idx *index.SpecIndex) error { + _, ln, vn := utils.FindKeyNodeFull(PathsLabel, info.RootNode.Content[0].Content) + if vn != nil { + ir := Paths{} + err := ir.Build(vn, idx) + if err != nil { + return err + } + nr := low.NodeReference[*Paths]{Value: &ir, ValueNode: vn, KeyNode: ln} + doc.Paths = nr + } + return nil +} + +func extractWebhooks(info *datamodel.SpecInfo, doc *Document, idx *index.SpecIndex) error { + hooks, hooksL, hooksN, eErr := low.ExtractMap[*PathItem](WebhooksLabel, info.RootNode, idx) + if eErr != nil { + return eErr + } + if hooks != nil { + doc.Webhooks = low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*PathItem]]{ + Value: hooks, + KeyNode: hooksL, + ValueNode: hooksN, + } + } + return nil +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/low/v3/document.go b/vendor/github.com/pb33f/libopenapi/datamodel/low/v3/document.go new file mode 100644 index 0000000000..231b639f32 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/low/v3/document.go @@ -0,0 +1,125 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +// Package v3 represents all OpenAPI 3+ low-level models. Low-level models are more difficult to navigate +// than higher-level models, however they are packed with all the raw AST and node data required to perform +// any kind of analysis on the underlying data. +// +// Every property is wrapped in a NodeReference or a KeyReference or a ValueReference. +package v3 + +import ( + "github.com/pb33f/libopenapi/datamodel/low" + "github.com/pb33f/libopenapi/datamodel/low/base" + "github.com/pb33f/libopenapi/index" +) + +type Document struct { + + // Version is the version of OpenAPI being used, extracted from the 'openapi: x.x.x' definition. + // This is not a standard property of the OpenAPI model, it's a convenience mechanism only. + Version low.NodeReference[string] + + // Info represents a specification Info definitions + // Provides metadata about the API. The metadata MAY be used by tooling as required. + // - https://spec.openapis.org/oas/v3.1.0#info-object + Info low.NodeReference[*base.Info] + + // JsonSchemaDialect is a 3.1+ property that sets the dialect to use for validating *base.Schema definitions + // The default value for the $schema keyword within Schema Objects contained within this OAS document. + // This MUST be in the form of a URI. + // - https://spec.openapis.org/oas/v3.1.0#schema-object + JsonSchemaDialect low.NodeReference[string] // 3.1 + + // Webhooks is a 3.1+ property that is similar to callbacks, except, this defines incoming webhooks. + // The incoming webhooks that MAY be received as part of this API and that the API consumer MAY choose to implement. + // Closely related to the callbacks feature, this section describes requests initiated other than by an API call, + // for example by an out-of-band registration. The key name is a unique string to refer to each webhook, + // while the (optionally referenced) Path Item Object describes a request that may be initiated by the API provider + // and the expected responses. An example is available. + Webhooks low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*PathItem]] // 3.1 + + // Servers is a slice of Server instances which provide connectivity information to a target server. If the servers + // property is not provided, or is an empty array, the default value would be a Server Object with an url value of /. + // - https://spec.openapis.org/oas/v3.1.0#server-object + Servers low.NodeReference[[]low.ValueReference[*Server]] + + // Paths contains all the PathItem definitions for the specification. + // The available paths and operations for the API, The most important part of ths spec. + // - https://spec.openapis.org/oas/v3.1.0#paths-object + Paths low.NodeReference[*Paths] + + // Components is an element to hold various schemas for the document. + // - https://spec.openapis.org/oas/v3.1.0#components-object + Components low.NodeReference[*Components] + + // Security contains global security requirements/roles for the specification + // A declaration of which security mechanisms can be used across the API. The list of values includes alternative + // security requirement objects that can be used. Only one of the security requirement objects need to be satisfied + // to authorize a request. Individual operations can override this definition. To make security optional, + // an empty security requirement ({}) can be included in the array. + // - https://spec.openapis.org/oas/v3.1.0#security-requirement-object + Security low.NodeReference[[]low.ValueReference[*base.SecurityRequirement]] + + // Tags is a slice of base.Tag instances defined by the specification + // A list of tags used by the document with additional metadata. The order of the tags can be used to reflect on + // their order by the parsing tools. Not all tags that are used by the Operation Object must be declared. + // The tags that are not declared MAY be organized randomly or based on the tools’ logic. + // Each tag name in the list MUST be unique. + // - https://spec.openapis.org/oas/v3.1.0#tag-object + Tags low.NodeReference[[]low.ValueReference[*base.Tag]] + + // ExternalDocs is an instance of base.ExternalDoc for.. well, obvious really, innit. + // - https://spec.openapis.org/oas/v3.1.0#external-documentation-object + ExternalDocs low.NodeReference[*base.ExternalDoc] + + // Extensions contains all custom extensions defined for the top-level document. + Extensions map[low.KeyReference[string]]low.ValueReference[any] + + // Index is a reference to the *index.SpecIndex that was created for the document and used + // as a guide when building out the Document. Ideal if further processing is required on the model and + // the original details are required to continue the work. + // + // This property is not a part of the OpenAPI schema, this is custom to libopenapi. + Index *index.SpecIndex +} + +// FindSecurityRequirement will attempt to locate a security requirement string from a supplied name. +func (d *Document) FindSecurityRequirement(name string) []low.ValueReference[string] { + for k := range d.Security.Value { + for i := range d.Security.Value[k].Value.Requirements.Value { + if i.Value == name { + return d.Security.Value[k].Value.Requirements.Value[i].Value + } + } + } + return nil +} + +// GetExtensions returns all Document extensions and satisfies the low.HasExtensions interface. +func (d *Document) GetExtensions() map[low.KeyReference[string]]low.ValueReference[any] { + return d.Extensions +} + +func (d *Document) GetExternalDocs() *low.NodeReference[any] { + return &low.NodeReference[any]{ + KeyNode: d.ExternalDocs.KeyNode, + ValueNode: d.ExternalDocs.ValueNode, + Value: d.ExternalDocs.Value, + } +} + +// TODO: this is early prototype mutation/modification code, keeping it around for later. +//func (d *Document) AddTag() *base.Tag { +// t := base.NewTag() +// //d.Tags.KeyNode +// t.Name.Value = "nice new tag" +// +// dat, _ := yaml.Marshal(t) +// var inject yaml.Node +// _ = yaml.Unmarshal(dat, &inject) +// +// d.Tags.ValueNode.Content = append(d.Tags.ValueNode.Content, inject.Content[0]) +// +// return t +//} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/low/v3/encoding.go b/vendor/github.com/pb33f/libopenapi/datamodel/low/v3/encoding.go new file mode 100644 index 0000000000..e9a5d08100 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/low/v3/encoding.go @@ -0,0 +1,74 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package v3 + +import ( + "crypto/sha256" + "fmt" + "github.com/pb33f/libopenapi/datamodel/low" + "github.com/pb33f/libopenapi/index" + "gopkg.in/yaml.v3" + "strings" +) + +// Encoding represents a low-level OpenAPI 3+ Encoding object +// - https://spec.openapis.org/oas/v3.1.0#encoding-object +type Encoding struct { + ContentType low.NodeReference[string] + Headers low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*Header]] + Style low.NodeReference[string] + Explode low.NodeReference[bool] + AllowReserved low.NodeReference[bool] + *low.Reference +} + +// FindHeader attempts to locate a Header with the supplied name +func (en *Encoding) FindHeader(hType string) *low.ValueReference[*Header] { + return low.FindItemInMap[*Header](hType, en.Headers.Value) +} + +// Hash will return a consistent SHA256 Hash of the Encoding object +func (en *Encoding) Hash() [32]byte { + var f []string + if en.ContentType.Value != "" { + f = append(f, en.ContentType.Value) + } + if len(en.Headers.Value) > 0 { + l := make([]string, len(en.Headers.Value)) + keys := make(map[string]low.ValueReference[*Header]) + z := 0 + for k := range en.Headers.Value { + keys[k.Value] = en.Headers.Value[k] + l[z] = k.Value + z++ + } + + for k := range en.Headers.Value { + f = append(f, fmt.Sprintf("%s-%x", k.Value, en.Headers.Value[k].Value.Hash())) + } + } + if en.Style.Value != "" { + f = append(f, en.Style.Value) + } + f = append(f, fmt.Sprint(sha256.Sum256([]byte(fmt.Sprint(en.Explode.Value))))) + f = append(f, fmt.Sprint(sha256.Sum256([]byte(fmt.Sprint(en.AllowReserved.Value))))) + return sha256.Sum256([]byte(strings.Join(f, "|"))) +} + +// Build will extract all Header objects from supplied node. +func (en *Encoding) Build(root *yaml.Node, idx *index.SpecIndex) error { + en.Reference = new(low.Reference) + headers, hL, hN, err := low.ExtractMap[*Header](HeadersLabel, root, idx) + if err != nil { + return err + } + if headers != nil { + en.Headers = low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*Header]]{ + Value: headers, + KeyNode: hL, + ValueNode: hN, + } + } + return nil +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/low/v3/header.go b/vendor/github.com/pb33f/libopenapi/datamodel/low/v3/header.go new file mode 100644 index 0000000000..9d283d5cb6 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/low/v3/header.go @@ -0,0 +1,192 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package v3 + +import ( + "crypto/sha256" + "fmt" + "github.com/pb33f/libopenapi/datamodel/low" + "github.com/pb33f/libopenapi/datamodel/low/base" + "github.com/pb33f/libopenapi/index" + "github.com/pb33f/libopenapi/utils" + "gopkg.in/yaml.v3" + "sort" + "strings" +) + +// Header represents a low-level OpenAPI 3+ Header object. +// - https://spec.openapis.org/oas/v3.1.0#header-object +type Header struct { + Description low.NodeReference[string] + Required low.NodeReference[bool] + Deprecated low.NodeReference[bool] + AllowEmptyValue low.NodeReference[bool] + Style low.NodeReference[string] + Explode low.NodeReference[bool] + AllowReserved low.NodeReference[bool] + Schema low.NodeReference[*base.SchemaProxy] + Example low.NodeReference[any] + Examples low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*base.Example]] + Content low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*MediaType]] + Extensions map[low.KeyReference[string]]low.ValueReference[any] + *low.Reference +} + +// FindExtension will attempt to locate an extension with the supplied name +func (h *Header) FindExtension(ext string) *low.ValueReference[any] { + return low.FindItemInMap[any](ext, h.Extensions) +} + +// FindExample will attempt to locate an Example with a specified name +func (h *Header) FindExample(eType string) *low.ValueReference[*base.Example] { + return low.FindItemInMap[*base.Example](eType, h.Examples.Value) +} + +// FindContent will attempt to locate a MediaType definition, with a specified name +func (h *Header) FindContent(ext string) *low.ValueReference[*MediaType] { + return low.FindItemInMap[*MediaType](ext, h.Content.Value) +} + +// GetExtensions returns all Header extensions and satisfies the low.HasExtensions interface. +func (h *Header) GetExtensions() map[low.KeyReference[string]]low.ValueReference[any] { + return h.Extensions +} + +// Hash will return a consistent SHA256 Hash of the Header object +func (h *Header) Hash() [32]byte { + var f []string + if h.Description.Value != "" { + f = append(f, h.Description.Value) + } + f = append(f, fmt.Sprint(h.Required.Value)) + f = append(f, fmt.Sprint(h.Deprecated.Value)) + f = append(f, fmt.Sprint(h.AllowEmptyValue.Value)) + if h.Style.Value != "" { + f = append(f, h.Style.Value) + } + f = append(f, fmt.Sprint(h.Explode.Value)) + f = append(f, fmt.Sprint(h.AllowReserved.Value)) + if h.Schema.Value != nil { + f = append(f, low.GenerateHashString(h.Schema.Value)) + } + if h.Example.Value != nil { + f = append(f, fmt.Sprint(h.Example.Value)) + } + if len(h.Examples.Value) > 0 { + for k := range h.Examples.Value { + f = append(f, fmt.Sprintf("%s-%x", k.Value, h.Examples.Value[k].Value.Hash())) + } + } + if len(h.Content.Value) > 0 { + for k := range h.Content.Value { + f = append(f, fmt.Sprintf("%s-%x", k.Value, h.Content.Value[k].Value.Hash())) + } + } + keys := make([]string, len(h.Extensions)) + z := 0 + for k := range h.Extensions { + keys[z] = fmt.Sprintf("%s-%x", k.Value, sha256.Sum256([]byte(fmt.Sprint(h.Extensions[k].Value)))) + z++ + } + sort.Strings(keys) + f = append(f, keys...) + return sha256.Sum256([]byte(strings.Join(f, "|"))) +} + +// Build will extract extensions, examples, schema and content/media types from node. +func (h *Header) Build(root *yaml.Node, idx *index.SpecIndex) error { + h.Reference = new(low.Reference) + h.Extensions = low.ExtractExtensions(root) + + // handle example if set. + _, expLabel, expNode := utils.FindKeyNodeFull(base.ExampleLabel, root.Content) + if expNode != nil { + h.Example = low.ExtractExample(expNode, expLabel) + } + + // handle examples if set. + exps, expsL, expsN, eErr := low.ExtractMap[*base.Example](base.ExamplesLabel, root, idx) + if eErr != nil { + return eErr + } + if exps != nil { + h.Examples = low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*base.Example]]{ + Value: exps, + KeyNode: expsL, + ValueNode: expsN, + } + } + + // handle schema + sch, sErr := base.ExtractSchema(root, idx) + if sErr != nil { + return sErr + } + if sch != nil { + h.Schema = *sch + } + + // handle content, if set. + con, cL, cN, cErr := low.ExtractMap[*MediaType](ContentLabel, root, idx) + if cErr != nil { + return cErr + } + h.Content = low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*MediaType]]{ + Value: con, + KeyNode: cL, + ValueNode: cN, + } + return nil +} + +// Getter methods to satisfy OpenAPIHeader interface. + +func (h *Header) GetDescription() *low.NodeReference[string] { + return &h.Description +} +func (h *Header) GetRequired() *low.NodeReference[bool] { + return &h.Required +} +func (h *Header) GetDeprecated() *low.NodeReference[bool] { + return &h.Deprecated +} +func (h *Header) GetAllowEmptyValue() *low.NodeReference[bool] { + return &h.AllowEmptyValue +} +func (h *Header) GetSchema() *low.NodeReference[any] { + i := low.NodeReference[any]{ + KeyNode: h.Schema.KeyNode, + ValueNode: h.Schema.ValueNode, + Value: h.Schema.Value, + } + return &i +} +func (h *Header) GetStyle() *low.NodeReference[string] { + return &h.Style +} +func (h *Header) GetAllowReserved() *low.NodeReference[bool] { + return &h.AllowReserved +} +func (h *Header) GetExplode() *low.NodeReference[bool] { + return &h.Explode +} +func (h *Header) GetExample() *low.NodeReference[any] { + return &h.Example +} +func (h *Header) GetExamples() *low.NodeReference[any] { + i := low.NodeReference[any]{ + KeyNode: h.Examples.KeyNode, + ValueNode: h.Examples.ValueNode, + Value: h.Examples.Value, + } + return &i +} +func (h *Header) GetContent() *low.NodeReference[any] { + c := low.NodeReference[any]{ + KeyNode: h.Content.KeyNode, + ValueNode: h.Content.ValueNode, + Value: h.Content.Value, + } + return &c +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/low/v3/link.go b/vendor/github.com/pb33f/libopenapi/datamodel/low/v3/link.go new file mode 100644 index 0000000000..26166ad38f --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/low/v3/link.go @@ -0,0 +1,104 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package v3 + +import ( + "crypto/sha256" + "fmt" + "github.com/pb33f/libopenapi/datamodel/low" + "github.com/pb33f/libopenapi/index" + "gopkg.in/yaml.v3" + "sort" + "strings" +) + +// Link represents a low-level OpenAPI 3+ Link object. +// +// The Link object represents a possible design-time link for a response. The presence of a link does not guarantee the +// caller’s ability to successfully invoke it, rather it provides a known relationship and traversal mechanism between +// responses and other operations. +// +// Unlike dynamic links (i.e. links provided in the response payload), the OAS linking mechanism does not require +// link information in the runtime response. +// +// For computing links, and providing instructions to execute them, a runtime expression is used for accessing values +// in an operation and using them as parameters while invoking the linked operation. +// - https://spec.openapis.org/oas/v3.1.0#link-object +type Link struct { + OperationRef low.NodeReference[string] + OperationId low.NodeReference[string] + Parameters low.NodeReference[map[low.KeyReference[string]]low.ValueReference[string]] + RequestBody low.NodeReference[string] + Description low.NodeReference[string] + Server low.NodeReference[*Server] + Extensions map[low.KeyReference[string]]low.ValueReference[any] + *low.Reference +} + +// GetExtensions returns all Link extensions and satisfies the low.HasExtensions interface. +func (l *Link) GetExtensions() map[low.KeyReference[string]]low.ValueReference[any] { + return l.Extensions +} + +// FindParameter will attempt to locate a parameter string value, using a parameter name input. +func (l *Link) FindParameter(pName string) *low.ValueReference[string] { + return low.FindItemInMap[string](pName, l.Parameters.Value) +} + +// FindExtension will attempt to locate an extension with a specific key +func (l *Link) FindExtension(ext string) *low.ValueReference[any] { + return low.FindItemInMap[any](ext, l.Extensions) +} + +// Build will extract extensions and servers from the node. +func (l *Link) Build(root *yaml.Node, idx *index.SpecIndex) error { + l.Reference = new(low.Reference) + l.Extensions = low.ExtractExtensions(root) + // extract server. + ser, sErr := low.ExtractObject[*Server](ServerLabel, root, idx) + if sErr != nil { + return sErr + } + l.Server = ser + return nil +} + +// Hash will return a consistent SHA256 Hash of the Link object +func (l *Link) Hash() [32]byte { + var f []string + if l.Description.Value != "" { + f = append(f, l.Description.Value) + } + if l.OperationRef.Value != "" { + f = append(f, l.OperationRef.Value) + } + if l.OperationId.Value != "" { + f = append(f, l.OperationId.Value) + } + if l.RequestBody.Value != "" { + f = append(f, l.RequestBody.Value) + } + if l.Server.Value != nil { + f = append(f, low.GenerateHashString(l.Server.Value)) + } + // todo: needs ordering. + + keys := make([]string, len(l.Parameters.Value)) + z := 0 + for k := range l.Parameters.Value { + keys[z] = l.Parameters.Value[k].Value + z++ + } + sort.Strings(keys) + f = append(f, keys...) + keys = make([]string, len(l.Extensions)) + z = 0 + for k := range l.Extensions { + keys[z] = fmt.Sprintf("%s-%x", k.Value, sha256.Sum256([]byte(fmt.Sprint(l.Extensions[k].Value)))) + z++ + } + sort.Strings(keys) + f = append(f, keys...) + return sha256.Sum256([]byte(strings.Join(f, "|"))) +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/low/v3/media_type.go b/vendor/github.com/pb33f/libopenapi/datamodel/low/v3/media_type.go new file mode 100644 index 0000000000..9aa9702d1d --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/low/v3/media_type.go @@ -0,0 +1,153 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package v3 + +import ( + "crypto/sha256" + "fmt" + "github.com/pb33f/libopenapi/datamodel/low" + "github.com/pb33f/libopenapi/datamodel/low/base" + "github.com/pb33f/libopenapi/index" + "github.com/pb33f/libopenapi/utils" + "gopkg.in/yaml.v3" + "sort" + "strings" +) + +// MediaType represents a low-level OpenAPI MediaType object. +// +// Each Media Type Object provides schema and examples for the media type identified by its key. +// - https://spec.openapis.org/oas/v3.1.0#media-type-object +type MediaType struct { + Schema low.NodeReference[*base.SchemaProxy] + Example low.NodeReference[any] + Examples low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*base.Example]] + Encoding low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*Encoding]] + Extensions map[low.KeyReference[string]]low.ValueReference[any] + *low.Reference +} + +// GetExtensions returns all MediaType extensions and satisfies the low.HasExtensions interface. +func (mt *MediaType) GetExtensions() map[low.KeyReference[string]]low.ValueReference[any] { + return mt.Extensions +} + +// FindExtension will attempt to locate an extension with the supplied name. +func (mt *MediaType) FindExtension(ext string) *low.ValueReference[any] { + return low.FindItemInMap[any](ext, mt.Extensions) +} + +// FindPropertyEncoding will attempt to locate an Encoding value with a specific name. +func (mt *MediaType) FindPropertyEncoding(eType string) *low.ValueReference[*Encoding] { + return low.FindItemInMap[*Encoding](eType, mt.Encoding.Value) +} + +// FindExample will attempt to locate an Example with a specific name. +func (mt *MediaType) FindExample(eType string) *low.ValueReference[*base.Example] { + return low.FindItemInMap[*base.Example](eType, mt.Examples.Value) +} + +// GetAllExamples will extract all examples from the MediaType instance. +func (mt *MediaType) GetAllExamples() map[low.KeyReference[string]]low.ValueReference[*base.Example] { + return mt.Examples.Value +} + +// Build will extract examples, extensions, schema and encoding from node. +func (mt *MediaType) Build(root *yaml.Node, idx *index.SpecIndex) error { + mt.Reference = new(low.Reference) + mt.Extensions = low.ExtractExtensions(root) + + // handle example if set. + _, expLabel, expNode := utils.FindKeyNodeFull(base.ExampleLabel, root.Content) + if expNode != nil { + var value any + if utils.IsNodeMap(expNode) { + var h map[string]any + _ = expNode.Decode(&h) + value = h + } + if utils.IsNodeArray(expNode) { + var h []any + _ = expNode.Decode(&h) + value = h + } + if value == nil { + if expNode.Value != "" { + value = expNode.Value + } + } + mt.Example = low.NodeReference[any]{Value: value, KeyNode: expLabel, ValueNode: expNode} + } + + //handle schema + sch, sErr := base.ExtractSchema(root, idx) + if sErr != nil { + return sErr + } + if sch != nil { + mt.Schema = *sch + } + + // handle examples if set. + exps, expsL, expsN, eErr := low.ExtractMap[*base.Example](base.ExamplesLabel, root, idx) + if eErr != nil { + return eErr + } + if exps != nil { + mt.Examples = low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*base.Example]]{ + Value: exps, + KeyNode: expsL, + ValueNode: expsN, + } + } + + // handle encoding + encs, encsL, encsN, encErr := low.ExtractMap[*Encoding](EncodingLabel, root, idx) + if encErr != nil { + return encErr + } + if encs != nil { + mt.Encoding = low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*Encoding]]{ + Value: encs, + KeyNode: encsL, + ValueNode: encsN, + } + } + return nil +} + +// Hash will return a consistent SHA256 Hash of the MediaType object +func (mt *MediaType) Hash() [32]byte { + var f []string + if mt.Schema.Value != nil { + f = append(f, low.GenerateHashString(mt.Schema.Value)) + } + if mt.Example.Value != nil { + f = append(f, fmt.Sprintf("%x", sha256.Sum256([]byte(fmt.Sprint(mt.Example.Value))))) + } + keys := make([]string, len(mt.Examples.Value)) + z := 0 + for k := range mt.Examples.Value { + keys[z] = low.GenerateHashString(mt.Examples.Value[k].Value) + z++ + } + sort.Strings(keys) + f = append(f, keys...) + keys = make([]string, len(mt.Encoding.Value)) + z = 0 + for k := range mt.Encoding.Value { + keys[z] = low.GenerateHashString(mt.Encoding.Value[k].Value) + } + sort.Strings(keys) + f = append(f, keys...) + keys = make([]string, len(mt.Extensions)) + z = 0 + for k := range mt.Extensions { + keys[z] = fmt.Sprintf("%s-%x", k.Value, sha256.Sum256([]byte(fmt.Sprint(mt.Extensions[k].Value)))) + z++ + } + sort.Strings(keys) + f = append(f, keys...) + return sha256.Sum256([]byte(strings.Join(f, "|"))) +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/low/v3/oauth_flows.go b/vendor/github.com/pb33f/libopenapi/datamodel/low/v3/oauth_flows.go new file mode 100644 index 0000000000..5d916666d6 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/low/v3/oauth_flows.go @@ -0,0 +1,151 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package v3 + +import ( + "crypto/sha256" + "fmt" + "github.com/pb33f/libopenapi/datamodel/low" + "github.com/pb33f/libopenapi/index" + "gopkg.in/yaml.v3" + "sort" + "strings" +) + +// OAuthFlows represents a low-level OpenAPI 3+ OAuthFlows object. +// - https://spec.openapis.org/oas/v3.1.0#oauth-flows-object +type OAuthFlows struct { + Implicit low.NodeReference[*OAuthFlow] + Password low.NodeReference[*OAuthFlow] + ClientCredentials low.NodeReference[*OAuthFlow] + AuthorizationCode low.NodeReference[*OAuthFlow] + Extensions map[low.KeyReference[string]]low.ValueReference[any] + *low.Reference +} + +// GetExtensions returns all OAuthFlows extensions and satisfies the low.HasExtensions interface. +func (o *OAuthFlows) GetExtensions() map[low.KeyReference[string]]low.ValueReference[any] { + return o.Extensions +} + +// FindExtension will attempt to locate an extension with the supplied name. +func (o *OAuthFlows) FindExtension(ext string) *low.ValueReference[any] { + return low.FindItemInMap[any](ext, o.Extensions) +} + +// Build will extract extensions and all OAuthFlow types from the supplied node. +func (o *OAuthFlows) Build(root *yaml.Node, idx *index.SpecIndex) error { + o.Reference = new(low.Reference) + o.Extensions = low.ExtractExtensions(root) + + v, vErr := low.ExtractObject[*OAuthFlow](ImplicitLabel, root, idx) + if vErr != nil { + return vErr + } + o.Implicit = v + + v, vErr = low.ExtractObject[*OAuthFlow](PasswordLabel, root, idx) + if vErr != nil { + return vErr + } + o.Password = v + + v, vErr = low.ExtractObject[*OAuthFlow](ClientCredentialsLabel, root, idx) + if vErr != nil { + return vErr + } + o.ClientCredentials = v + + v, vErr = low.ExtractObject[*OAuthFlow](AuthorizationCodeLabel, root, idx) + if vErr != nil { + return vErr + } + o.AuthorizationCode = v + return nil +} + +// Hash will return a consistent SHA256 Hash of the OAuthFlow object +func (o *OAuthFlows) Hash() [32]byte { + var f []string + if !o.Implicit.IsEmpty() { + f = append(f, low.GenerateHashString(o.Implicit.Value)) + } + if !o.Password.IsEmpty() { + f = append(f, low.GenerateHashString(o.Password.Value)) + } + if !o.ClientCredentials.IsEmpty() { + f = append(f, low.GenerateHashString(o.ClientCredentials.Value)) + } + if !o.AuthorizationCode.IsEmpty() { + f = append(f, low.GenerateHashString(o.AuthorizationCode.Value)) + } + for k := range o.Extensions { + f = append(f, fmt.Sprintf("%s-%v", k.Value, o.Extensions[k].Value)) + } + return sha256.Sum256([]byte(strings.Join(f, "|"))) +} + +// OAuthFlow represents a low-level OpenAPI 3+ OAuthFlow object. +// - https://spec.openapis.org/oas/v3.1.0#oauth-flow-object +type OAuthFlow struct { + AuthorizationUrl low.NodeReference[string] + TokenUrl low.NodeReference[string] + RefreshUrl low.NodeReference[string] + Scopes low.NodeReference[map[low.KeyReference[string]]low.ValueReference[string]] + Extensions map[low.KeyReference[string]]low.ValueReference[any] + *low.Reference +} + +// GetExtensions returns all OAuthFlow extensions and satisfies the low.HasExtensions interface. +func (o *OAuthFlow) GetExtensions() map[low.KeyReference[string]]low.ValueReference[any] { + return o.Extensions +} + +// FindScope attempts to locate a scope using a specified name. +func (o *OAuthFlow) FindScope(scope string) *low.ValueReference[string] { + return low.FindItemInMap[string](scope, o.Scopes.Value) +} + +// FindExtension attempts to locate an extension with a specified key +func (o *OAuthFlow) FindExtension(ext string) *low.ValueReference[any] { + return low.FindItemInMap[any](ext, o.Extensions) +} + +// Build will extract extensions from the node. +func (o *OAuthFlow) Build(root *yaml.Node, idx *index.SpecIndex) error { + o.Reference = new(low.Reference) + o.Extensions = low.ExtractExtensions(root) + return nil +} + +// Hash will return a consistent SHA256 Hash of the OAuthFlow object +func (o *OAuthFlow) Hash() [32]byte { + var f []string + if !o.AuthorizationUrl.IsEmpty() { + f = append(f, o.AuthorizationUrl.Value) + } + if !o.TokenUrl.IsEmpty() { + f = append(f, o.TokenUrl.Value) + } + if !o.RefreshUrl.IsEmpty() { + f = append(f, o.RefreshUrl.Value) + } + keys := make([]string, len(o.Scopes.Value)) + z := 0 + for k := range o.Scopes.Value { + keys[z] = fmt.Sprintf("%s-%s", k.Value, sha256.Sum256([]byte(fmt.Sprint(o.Scopes.Value[k].Value)))) + z++ + } + sort.Strings(keys) + f = append(f, keys...) + keys = make([]string, len(o.Extensions)) + z = 0 + for k := range o.Extensions { + keys[z] = fmt.Sprintf("%s-%x", k.Value, sha256.Sum256([]byte(fmt.Sprint(o.Extensions[k].Value)))) + z++ + } + sort.Strings(keys) + f = append(f, keys...) + return sha256.Sum256([]byte(strings.Join(f, "|"))) +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/low/v3/operation.go b/vendor/github.com/pb33f/libopenapi/datamodel/low/v3/operation.go new file mode 100644 index 0000000000..e3badf74b3 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/low/v3/operation.go @@ -0,0 +1,268 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package v3 + +import ( + "crypto/sha256" + "fmt" + "github.com/pb33f/libopenapi/datamodel/low" + "github.com/pb33f/libopenapi/datamodel/low/base" + "github.com/pb33f/libopenapi/index" + "gopkg.in/yaml.v3" + "sort" + "strings" +) + +// Operation is a low-level representation of an OpenAPI 3+ Operation object. +// +// An Operation is perhaps the most important object of the entire specification. Everything of value +// happens here. The entire being for existence of this library and the specification, is this Operation. +// - https://spec.openapis.org/oas/v3.1.0#operation-object +type Operation struct { + Tags low.NodeReference[[]low.ValueReference[string]] + Summary low.NodeReference[string] + Description low.NodeReference[string] + ExternalDocs low.NodeReference[*base.ExternalDoc] + OperationId low.NodeReference[string] + Parameters low.NodeReference[[]low.ValueReference[*Parameter]] + RequestBody low.NodeReference[*RequestBody] + Responses low.NodeReference[*Responses] + Callbacks low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*Callback]] + Deprecated low.NodeReference[bool] + Security low.NodeReference[[]low.ValueReference[*base.SecurityRequirement]] + Servers low.NodeReference[[]low.ValueReference[*Server]] + Extensions map[low.KeyReference[string]]low.ValueReference[any] + *low.Reference +} + +// FindCallback will attempt to locate a Callback instance by the supplied name. +func (o *Operation) FindCallback(callback string) *low.ValueReference[*Callback] { + return low.FindItemInMap[*Callback](callback, o.Callbacks.Value) +} + +// FindSecurityRequirement will attempt to locate a security requirement string from a supplied name. +func (o *Operation) FindSecurityRequirement(name string) []low.ValueReference[string] { + for k := range o.Security.Value { + for i := range o.Security.Value[k].Value.Requirements.Value { + if i.Value == name { + return o.Security.Value[k].Value.Requirements.Value[i].Value + } + } + } + return nil +} + +// Build will extract external docs, parameters, request body, responses, callbacks, security and servers. +func (o *Operation) Build(root *yaml.Node, idx *index.SpecIndex) error { + o.Reference = new(low.Reference) + o.Extensions = low.ExtractExtensions(root) + + // extract externalDocs + extDocs, dErr := low.ExtractObject[*base.ExternalDoc](base.ExternalDocsLabel, root, idx) + if dErr != nil { + return dErr + } + o.ExternalDocs = extDocs + + // extract parameters + params, ln, vn, pErr := low.ExtractArray[*Parameter](ParametersLabel, root, idx) + if pErr != nil { + return pErr + } + if params != nil { + o.Parameters = low.NodeReference[[]low.ValueReference[*Parameter]]{ + Value: params, + KeyNode: ln, + ValueNode: vn, + } + } + + // extract request body + rBody, rErr := low.ExtractObject[*RequestBody](RequestBodyLabel, root, idx) + if rErr != nil { + return rErr + } + o.RequestBody = rBody + + // extract responses + respBody, respErr := low.ExtractObject[*Responses](ResponsesLabel, root, idx) + if respErr != nil { + return respErr + } + o.Responses = respBody + + // extract callbacks + callbacks, cbL, cbN, cbErr := low.ExtractMap[*Callback](CallbacksLabel, root, idx) + if cbErr != nil { + return cbErr + } + if callbacks != nil { + o.Callbacks = low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*Callback]]{ + Value: callbacks, + KeyNode: cbL, + ValueNode: cbN, + } + } + + // extract security + sec, sln, svn, sErr := low.ExtractArray[*base.SecurityRequirement](SecurityLabel, root, idx) + if sErr != nil { + return sErr + } + if sec != nil { + o.Security = low.NodeReference[[]low.ValueReference[*base.SecurityRequirement]]{ + Value: sec, + KeyNode: sln, + ValueNode: svn, + } + } + + // extract servers + servers, sl, sn, serErr := low.ExtractArray[*Server](ServersLabel, root, idx) + if serErr != nil { + return serErr + } + if servers != nil { + o.Servers = low.NodeReference[[]low.ValueReference[*Server]]{ + Value: servers, + KeyNode: sl, + ValueNode: sn, + } + } + return nil +} + +// Hash will return a consistent SHA256 Hash of the Operation object +func (o *Operation) Hash() [32]byte { + var f []string + if !o.Summary.IsEmpty() { + f = append(f, o.Summary.Value) + } + if !o.Description.IsEmpty() { + f = append(f, o.Description.Value) + } + if !o.OperationId.IsEmpty() { + f = append(f, o.OperationId.Value) + } + if !o.RequestBody.IsEmpty() { + f = append(f, low.GenerateHashString(o.RequestBody.Value)) + } + if !o.Summary.IsEmpty() { + f = append(f, o.Summary.Value) + } + if !o.ExternalDocs.IsEmpty() { + f = append(f, low.GenerateHashString(o.ExternalDocs.Value)) + } + if !o.Responses.IsEmpty() { + f = append(f, low.GenerateHashString(o.Responses.Value)) + } + if !o.Security.IsEmpty() { + for k := range o.Security.Value { + f = append(f, low.GenerateHashString(o.Security.Value[k].Value)) + } + } + if !o.Deprecated.IsEmpty() { + f = append(f, fmt.Sprint(o.Deprecated.Value)) + } + var keys []string + keys = make([]string, len(o.Tags.Value)) + for k := range o.Tags.Value { + keys[k] = o.Tags.Value[k].Value + } + sort.Strings(keys) + f = append(f, keys...) + + keys = make([]string, len(o.Servers.Value)) + for k := range o.Servers.Value { + keys[k] = low.GenerateHashString(o.Servers.Value[k].Value) + } + sort.Strings(keys) + f = append(f, keys...) + + keys = make([]string, len(o.Parameters.Value)) + for k := range o.Parameters.Value { + keys[k] = low.GenerateHashString(o.Parameters.Value[k].Value) + } + sort.Strings(keys) + f = append(f, keys...) + + keys = make([]string, len(o.Callbacks.Value)) + z := 0 + for k := range o.Callbacks.Value { + keys[z] = low.GenerateHashString(o.Callbacks.Value[k].Value) + z++ + } + sort.Strings(keys) + f = append(f, keys...) + + keys = make([]string, len(o.Extensions)) + z = 0 + for k := range o.Extensions { + keys[z] = fmt.Sprintf("%s-%x", k.Value, sha256.Sum256([]byte(fmt.Sprint(o.Extensions[k].Value)))) + z++ + } + sort.Strings(keys) + f = append(f, keys...) + + return sha256.Sum256([]byte(strings.Join(f, "|"))) +} + +// methods to satisfy swagger operations interface + +func (o *Operation) GetTags() low.NodeReference[[]low.ValueReference[string]] { + return o.Tags +} +func (o *Operation) GetSummary() low.NodeReference[string] { + return o.Summary +} +func (o *Operation) GetDescription() low.NodeReference[string] { + return o.Description +} +func (o *Operation) GetExternalDocs() low.NodeReference[any] { + return low.NodeReference[any]{ + ValueNode: o.ExternalDocs.ValueNode, + KeyNode: o.ExternalDocs.KeyNode, + Value: o.ExternalDocs.Value, + } +} +func (o *Operation) GetOperationId() low.NodeReference[string] { + return o.OperationId +} +func (o *Operation) GetDeprecated() low.NodeReference[bool] { + return o.Deprecated +} +func (o *Operation) GetExtensions() map[low.KeyReference[string]]low.ValueReference[any] { + return o.Extensions +} +func (o *Operation) GetResponses() low.NodeReference[any] { + return low.NodeReference[any]{ + ValueNode: o.Responses.ValueNode, + KeyNode: o.Responses.KeyNode, + Value: o.Responses.Value, + } +} +func (o *Operation) GetParameters() low.NodeReference[any] { + return low.NodeReference[any]{ + ValueNode: o.Parameters.ValueNode, + KeyNode: o.Parameters.KeyNode, + Value: o.Parameters.Value, + } +} +func (o *Operation) GetSecurity() low.NodeReference[any] { + return low.NodeReference[any]{ + ValueNode: o.Security.ValueNode, + KeyNode: o.Security.KeyNode, + Value: o.Security.Value, + } +} +func (o *Operation) GetServers() low.NodeReference[any] { + return low.NodeReference[any]{ + ValueNode: o.Servers.ValueNode, + KeyNode: o.Servers.KeyNode, + Value: o.Servers.Value, + } +} +func (o *Operation) GetCallbacks() low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*Callback]] { + return o.Callbacks +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/low/v3/parameter.go b/vendor/github.com/pb33f/libopenapi/datamodel/low/v3/parameter.go new file mode 100644 index 0000000000..1a5bdd003f --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/low/v3/parameter.go @@ -0,0 +1,217 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package v3 + +import ( + "crypto/sha256" + "fmt" + "github.com/pb33f/libopenapi/datamodel/low" + "github.com/pb33f/libopenapi/datamodel/low/base" + "github.com/pb33f/libopenapi/index" + "github.com/pb33f/libopenapi/utils" + "gopkg.in/yaml.v3" + "sort" + "strings" +) + +// Parameter represents a high-level OpenAPI 3+ Parameter object, that is backed by a low-level one. +// +// A unique parameter is defined by a combination of a name and location. +// - https://spec.openapis.org/oas/v3.1.0#parameter-object +type Parameter struct { + Name low.NodeReference[string] + In low.NodeReference[string] + Description low.NodeReference[string] + Required low.NodeReference[bool] + Deprecated low.NodeReference[bool] + AllowEmptyValue low.NodeReference[bool] + Style low.NodeReference[string] + Explode low.NodeReference[bool] + AllowReserved low.NodeReference[bool] + Schema low.NodeReference[*base.SchemaProxy] + Example low.NodeReference[any] + Examples low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*base.Example]] + Content low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*MediaType]] + Extensions map[low.KeyReference[string]]low.ValueReference[any] + *low.Reference +} + +// FindContent will attempt to locate a MediaType instance using the specified name. +func (p *Parameter) FindContent(cType string) *low.ValueReference[*MediaType] { + return low.FindItemInMap[*MediaType](cType, p.Content.Value) +} + +// FindExample will attempt to locate a base.Example instance using the specified name. +func (p *Parameter) FindExample(eType string) *low.ValueReference[*base.Example] { + return low.FindItemInMap[*base.Example](eType, p.Examples.Value) +} + +// FindExtension attempts to locate an extension using the specified name. +func (p *Parameter) FindExtension(ext string) *low.ValueReference[any] { + return low.FindItemInMap[any](ext, p.Extensions) +} + +// GetExtensions returns all extensions for Parameter. +func (p *Parameter) GetExtensions() map[low.KeyReference[string]]low.ValueReference[any] { + return p.Extensions +} + +// Build will extract examples, extensions and content/media types. +func (p *Parameter) Build(root *yaml.Node, idx *index.SpecIndex) error { + p.Reference = new(low.Reference) + p.Extensions = low.ExtractExtensions(root) + + // handle example if set. + _, expLabel, expNode := utils.FindKeyNodeFull(base.ExampleLabel, root.Content) + if expNode != nil { + p.Example = low.ExtractExample(expNode, expLabel) + } + + // handle schema + sch, sErr := base.ExtractSchema(root, idx) + if sErr != nil { + return sErr + } + if sch != nil { + p.Schema = *sch + } + + // handle examples if set. + exps, expsL, expsN, eErr := low.ExtractMap[*base.Example](base.ExamplesLabel, root, idx) + if eErr != nil { + return eErr + } + if exps != nil { + p.Examples = low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*base.Example]]{ + Value: exps, + KeyNode: expsL, + ValueNode: expsN, + } + } + + // handle content, if set. + con, cL, cN, cErr := low.ExtractMap[*MediaType](ContentLabel, root, idx) + if cErr != nil { + return cErr + } + p.Content = low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*MediaType]]{ + Value: con, + KeyNode: cL, + ValueNode: cN, + } + return nil +} + +// Hash will return a consistent SHA256 Hash of the Parameter object +func (p *Parameter) Hash() [32]byte { + var f []string + if p.Name.Value != "" { + f = append(f, p.Name.Value) + } + if p.In.Value != "" { + f = append(f, p.In.Value) + } + if p.Description.Value != "" { + f = append(f, p.Description.Value) + } + f = append(f, fmt.Sprint(p.Required.Value)) + f = append(f, fmt.Sprint(p.Deprecated.Value)) + f = append(f, fmt.Sprint(p.AllowEmptyValue.Value)) + if p.Style.Value != "" { + f = append(f, fmt.Sprint(p.Style.Value)) + } + f = append(f, fmt.Sprint(p.Explode.Value)) + f = append(f, fmt.Sprint(p.AllowReserved.Value)) + if p.Schema.Value != nil { + f = append(f, fmt.Sprintf("%x", p.Schema.Value.Schema().Hash())) + } + if p.Example.Value != nil { + f = append(f, fmt.Sprintf("%x", p.Example.Value)) + } + + var keys []string + keys = make([]string, len(p.Examples.Value)) + z := 0 + for k := range p.Examples.Value { + keys[z] = low.GenerateHashString(p.Examples.Value[k].Value) + z++ + } + sort.Strings(keys) + f = append(f, keys...) + keys = make([]string, len(p.Content.Value)) + z = 0 + for k := range p.Content.Value { + keys[z] = low.GenerateHashString(p.Content.Value[k].Value) + z++ + } + sort.Strings(keys) + f = append(f, keys...) + keys = make([]string, len(p.Extensions)) + z = 0 + for k := range p.Extensions { + keys[z] = fmt.Sprintf("%s-%x", k.Value, sha256.Sum256([]byte(fmt.Sprint(p.Extensions[k].Value)))) + z++ + } + sort.Strings(keys) + f = append(f, keys...) + + return sha256.Sum256([]byte(strings.Join(f, "|"))) +} + +// IsParameter compliance methods. + +func (p *Parameter) GetName() *low.NodeReference[string] { + return &p.Name +} +func (p *Parameter) GetIn() *low.NodeReference[string] { + return &p.In +} +func (p *Parameter) GetDescription() *low.NodeReference[string] { + return &p.Description +} +func (p *Parameter) GetRequired() *low.NodeReference[bool] { + return &p.Required +} +func (p *Parameter) GetDeprecated() *low.NodeReference[bool] { + return &p.Deprecated +} +func (p *Parameter) GetAllowEmptyValue() *low.NodeReference[bool] { + return &p.AllowEmptyValue +} +func (p *Parameter) GetSchema() *low.NodeReference[any] { + i := low.NodeReference[any]{ + KeyNode: p.Schema.KeyNode, + ValueNode: p.Schema.ValueNode, + Value: p.Schema.Value, + } + return &i +} +func (p *Parameter) GetStyle() *low.NodeReference[string] { + return &p.Style +} +func (p *Parameter) GetAllowReserved() *low.NodeReference[bool] { + return &p.AllowReserved +} +func (p *Parameter) GetExplode() *low.NodeReference[bool] { + return &p.Explode +} +func (p *Parameter) GetExample() *low.NodeReference[any] { + return &p.Example +} +func (p *Parameter) GetExamples() *low.NodeReference[any] { + i := low.NodeReference[any]{ + KeyNode: p.Examples.KeyNode, + ValueNode: p.Examples.ValueNode, + Value: p.Examples.Value, + } + return &i +} +func (p *Parameter) GetContent() *low.NodeReference[any] { + c := low.NodeReference[any]{ + KeyNode: p.Content.KeyNode, + ValueNode: p.Content.ValueNode, + Value: p.Content.Value, + } + return &c +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/low/v3/path_item.go b/vendor/github.com/pb33f/libopenapi/datamodel/low/v3/path_item.go new file mode 100644 index 0000000000..c178bd2851 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/low/v3/path_item.go @@ -0,0 +1,313 @@ +// Copyright 2022-2023 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package v3 + +import ( + "crypto/sha256" + "fmt" + "sort" + "strings" + "sync" + + "github.com/pb33f/libopenapi/datamodel/low" + "github.com/pb33f/libopenapi/index" + "github.com/pb33f/libopenapi/utils" + "gopkg.in/yaml.v3" +) + +// PathItem represents a low-level OpenAPI 3+ PathItem object. +// +// Describes the operations available on a single path. A Path Item MAY be empty, due to ACL constraints. +// The path itself is still exposed to the documentation viewer, but they will not know which operations and parameters +// are available. +// - https://spec.openapis.org/oas/v3.1.0#path-item-object +type PathItem struct { + Description low.NodeReference[string] + Summary low.NodeReference[string] + Get low.NodeReference[*Operation] + Put low.NodeReference[*Operation] + Post low.NodeReference[*Operation] + Delete low.NodeReference[*Operation] + Options low.NodeReference[*Operation] + Head low.NodeReference[*Operation] + Patch low.NodeReference[*Operation] + Trace low.NodeReference[*Operation] + Servers low.NodeReference[[]low.ValueReference[*Server]] + Parameters low.NodeReference[[]low.ValueReference[*Parameter]] + Extensions map[low.KeyReference[string]]low.ValueReference[any] + *low.Reference +} + +// Hash will return a consistent SHA256 Hash of the PathItem object +func (p *PathItem) Hash() [32]byte { + var f []string + if !p.Description.IsEmpty() { + f = append(f, p.Description.Value) + } + if !p.Summary.IsEmpty() { + f = append(f, p.Summary.Value) + } + if !p.Get.IsEmpty() { + f = append(f, fmt.Sprintf("%s-%s", GetLabel, low.GenerateHashString(p.Get.Value))) + } + if !p.Put.IsEmpty() { + f = append(f, fmt.Sprintf("%s-%s", PutLabel, low.GenerateHashString(p.Put.Value))) + } + if !p.Post.IsEmpty() { + f = append(f, fmt.Sprintf("%s-%s", PutLabel, low.GenerateHashString(p.Post.Value))) + } + if !p.Delete.IsEmpty() { + f = append(f, fmt.Sprintf("%s-%s", DeleteLabel, low.GenerateHashString(p.Delete.Value))) + } + if !p.Options.IsEmpty() { + f = append(f, fmt.Sprintf("%s-%s", OptionsLabel, low.GenerateHashString(p.Options.Value))) + } + if !p.Head.IsEmpty() { + f = append(f, fmt.Sprintf("%s-%s", HeadLabel, low.GenerateHashString(p.Head.Value))) + } + if !p.Patch.IsEmpty() { + f = append(f, fmt.Sprintf("%s-%s", PatchLabel, low.GenerateHashString(p.Patch.Value))) + } + if !p.Trace.IsEmpty() { + f = append(f, fmt.Sprintf("%s-%s", TraceLabel, low.GenerateHashString(p.Trace.Value))) + } + keys := make([]string, len(p.Parameters.Value)) + for k := range p.Parameters.Value { + keys[k] = low.GenerateHashString(p.Parameters.Value[k].Value) + } + sort.Strings(keys) + f = append(f, keys...) + keys = make([]string, len(p.Servers.Value)) + for k := range p.Servers.Value { + keys[k] = low.GenerateHashString(p.Servers.Value[k].Value) + } + sort.Strings(keys) + f = append(f, keys...) + + keys = make([]string, len(p.Extensions)) + z := 0 + for k := range p.Extensions { + keys[z] = fmt.Sprintf("%s-%x", k.Value, sha256.Sum256([]byte(fmt.Sprint(p.Extensions[k].Value)))) + z++ + } + sort.Strings(keys) + f = append(f, keys...) + return sha256.Sum256([]byte(strings.Join(f, "|"))) +} + +// FindExtension attempts to find an extension +func (p *PathItem) FindExtension(ext string) *low.ValueReference[any] { + return low.FindItemInMap[any](ext, p.Extensions) +} + +// GetExtensions returns all PathItem extensions and satisfies the low.HasExtensions interface. +func (p *PathItem) GetExtensions() map[low.KeyReference[string]]low.ValueReference[any] { + return p.Extensions +} + +// Build extracts extensions, parameters, servers and each http method defined. +// everything is extracted asynchronously for speed. +func (p *PathItem) Build(root *yaml.Node, idx *index.SpecIndex) error { + p.Reference = new(low.Reference) + p.Extensions = low.ExtractExtensions(root) + skip := false + var currentNode *yaml.Node + + var wg sync.WaitGroup + var errors []error + + var ops []low.NodeReference[*Operation] + + // extract parameters + params, ln, vn, pErr := low.ExtractArray[*Parameter](ParametersLabel, root, idx) + if pErr != nil { + return pErr + } + if params != nil { + p.Parameters = low.NodeReference[[]low.ValueReference[*Parameter]]{ + Value: params, + KeyNode: ln, + ValueNode: vn, + } + } + + _, ln, vn = utils.FindKeyNodeFullTop(ServersLabel, root.Content) + if vn != nil { + if utils.IsNodeArray(vn) { + var servers []low.ValueReference[*Server] + for _, srvN := range vn.Content { + if utils.IsNodeMap(srvN) { + srvr := new(Server) + _ = low.BuildModel(srvN, srvr) + srvr.Build(srvN, idx) + servers = append(servers, low.ValueReference[*Server]{ + Value: srvr, + ValueNode: srvN, + }) + } + } + p.Servers = low.NodeReference[[]low.ValueReference[*Server]]{ + Value: servers, + KeyNode: ln, + ValueNode: vn, + } + } + } + + for i, pathNode := range root.Content { + if strings.HasPrefix(strings.ToLower(pathNode.Value), "x-") { + skip = true + continue + } + if strings.HasPrefix(strings.ToLower(pathNode.Value), "parameters") { + skip = true + continue + } + if skip { + skip = false + continue + } + if i%2 == 0 { + currentNode = pathNode + continue + } + + // the only thing we now care about is handling operations, filter out anything that's not a verb. + switch currentNode.Value { + case GetLabel: + break + case PostLabel: + break + case PutLabel: + break + case PatchLabel: + break + case DeleteLabel: + break + case HeadLabel: + break + case OptionsLabel: + break + case TraceLabel: + break + default: + continue // ignore everything else. + } + + var op Operation + opIsRef := false + var opRefVal string + if ok, _, ref := utils.IsNodeRefValue(pathNode); ok { + // According to OpenAPI spec the only valid $ref for paths is + // reference for the whole pathItem. Unfortunately, internet is full of invalid specs + // even from trusted companies like DigitalOcean where they tend to + // use file $ref for each respective operation: + // /endpoint/call/name: + // post: + // $ref: 'file.yaml' + // Check if that is the case and resolve such thing properly too. + + opIsRef = true + opRefVal = ref + r, err := low.LocateRefNode(pathNode, idx) + if r != nil { + if r.Kind == yaml.DocumentNode { + r = r.Content[0] + } + pathNode = r + if r.Tag == "" { + // If it's a node from file, tag is empty + pathNode = r.Content[0] + } + + if err != nil { + if !idx.AllowCircularReferenceResolving() { + return fmt.Errorf("build schema failed: %s", err.Error()) + } + } + } else { + return fmt.Errorf("path item build failed: cannot find reference: %s at line %d, col %d", + pathNode.Content[1].Value, pathNode.Content[1].Line, pathNode.Content[1].Column) + } + } + wg.Add(1) + go low.BuildModelAsync(pathNode, &op, &wg, &errors) + + opRef := low.NodeReference[*Operation]{ + Value: &op, + KeyNode: currentNode, + ValueNode: pathNode, + } + if opIsRef { + opRef.Reference = opRefVal + opRef.ReferenceNode = true + } + + ops = append(ops, opRef) + + switch currentNode.Value { + case GetLabel: + p.Get = opRef + case PostLabel: + p.Post = opRef + case PutLabel: + p.Put = opRef + case PatchLabel: + p.Patch = opRef + case DeleteLabel: + p.Delete = opRef + case HeadLabel: + p.Head = opRef + case OptionsLabel: + p.Options = opRef + case TraceLabel: + p.Trace = opRef + } + } + + // all operations have been superficially built, + // now we need to build out the operation, we will do this asynchronously for speed. + opBuildChan := make(chan bool) + opErrorChan := make(chan error) + + buildOpFunc := func(op low.NodeReference[*Operation], ch chan<- bool, errCh chan<- error, ref string) { + er := op.Value.Build(op.ValueNode, idx) + if ref != "" { + op.Value.Reference.Reference = ref + } + if er != nil { + errCh <- er + } + ch <- true + } + + if len(ops) <= 0 { + return nil // nothing to do. + } + + for _, op := range ops { + ref := "" + if op.ReferenceNode { + ref = op.Reference + } + go buildOpFunc(op, opBuildChan, opErrorChan, ref) + } + + n := 0 + total := len(ops) + for n < total { + select { + case buildError := <-opErrorChan: + return buildError + case <-opBuildChan: + n++ + } + } + + // make sure we don't exit before the path is finished building. + if len(ops) > 0 { + wg.Wait() + } + return nil +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/low/v3/paths.go b/vendor/github.com/pb33f/libopenapi/datamodel/low/v3/paths.go new file mode 100644 index 0000000000..c7c8f04461 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/low/v3/paths.go @@ -0,0 +1,176 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package v3 + +import ( + "crypto/sha256" + "fmt" + "sort" + "strings" + + "github.com/pb33f/libopenapi/datamodel/low" + "github.com/pb33f/libopenapi/index" + "github.com/pb33f/libopenapi/utils" + "gopkg.in/yaml.v3" +) + +// Paths represents a high-level OpenAPI 3+ Paths object, that is backed by a low-level one. +// +// Holds the relative paths to the individual endpoints and their operations. The path is appended to the URL from the +// Server Object in order to construct the full URL. The Paths MAY be empty, due to Access Control List (ACL) +// constraints. +// - https://spec.openapis.org/oas/v3.1.0#paths-object +type Paths struct { + PathItems map[low.KeyReference[string]]low.ValueReference[*PathItem] + Extensions map[low.KeyReference[string]]low.ValueReference[any] + *low.Reference +} + +// FindPath will attempt to locate a PathItem using the provided path string. +func (p *Paths) FindPath(path string) *low.ValueReference[*PathItem] { + for k, j := range p.PathItems { + if k.Value == path { + return &j + } + } + return nil +} + +// FindPathAndKey attempts to locate a PathItem instance, given a path key. +func (p *Paths) FindPathAndKey(path string) (*low.KeyReference[string], *low.ValueReference[*PathItem]) { + for k, j := range p.PathItems { + if k.Value == path { + return &k, &j + } + } + return nil, nil +} + +// FindExtension will attempt to locate an extension using the specified string. +func (p *Paths) FindExtension(ext string) *low.ValueReference[any] { + return low.FindItemInMap[any](ext, p.Extensions) +} + +// GetExtensions returns all Paths extensions and satisfies the low.HasExtensions interface. +func (p *Paths) GetExtensions() map[low.KeyReference[string]]low.ValueReference[any] { + return p.Extensions +} + +// Build will extract extensions and all PathItems. This happens asynchronously for speed. +func (p *Paths) Build(root *yaml.Node, idx *index.SpecIndex) error { + p.Reference = new(low.Reference) + p.Extensions = low.ExtractExtensions(root) + skip := false + var currentNode *yaml.Node + + pathsMap := make(map[low.KeyReference[string]]low.ValueReference[*PathItem]) + + // build each new path, in a new thread. + type pathBuildResult struct { + k low.KeyReference[string] + v low.ValueReference[*PathItem] + } + + bChan := make(chan pathBuildResult) + eChan := make(chan error) + buildPathItem := func(cNode, pNode *yaml.Node, b chan<- pathBuildResult, e chan<- error) { + if ok, _, _ := utils.IsNodeRefValue(pNode); ok { + r, err := low.LocateRefNode(pNode, idx) + if r != nil { + pNode = r + if r.Tag == "" { + // If it's a node from file, tag is empty + // If it's a reference we need to extract actual operation node + pNode = r.Content[0] + } + + if err != nil { + if !idx.AllowCircularReferenceResolving() { + e <- fmt.Errorf("path item build failed: %s", err.Error()) + return + } + } + } else { + e <- fmt.Errorf("path item build failed: cannot find reference: %s at line %d, col %d", + pNode.Content[1].Value, pNode.Content[1].Line, pNode.Content[1].Column) + return + } + } + + path := new(PathItem) + _ = low.BuildModel(pNode, path) + err := path.Build(pNode, idx) + if err != nil { + e <- err + return + } + b <- pathBuildResult{ + k: low.KeyReference[string]{ + Value: cNode.Value, + KeyNode: cNode, + }, + v: low.ValueReference[*PathItem]{ + Value: path, + ValueNode: pNode, + }, + } + } + + pathCount := 0 + for i, pathNode := range root.Content { + if strings.HasPrefix(strings.ToLower(pathNode.Value), "x-") { + skip = true + continue + } + if skip { + skip = false + continue + } + if i%2 == 0 { + currentNode = pathNode + continue + } + pathCount++ + go buildPathItem(currentNode, pathNode, bChan, eChan) + } + + completedItems := 0 + for completedItems < pathCount { + select { + case err := <-eChan: + return err + case res := <-bChan: + completedItems++ + pathsMap[res.k] = res.v + } + } + p.PathItems = pathsMap + return nil +} + +// Hash will return a consistent SHA256 Hash of the PathItem object +func (p *Paths) Hash() [32]byte { + var f []string + l := make([]string, len(p.PathItems)) + keys := make(map[string]low.ValueReference[*PathItem]) + z := 0 + for k := range p.PathItems { + keys[k.Value] = p.PathItems[k] + l[z] = k.Value + z++ + } + sort.Strings(l) + for k := range l { + f = append(f, fmt.Sprintf("%s-%s", l[k], low.GenerateHashString(keys[l[k]].Value))) + } + ekeys := make([]string, len(p.Extensions)) + z = 0 + for k := range p.Extensions { + ekeys[z] = fmt.Sprintf("%s-%x", k.Value, sha256.Sum256([]byte(fmt.Sprint(p.Extensions[k].Value)))) + z++ + } + sort.Strings(ekeys) + f = append(f, ekeys...) + return sha256.Sum256([]byte(strings.Join(f, "|"))) +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/low/v3/request_body.go b/vendor/github.com/pb33f/libopenapi/datamodel/low/v3/request_body.go new file mode 100644 index 0000000000..d11c6d8b5c --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/low/v3/request_body.go @@ -0,0 +1,84 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package v3 + +import ( + "crypto/sha256" + "fmt" + "github.com/pb33f/libopenapi/datamodel/low" + "github.com/pb33f/libopenapi/index" + "gopkg.in/yaml.v3" + "sort" + "strings" +) + +// RequestBody represents a low-level OpenAPI 3+ RequestBody object. +// - https://spec.openapis.org/oas/v3.1.0#request-body-object +type RequestBody struct { + Description low.NodeReference[string] + Content low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*MediaType]] + Required low.NodeReference[bool] + Extensions map[low.KeyReference[string]]low.ValueReference[any] + *low.Reference +} + +// FindExtension attempts to locate an extension using the provided name. +func (rb *RequestBody) FindExtension(ext string) *low.ValueReference[any] { + return low.FindItemInMap[any](ext, rb.Extensions) +} + +// GetExtensions returns all RequestBody extensions and satisfies the low.HasExtensions interface. +func (rb *RequestBody) GetExtensions() map[low.KeyReference[string]]low.ValueReference[any] { + return rb.Extensions +} + +// FindContent attempts to find content/MediaType defined using a specified name. +func (rb *RequestBody) FindContent(cType string) *low.ValueReference[*MediaType] { + return low.FindItemInMap[*MediaType](cType, rb.Content.Value) +} + +// Build will extract extensions and MediaType objects from the node. +func (rb *RequestBody) Build(root *yaml.Node, idx *index.SpecIndex) error { + rb.Reference = new(low.Reference) + rb.Extensions = low.ExtractExtensions(root) + + // handle content, if set. + con, cL, cN, cErr := low.ExtractMap[*MediaType](ContentLabel, root, idx) + if cErr != nil { + return cErr + } + if con != nil { + rb.Content = low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*MediaType]]{ + Value: con, + KeyNode: cL, + ValueNode: cN, + } + } + return nil +} + +// Hash will return a consistent SHA256 Hash of the RequestBody object +func (rb *RequestBody) Hash() [32]byte { + var f []string + if rb.Description.Value != "" { + f = append(f, rb.Description.Value) + } + if !rb.Required.IsEmpty() { + f = append(f, fmt.Sprint(rb.Required.Value)) + } + for k := range rb.Content.Value { + f = append(f, low.GenerateHashString(rb.Content.Value[k].Value)) + } + + keys := make([]string, len(rb.Extensions)) + z := 0 + for k := range rb.Extensions { + keys[z] = fmt.Sprintf("%s-%x", k.Value, sha256.Sum256([]byte(fmt.Sprint(rb.Extensions[k].Value)))) + z++ + } + sort.Strings(keys) + f = append(f, keys...) + + return sha256.Sum256([]byte(strings.Join(f, "|"))) +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/low/v3/response.go b/vendor/github.com/pb33f/libopenapi/datamodel/low/v3/response.go new file mode 100644 index 0000000000..4163195c06 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/low/v3/response.go @@ -0,0 +1,139 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package v3 + +import ( + "crypto/sha256" + "fmt" + "github.com/pb33f/libopenapi/datamodel/low" + "github.com/pb33f/libopenapi/index" + "gopkg.in/yaml.v3" + "sort" + "strings" +) + +// Response represents a high-level OpenAPI 3+ Response object that is backed by a low-level one. +// +// Describes a single response from an API Operation, including design-time, static links to +// operations based on the response. +// - https://spec.openapis.org/oas/v3.1.0#response-object +type Response struct { + Description low.NodeReference[string] + Headers low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*Header]] + Content low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*MediaType]] + Extensions map[low.KeyReference[string]]low.ValueReference[any] + Links low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*Link]] + *low.Reference +} + +// FindExtension will attempt to locate an extension using the supplied key +func (r *Response) FindExtension(ext string) *low.ValueReference[any] { + return low.FindItemInMap[any](ext, r.Extensions) +} + +// GetExtensions returns all OAuthFlow extensions and satisfies the low.HasExtensions interface. +func (r *Response) GetExtensions() map[low.KeyReference[string]]low.ValueReference[any] { + return r.Extensions +} + +// FindContent will attempt to locate a MediaType instance using the supplied key. +func (r *Response) FindContent(cType string) *low.ValueReference[*MediaType] { + return low.FindItemInMap[*MediaType](cType, r.Content.Value) +} + +// FindHeader will attempt to locate a Header instance using the supplied key. +func (r *Response) FindHeader(hType string) *low.ValueReference[*Header] { + return low.FindItemInMap[*Header](hType, r.Headers.Value) +} + +// FindLink will attempt to locate a Link instance using the supplied key. +func (r *Response) FindLink(hType string) *low.ValueReference[*Link] { + return low.FindItemInMap[*Link](hType, r.Links.Value) +} + +// Build will extract headers, extensions, content and links from node. +func (r *Response) Build(root *yaml.Node, idx *index.SpecIndex) error { + r.Reference = new(low.Reference) + r.Extensions = low.ExtractExtensions(root) + + //extract headers + headers, lN, kN, err := low.ExtractMapExtensions[*Header](HeadersLabel, root, idx, true) + if err != nil { + return err + } + if headers != nil { + r.Headers = low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*Header]]{ + Value: headers, + KeyNode: lN, + ValueNode: kN, + } + } + + con, clN, cN, cErr := low.ExtractMap[*MediaType](ContentLabel, root, idx) + if cErr != nil { + return cErr + } + if con != nil { + r.Content = low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*MediaType]]{ + Value: con, + KeyNode: clN, + ValueNode: cN, + } + } + + // handle links if set + links, linkLabel, linkValue, lErr := low.ExtractMap[*Link](LinksLabel, root, idx) + if lErr != nil { + return lErr + } + if links != nil { + r.Links = low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*Link]]{ + Value: links, + KeyNode: linkLabel, + ValueNode: linkValue, + } + } + return nil +} + +// Hash will return a consistent SHA256 Hash of the Response object +func (r *Response) Hash() [32]byte { + var f []string + if r.Description.Value != "" { + f = append(f, r.Description.Value) + } + keys := make([]string, len(r.Headers.Value)) + z := 0 + for k := range r.Headers.Value { + keys[z] = fmt.Sprintf("%s-%s", k.Value, low.GenerateHashString(r.Headers.Value[k].Value)) + z++ + } + sort.Strings(keys) + f = append(f, keys...) + keys = make([]string, len(r.Content.Value)) + z = 0 + for k := range r.Content.Value { + keys[z] = fmt.Sprintf("%s-%s", k.Value, low.GenerateHashString(r.Content.Value[k].Value)) + z++ + } + sort.Strings(keys) + f = append(f, keys...) + keys = make([]string, len(r.Links.Value)) + z = 0 + for k := range r.Links.Value { + keys[z] = fmt.Sprintf("%s-%s", k.Value, low.GenerateHashString(r.Links.Value[k].Value)) + z++ + } + sort.Strings(keys) + f = append(f, keys...) + keys = make([]string, len(r.Extensions)) + z = 0 + for k := range r.Extensions { + keys[z] = fmt.Sprintf("%s-%x", k.Value, sha256.Sum256([]byte(fmt.Sprint(r.Extensions[k].Value)))) + z++ + } + sort.Strings(keys) + f = append(f, keys...) + return sha256.Sum256([]byte(strings.Join(f, "|"))) +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/low/v3/responses.go b/vendor/github.com/pb33f/libopenapi/datamodel/low/v3/responses.go new file mode 100644 index 0000000000..7a40c7bd7f --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/low/v3/responses.go @@ -0,0 +1,138 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package v3 + +import ( + "crypto/sha256" + "fmt" + "github.com/pb33f/libopenapi/datamodel/low" + "github.com/pb33f/libopenapi/index" + "github.com/pb33f/libopenapi/utils" + "gopkg.in/yaml.v3" + "sort" + "strings" +) + +// Responses represents a low-level OpenAPI 3+ Responses object. +// +// It's a container for the expected responses of an operation. The container maps an HTTP response code to the +// expected response. +// +// The specification is not necessarily expected to cover all possible HTTP response codes because they may not be +// known in advance. However, documentation is expected to cover a successful operation response and any known errors. +// +// The default MAY be used as a default response object for all HTTP codes that are not covered individually by +// the Responses Object. +// +// The Responses Object MUST contain at least one response code, and if only one response code is provided it SHOULD +// be the response for a successful operation call. +// - https://spec.openapis.org/oas/v3.1.0#responses-object +// +// This structure is identical to the v2 version, however they use different response types, hence +// the duplication. Perhaps in the future we could use generics here, but for now to keep things +// simple, they are broken out into individual versions. +type Responses struct { + Codes map[low.KeyReference[string]]low.ValueReference[*Response] + Default low.NodeReference[*Response] + Extensions map[low.KeyReference[string]]low.ValueReference[any] + *low.Reference +} + +// GetExtensions returns all Responses extensions and satisfies the low.HasExtensions interface. +func (r *Responses) GetExtensions() map[low.KeyReference[string]]low.ValueReference[any] { + return r.Extensions +} + +// Build will extract default response and all Response objects for each code +func (r *Responses) Build(root *yaml.Node, idx *index.SpecIndex) error { + r.Reference = new(low.Reference) + r.Extensions = low.ExtractExtensions(root) + if utils.IsNodeMap(root) { + codes, err := low.ExtractMapNoLookup[*Response](root, idx) + + if err != nil { + return err + } + if codes != nil { + r.Codes = codes + } + + def := r.getDefault() + if def != nil { + // default is bundled into codes, pull it out + r.Default = *def + // remove default from codes + r.deleteCode(DefaultLabel) + } + } else { + return fmt.Errorf("responses build failed: vn node is not a map! line %d, col %d", + root.Line, root.Column) + } + return nil +} + +func (r *Responses) getDefault() *low.NodeReference[*Response] { + for n, o := range r.Codes { + if strings.ToLower(n.Value) == DefaultLabel { + return &low.NodeReference[*Response]{ + ValueNode: o.ValueNode, + KeyNode: n.KeyNode, + Value: o.Value, + } + } + } + return nil +} + +// used to remove default from codes extracted by Build() +func (r *Responses) deleteCode(code string) { + var key *low.KeyReference[string] + if r.Codes != nil { + for k := range r.Codes { + if k.Value == code { + key = &k + break + } + } + } + // should never be nil, but, you never know... science and all that! + if key != nil { + delete(r.Codes, *key) + } +} + +// FindResponseByCode will attempt to locate a Response using an HTTP response code. +func (r *Responses) FindResponseByCode(code string) *low.ValueReference[*Response] { + return low.FindItemInMap[*Response](code, r.Codes) +} + +// Hash will return a consistent SHA256 Hash of the Examples object +func (r *Responses) Hash() [32]byte { + var f []string + var keys []string + keys = make([]string, len(r.Codes)) + cMap := make(map[string]*Response, len(keys)) + z := 0 + for k := range r.Codes { + keys[z] = k.Value + cMap[k.Value] = r.Codes[k].Value + z++ + } + sort.Strings(keys) + for k := range keys { + f = append(f, fmt.Sprintf("%s-%s", keys[k], low.GenerateHashString(cMap[keys[k]]))) + } + if !r.Default.IsEmpty() { + f = append(f, low.GenerateHashString(r.Default.Value)) + } + keys = make([]string, len(r.Extensions)) + z = 0 + for k := range r.Extensions { + keys[z] = fmt.Sprintf("%s-%x", k.Value, sha256.Sum256([]byte(fmt.Sprint(r.Extensions[k].Value)))) + z++ + } + sort.Strings(keys) + f = append(f, keys...) + return sha256.Sum256([]byte(strings.Join(f, "|"))) +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/low/v3/security_scheme.go b/vendor/github.com/pb33f/libopenapi/datamodel/low/v3/security_scheme.go new file mode 100644 index 0000000000..468a8c857f --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/low/v3/security_scheme.go @@ -0,0 +1,100 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package v3 + +import ( + "crypto/sha256" + "fmt" + "github.com/pb33f/libopenapi/datamodel/low" + "github.com/pb33f/libopenapi/index" + "gopkg.in/yaml.v3" + "sort" + "strings" +) + +// SecurityScheme represents a low-level OpenAPI 3+ SecurityScheme object. +// +// Defines a security scheme that can be used by the operations. +// +// Supported schemes are HTTP authentication, an API key (either as a header, a cookie parameter or as a query parameter), +// mutual TLS (use of a client certificate), OAuth2’s common flows (implicit, password, client credentials and +// authorization code) as defined in RFC6749 (https://www.rfc-editor.org/rfc/rfc6749), and OpenID Connect Discovery. +// Please note that as of 2020, the implicit flow is about to be deprecated by OAuth 2.0 Security Best Current Practice. +// Recommended for most use case is Authorization Code Grant flow with PKCE. +// - https://spec.openapis.org/oas/v3.1.0#security-scheme-object +type SecurityScheme struct { + Type low.NodeReference[string] + Description low.NodeReference[string] + Name low.NodeReference[string] + In low.NodeReference[string] + Scheme low.NodeReference[string] + BearerFormat low.NodeReference[string] + Flows low.NodeReference[*OAuthFlows] + OpenIdConnectUrl low.NodeReference[string] + Extensions map[low.KeyReference[string]]low.ValueReference[any] + *low.Reference +} + +// FindExtension attempts to locate an extension using the supplied key. +func (ss *SecurityScheme) FindExtension(ext string) *low.ValueReference[any] { + return low.FindItemInMap[any](ext, ss.Extensions) +} + +// GetExtensions returns all SecurityScheme extensions and satisfies the low.HasExtensions interface. +func (ss *SecurityScheme) GetExtensions() map[low.KeyReference[string]]low.ValueReference[any] { + return ss.Extensions +} + +// Build will extract OAuthFlows and extensions from the node. +func (ss *SecurityScheme) Build(root *yaml.Node, idx *index.SpecIndex) error { + ss.Reference = new(low.Reference) + ss.Extensions = low.ExtractExtensions(root) + + oa, oaErr := low.ExtractObject[*OAuthFlows](OAuthFlowsLabel, root, idx) + if oaErr != nil { + return oaErr + } + if oa.Value != nil { + ss.Flows = oa + } + return nil +} + +// Hash will return a consistent SHA256 Hash of the SecurityScheme object +func (ss *SecurityScheme) Hash() [32]byte { + var f []string + if !ss.Type.IsEmpty() { + f = append(f, ss.Type.Value) + } + if !ss.Description.IsEmpty() { + f = append(f, ss.Description.Value) + } + if !ss.Name.IsEmpty() { + f = append(f, ss.Name.Value) + } + if !ss.In.IsEmpty() { + f = append(f, ss.In.Value) + } + if !ss.Scheme.IsEmpty() { + f = append(f, ss.Scheme.Value) + } + if !ss.BearerFormat.IsEmpty() { + f = append(f, ss.BearerFormat.Value) + } + if !ss.Flows.IsEmpty() { + f = append(f, low.GenerateHashString(ss.Flows.Value)) + } + if !ss.OpenIdConnectUrl.IsEmpty() { + f = append(f, ss.OpenIdConnectUrl.Value) + } + keys := make([]string, len(ss.Extensions)) + z := 0 + for k := range ss.Extensions { + keys[z] = fmt.Sprintf("%s-%x", k.Value, sha256.Sum256([]byte(fmt.Sprint(ss.Extensions[k].Value)))) + z++ + } + sort.Strings(keys) + f = append(f, keys...) + return sha256.Sum256([]byte(strings.Join(f, "|"))) +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/low/v3/server.go b/vendor/github.com/pb33f/libopenapi/datamodel/low/v3/server.go new file mode 100644 index 0000000000..92e22105ef --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/low/v3/server.go @@ -0,0 +1,92 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package v3 + +import ( + "crypto/sha256" + "github.com/pb33f/libopenapi/datamodel/low" + "github.com/pb33f/libopenapi/index" + "github.com/pb33f/libopenapi/utils" + "gopkg.in/yaml.v3" + "sort" + "strings" +) + +// Server represents a low-level OpenAPI 3+ Server object. +// - https://spec.openapis.org/oas/v3.1.0#server-object +type Server struct { + URL low.NodeReference[string] + Description low.NodeReference[string] + Variables low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*ServerVariable]] + Extensions map[low.KeyReference[string]]low.ValueReference[any] + *low.Reference +} + +// GetExtensions returns all Paths extensions and satisfies the low.HasExtensions interface. +func (s *Server) GetExtensions() map[low.KeyReference[string]]low.ValueReference[any] { + return s.Extensions +} + +// FindVariable attempts to locate a ServerVariable instance using the supplied key. +func (s *Server) FindVariable(serverVar string) *low.ValueReference[*ServerVariable] { + return low.FindItemInMap[*ServerVariable](serverVar, s.Variables.Value) +} + +// Build will extract server variables from the supplied node. +func (s *Server) Build(root *yaml.Node, idx *index.SpecIndex) error { + s.Reference = new(low.Reference) + s.Extensions = low.ExtractExtensions(root) + kn, vars := utils.FindKeyNode(VariablesLabel, root.Content) + if vars == nil { + return nil + } + variablesMap := make(map[low.KeyReference[string]]low.ValueReference[*ServerVariable]) + if utils.IsNodeMap(vars) { + var currentNode string + var keyNode *yaml.Node + for i, varNode := range vars.Content { + if i%2 == 0 { + currentNode = varNode.Value + keyNode = varNode + continue + } + variable := ServerVariable{} + variable.Reference = new(low.Reference) + _ = low.BuildModel(varNode, &variable) + variablesMap[low.KeyReference[string]{ + Value: currentNode, + KeyNode: keyNode, + }] = low.ValueReference[*ServerVariable]{ + ValueNode: varNode, + Value: &variable, + } + } + s.Variables = low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*ServerVariable]]{ + KeyNode: kn, + ValueNode: vars, + Value: variablesMap, + } + } + return nil +} + +// Hash will return a consistent SHA256 Hash of the Server object +func (s *Server) Hash() [32]byte { + var f []string + keys := make([]string, len(s.Variables.Value)) + z := 0 + for k := range s.Variables.Value { + keys[z] = low.GenerateHashString(s.Variables.Value[k].Value) + z++ + } + sort.Strings(keys) + f = append(f, keys...) + if !s.URL.IsEmpty() { + f = append(f, s.URL.Value) + } + if !s.Description.IsEmpty() { + f = append(f, s.Description.Value) + } + return sha256.Sum256([]byte(strings.Join(f, "|"))) +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/low/v3/server_variable.go b/vendor/github.com/pb33f/libopenapi/datamodel/low/v3/server_variable.go new file mode 100644 index 0000000000..e538a3ca0d --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/low/v3/server_variable.go @@ -0,0 +1,43 @@ +package v3 + +import ( + "crypto/sha256" + "fmt" + "github.com/pb33f/libopenapi/datamodel/low" + "sort" + "strings" +) + +// ServerVariable represents a low-level OpenAPI 3+ ServerVariable object. +// +// ServerVariable is an object representing a Server Variable for server URL template substitution. +// - https://spec.openapis.org/oas/v3.1.0#server-variable-object +// +// This is the only struct that is not Buildable, it's not used by anything other than a Server instance, +// and it has nothing to build that requires it to be buildable. +type ServerVariable struct { + Enum []low.NodeReference[string] + Default low.NodeReference[string] + Description low.NodeReference[string] + *low.Reference +} + +// Hash will return a consistent SHA256 Hash of the ServerVariable object +func (s *ServerVariable) Hash() [32]byte { + var f []string + keys := make([]string, len(s.Enum)) + z := 0 + for k := range s.Enum { + keys[z] = fmt.Sprint(s.Enum[k].Value) + z++ + } + sort.Strings(keys) + f = append(f, keys...) + if !s.Default.IsEmpty() { + f = append(f, s.Default.Value) + } + if !s.Description.IsEmpty() { + f = append(f, s.Description.Value) + } + return sha256.Sum256([]byte(strings.Join(f, "|"))) +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/schemas/oas3-schema.json b/vendor/github.com/pb33f/libopenapi/datamodel/schemas/oas3-schema.json new file mode 100644 index 0000000000..4360553fe5 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/schemas/oas3-schema.json @@ -0,0 +1,1662 @@ +{ + "id": "https://spec.openapis.org/oas/3.0/schema/2021-09-28", + "$schema": "http://json-schema.org/draft-04/schema#", + "description": "The description of OpenAPI v3.0.x documents, as defined by https://spec.openapis.org/oas/v3.0.3", + "type": "object", + "required": [ + "openapi", + "info", + "paths" + ], + "properties": { + "openapi": { + "type": "string", + "pattern": "^3\\.0\\.\\d(-.+)?$" + }, + "info": { + "$ref": "#/definitions/Info" + }, + "externalDocs": { + "$ref": "#/definitions/ExternalDocumentation" + }, + "servers": { + "type": "array", + "items": { + "$ref": "#/definitions/Server" + } + }, + "security": { + "type": "array", + "items": { + "$ref": "#/definitions/SecurityRequirement" + } + }, + "tags": { + "type": "array", + "items": { + "$ref": "#/definitions/Tag" + }, + "uniqueItems": true + }, + "paths": { + "$ref": "#/definitions/Paths" + }, + "components": { + "$ref": "#/definitions/Components" + } + }, + "patternProperties": { + "^x-": { + } + }, + "additionalProperties": false, + "definitions": { + "Reference": { + "type": "object", + "required": [ + "$ref" + ], + "patternProperties": { + "^\\$ref$": { + "type": "string", + "format": "uri-reference" + } + } + }, + "Info": { + "type": "object", + "required": [ + "title", + "version" + ], + "properties": { + "title": { + "type": "string" + }, + "description": { + "type": "string" + }, + "termsOfService": { + "type": "string", + "format": "uri-reference" + }, + "contact": { + "$ref": "#/definitions/Contact" + }, + "license": { + "$ref": "#/definitions/License" + }, + "version": { + "type": "string" + } + }, + "patternProperties": { + "^x-": { + } + }, + "additionalProperties": false + }, + "Contact": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "url": { + "type": "string", + "format": "uri-reference" + }, + "email": { + "type": "string", + "format": "email" + } + }, + "patternProperties": { + "^x-": { + } + }, + "additionalProperties": false + }, + "License": { + "type": "object", + "required": [ + "name" + ], + "properties": { + "name": { + "type": "string" + }, + "url": { + "type": "string", + "format": "uri-reference" + } + }, + "patternProperties": { + "^x-": { + } + }, + "additionalProperties": false + }, + "Server": { + "type": "object", + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string" + }, + "description": { + "type": "string" + }, + "variables": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/ServerVariable" + } + } + }, + "patternProperties": { + "^x-": { + } + }, + "additionalProperties": false + }, + "ServerVariable": { + "type": "object", + "required": [ + "default" + ], + "properties": { + "enum": { + "type": "array", + "items": { + "type": "string" + } + }, + "default": { + "type": "string" + }, + "description": { + "type": "string" + } + }, + "patternProperties": { + "^x-": { + } + }, + "additionalProperties": false + }, + "Components": { + "type": "object", + "properties": { + "schemas": { + "type": "object", + "patternProperties": { + "^[a-zA-Z0-9\\.\\-_]+$": { + "oneOf": [ + { + "$ref": "#/definitions/Schema" + }, + { + "$ref": "#/definitions/Reference" + } + ] + } + } + }, + "responses": { + "type": "object", + "patternProperties": { + "^[a-zA-Z0-9\\.\\-_]+$": { + "oneOf": [ + { + "$ref": "#/definitions/Reference" + }, + { + "$ref": "#/definitions/Response" + } + ] + } + } + }, + "parameters": { + "type": "object", + "patternProperties": { + "^[a-zA-Z0-9\\.\\-_]+$": { + "oneOf": [ + { + "$ref": "#/definitions/Reference" + }, + { + "$ref": "#/definitions/Parameter" + } + ] + } + } + }, + "examples": { + "type": "object", + "patternProperties": { + "^[a-zA-Z0-9\\.\\-_]+$": { + "oneOf": [ + { + "$ref": "#/definitions/Reference" + }, + { + "$ref": "#/definitions/Example" + } + ] + } + } + }, + "requestBodies": { + "type": "object", + "patternProperties": { + "^[a-zA-Z0-9\\.\\-_]+$": { + "oneOf": [ + { + "$ref": "#/definitions/Reference" + }, + { + "$ref": "#/definitions/RequestBody" + } + ] + } + } + }, + "headers": { + "type": "object", + "patternProperties": { + "^[a-zA-Z0-9\\.\\-_]+$": { + "oneOf": [ + { + "$ref": "#/definitions/Reference" + }, + { + "$ref": "#/definitions/Header" + } + ] + } + } + }, + "securitySchemes": { + "type": "object", + "patternProperties": { + "^[a-zA-Z0-9\\.\\-_]+$": { + "oneOf": [ + { + "$ref": "#/definitions/Reference" + }, + { + "$ref": "#/definitions/SecurityScheme" + } + ] + } + } + }, + "links": { + "type": "object", + "patternProperties": { + "^[a-zA-Z0-9\\.\\-_]+$": { + "oneOf": [ + { + "$ref": "#/definitions/Reference" + }, + { + "$ref": "#/definitions/Link" + } + ] + } + } + }, + "callbacks": { + "type": "object", + "patternProperties": { + "^[a-zA-Z0-9\\.\\-_]+$": { + "oneOf": [ + { + "$ref": "#/definitions/Reference" + }, + { + "$ref": "#/definitions/Callback" + } + ] + } + } + } + }, + "patternProperties": { + "^x-": { + } + }, + "additionalProperties": false + }, + "Schema": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "multipleOf": { + "type": "number", + "minimum": 0, + "exclusiveMinimum": true + }, + "maximum": { + "type": "number" + }, + "exclusiveMaximum": { + "type": "boolean", + "default": false + }, + "minimum": { + "type": "number" + }, + "exclusiveMinimum": { + "type": "boolean", + "default": false + }, + "maxLength": { + "type": "integer", + "minimum": 0 + }, + "minLength": { + "type": "integer", + "minimum": 0, + "default": 0 + }, + "pattern": { + "type": "string", + "format": "regex" + }, + "maxItems": { + "type": "integer", + "minimum": 0 + }, + "minItems": { + "type": "integer", + "minimum": 0, + "default": 0 + }, + "uniqueItems": { + "type": "boolean", + "default": false + }, + "maxProperties": { + "type": "integer", + "minimum": 0 + }, + "minProperties": { + "type": "integer", + "minimum": 0, + "default": 0 + }, + "required": { + "type": "array", + "items": { + "type": "string" + }, + "minItems": 1, + "uniqueItems": true + }, + "enum": { + "type": "array", + "items": { + }, + "minItems": 1, + "uniqueItems": false + }, + "type": { + "type": "string", + "enum": [ + "array", + "boolean", + "integer", + "number", + "object", + "string" + ] + }, + "not": { + "oneOf": [ + { + "$ref": "#/definitions/Schema" + }, + { + "$ref": "#/definitions/Reference" + } + ] + }, + "allOf": { + "type": "array", + "items": { + "oneOf": [ + { + "$ref": "#/definitions/Schema" + }, + { + "$ref": "#/definitions/Reference" + } + ] + } + }, + "oneOf": { + "type": "array", + "items": { + "oneOf": [ + { + "$ref": "#/definitions/Schema" + }, + { + "$ref": "#/definitions/Reference" + } + ] + } + }, + "anyOf": { + "type": "array", + "items": { + "oneOf": [ + { + "$ref": "#/definitions/Schema" + }, + { + "$ref": "#/definitions/Reference" + } + ] + } + }, + "items": { + "oneOf": [ + { + "$ref": "#/definitions/Schema" + }, + { + "$ref": "#/definitions/Reference" + } + ] + }, + "properties": { + "type": "object", + "additionalProperties": { + "oneOf": [ + { + "$ref": "#/definitions/Schema" + }, + { + "$ref": "#/definitions/Reference" + } + ] + } + }, + "additionalProperties": { + "oneOf": [ + { + "$ref": "#/definitions/Schema" + }, + { + "$ref": "#/definitions/Reference" + }, + { + "type": "boolean" + } + ], + "default": true + }, + "description": { + "type": "string" + }, + "format": { + "type": "string" + }, + "default": { + }, + "nullable": { + "type": "boolean", + "default": false + }, + "discriminator": { + "$ref": "#/definitions/Discriminator" + }, + "readOnly": { + "type": "boolean", + "default": false + }, + "writeOnly": { + "type": "boolean", + "default": false + }, + "example": { + }, + "externalDocs": { + "$ref": "#/definitions/ExternalDocumentation" + }, + "deprecated": { + "type": "boolean", + "default": false + }, + "xml": { + "$ref": "#/definitions/XML" + } + }, + "patternProperties": { + "^x-": { + } + }, + "additionalProperties": false + }, + "Discriminator": { + "type": "object", + "required": [ + "propertyName" + ], + "properties": { + "propertyName": { + "type": "string" + }, + "mapping": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + }, + "XML": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "namespace": { + "type": "string", + "format": "uri" + }, + "prefix": { + "type": "string" + }, + "attribute": { + "type": "boolean", + "default": false + }, + "wrapped": { + "type": "boolean", + "default": false + } + }, + "patternProperties": { + "^x-": { + } + }, + "additionalProperties": false + }, + "Response": { + "type": "object", + "required": [ + "description" + ], + "properties": { + "description": { + "type": "string" + }, + "headers": { + "type": "object", + "additionalProperties": { + "oneOf": [ + { + "$ref": "#/definitions/Header" + }, + { + "$ref": "#/definitions/Reference" + } + ] + } + }, + "content": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/MediaType" + } + }, + "links": { + "type": "object", + "additionalProperties": { + "oneOf": [ + { + "$ref": "#/definitions/Link" + }, + { + "$ref": "#/definitions/Reference" + } + ] + } + } + }, + "patternProperties": { + "^x-": { + } + }, + "additionalProperties": false + }, + "MediaType": { + "type": "object", + "properties": { + "schema": { + "oneOf": [ + { + "$ref": "#/definitions/Schema" + }, + { + "$ref": "#/definitions/Reference" + } + ] + }, + "example": { + }, + "examples": { + "type": "object", + "additionalProperties": { + "oneOf": [ + { + "$ref": "#/definitions/Example" + }, + { + "$ref": "#/definitions/Reference" + } + ] + } + }, + "encoding": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/Encoding" + } + } + }, + "patternProperties": { + "^x-": { + } + }, + "additionalProperties": false, + "allOf": [ + { + "$ref": "#/definitions/ExampleXORExamples" + } + ] + }, + "Example": { + "type": "object", + "properties": { + "summary": { + "type": "string" + }, + "description": { + "type": "string" + }, + "value": { + }, + "externalValue": { + "type": "string", + "format": "uri-reference" + } + }, + "patternProperties": { + "^x-": { + } + }, + "additionalProperties": false + }, + "Header": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "required": { + "type": "boolean", + "default": false + }, + "deprecated": { + "type": "boolean", + "default": false + }, + "allowEmptyValue": { + "type": "boolean", + "default": false + }, + "style": { + "type": "string", + "enum": [ + "simple" + ], + "default": "simple" + }, + "explode": { + "type": "boolean" + }, + "allowReserved": { + "type": "boolean", + "default": false + }, + "schema": { + "oneOf": [ + { + "$ref": "#/definitions/Schema" + }, + { + "$ref": "#/definitions/Reference" + } + ] + }, + "content": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/MediaType" + }, + "minProperties": 1, + "maxProperties": 1 + }, + "example": { + }, + "examples": { + "type": "object", + "additionalProperties": { + "oneOf": [ + { + "$ref": "#/definitions/Example" + }, + { + "$ref": "#/definitions/Reference" + } + ] + } + } + }, + "patternProperties": { + "^x-": { + } + }, + "additionalProperties": false, + "allOf": [ + { + "$ref": "#/definitions/ExampleXORExamples" + }, + { + "$ref": "#/definitions/SchemaXORContent" + } + ] + }, + "Paths": { + "type": "object", + "patternProperties": { + "^\\/": { + "$ref": "#/definitions/PathItem" + }, + "^x-": { + } + }, + "additionalProperties": false + }, + "PathItem": { + "type": "object", + "properties": { + "$ref": { + "type": "string" + }, + "summary": { + "type": "string" + }, + "description": { + "type": "string" + }, + "servers": { + "type": "array", + "items": { + "$ref": "#/definitions/Server" + } + }, + "parameters": { + "type": "array", + "items": { + "oneOf": [ + { + "$ref": "#/definitions/Parameter" + }, + { + "$ref": "#/definitions/Reference" + } + ] + }, + "uniqueItems": true + } + }, + "patternProperties": { + "^(get|put|post|delete|options|head|patch|trace)$": { + "$ref": "#/definitions/Operation" + }, + "^x-": { + } + }, + "additionalProperties": false + }, + "Operation": { + "type": "object", + "required": [ + "responses" + ], + "properties": { + "tags": { + "type": "array", + "items": { + "type": "string" + } + }, + "summary": { + "type": "string" + }, + "description": { + "type": "string" + }, + "externalDocs": { + "$ref": "#/definitions/ExternalDocumentation" + }, + "operationId": { + "type": "string" + }, + "parameters": { + "type": "array", + "items": { + "oneOf": [ + { + "$ref": "#/definitions/Parameter" + }, + { + "$ref": "#/definitions/Reference" + } + ] + }, + "uniqueItems": true + }, + "requestBody": { + "oneOf": [ + { + "$ref": "#/definitions/RequestBody" + }, + { + "$ref": "#/definitions/Reference" + } + ] + }, + "responses": { + "$ref": "#/definitions/Responses" + }, + "callbacks": { + "type": "object", + "additionalProperties": { + "oneOf": [ + { + "$ref": "#/definitions/Callback" + }, + { + "$ref": "#/definitions/Reference" + } + ] + } + }, + "deprecated": { + "type": "boolean", + "default": false + }, + "security": { + "type": "array", + "items": { + "$ref": "#/definitions/SecurityRequirement" + } + }, + "servers": { + "type": "array", + "items": { + "$ref": "#/definitions/Server" + } + } + }, + "patternProperties": { + "^x-": { + } + }, + "additionalProperties": false + }, + "Responses": { + "type": "object", + "properties": { + "default": { + "oneOf": [ + { + "$ref": "#/definitions/Response" + }, + { + "$ref": "#/definitions/Reference" + } + ] + } + }, + "patternProperties": { + "^[1-5](?:\\d{2}|XX)$": { + "oneOf": [ + { + "$ref": "#/definitions/Response" + }, + { + "$ref": "#/definitions/Reference" + } + ] + }, + "^x-": { + } + }, + "minProperties": 1, + "additionalProperties": false + }, + "SecurityRequirement": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "Tag": { + "type": "object", + "required": [ + "name" + ], + "properties": { + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "externalDocs": { + "$ref": "#/definitions/ExternalDocumentation" + } + }, + "patternProperties": { + "^x-": { + } + }, + "additionalProperties": false + }, + "ExternalDocumentation": { + "type": "object", + "required": [ + "url" + ], + "properties": { + "description": { + "type": "string" + }, + "url": { + "type": "string", + "format": "uri-reference" + } + }, + "patternProperties": { + "^x-": { + } + }, + "additionalProperties": false + }, + "ExampleXORExamples": { + "description": "Example and examples are mutually exclusive", + "not": { + "required": [ + "example", + "examples" + ] + } + }, + "SchemaXORContent": { + "description": "Schema and content are mutually exclusive, at least one is required", + "not": { + "required": [ + "schema", + "content" + ] + }, + "oneOf": [ + { + "required": [ + "schema" + ] + }, + { + "required": [ + "content" + ], + "description": "Some properties are not allowed if content is present", + "allOf": [ + { + "not": { + "required": [ + "style" + ] + } + }, + { + "not": { + "required": [ + "explode" + ] + } + }, + { + "not": { + "required": [ + "allowReserved" + ] + } + }, + { + "not": { + "required": [ + "example" + ] + } + }, + { + "not": { + "required": [ + "examples" + ] + } + } + ] + } + ] + }, + "Parameter": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "in": { + "type": "string" + }, + "description": { + "type": "string" + }, + "required": { + "type": "boolean", + "default": false + }, + "deprecated": { + "type": "boolean", + "default": false + }, + "allowEmptyValue": { + "type": "boolean", + "default": false + }, + "style": { + "type": "string" + }, + "explode": { + "type": "boolean" + }, + "allowReserved": { + "type": "boolean", + "default": false + }, + "schema": { + "oneOf": [ + { + "$ref": "#/definitions/Schema" + }, + { + "$ref": "#/definitions/Reference" + } + ] + }, + "content": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/MediaType" + }, + "minProperties": 1, + "maxProperties": 1 + }, + "example": { + }, + "examples": { + "type": "object", + "additionalProperties": { + "oneOf": [ + { + "$ref": "#/definitions/Example" + }, + { + "$ref": "#/definitions/Reference" + } + ] + } + } + }, + "patternProperties": { + "^x-": { + } + }, + "additionalProperties": false, + "required": [ + "name", + "in" + ], + "allOf": [ + { + "$ref": "#/definitions/ExampleXORExamples" + }, + { + "$ref": "#/definitions/SchemaXORContent" + }, + { + "$ref": "#/definitions/ParameterLocation" + } + ] + }, + "ParameterLocation": { + "description": "Parameter location", + "oneOf": [ + { + "description": "Parameter in path", + "required": [ + "required" + ], + "properties": { + "in": { + "enum": [ + "path" + ] + }, + "style": { + "enum": [ + "matrix", + "label", + "simple" + ], + "default": "simple" + }, + "required": { + "enum": [ + true + ] + } + } + }, + { + "description": "Parameter in query", + "properties": { + "in": { + "enum": [ + "query" + ] + }, + "style": { + "enum": [ + "form", + "spaceDelimited", + "pipeDelimited", + "deepObject" + ], + "default": "form" + } + } + }, + { + "description": "Parameter in header", + "properties": { + "in": { + "enum": [ + "header" + ] + }, + "style": { + "enum": [ + "simple" + ], + "default": "simple" + } + } + }, + { + "description": "Parameter in cookie", + "properties": { + "in": { + "enum": [ + "cookie" + ] + }, + "style": { + "enum": [ + "form" + ], + "default": "form" + } + } + } + ] + }, + "RequestBody": { + "type": "object", + "required": [ + "content" + ], + "properties": { + "description": { + "type": "string" + }, + "content": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/MediaType" + } + }, + "required": { + "type": "boolean", + "default": false + } + }, + "patternProperties": { + "^x-": { + } + }, + "additionalProperties": false + }, + "SecurityScheme": { + "oneOf": [ + { + "$ref": "#/definitions/APIKeySecurityScheme" + }, + { + "$ref": "#/definitions/HTTPSecurityScheme" + }, + { + "$ref": "#/definitions/OAuth2SecurityScheme" + }, + { + "$ref": "#/definitions/OpenIdConnectSecurityScheme" + } + ] + }, + "APIKeySecurityScheme": { + "type": "object", + "required": [ + "type", + "name", + "in" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "apiKey" + ] + }, + "name": { + "type": "string" + }, + "in": { + "type": "string", + "enum": [ + "header", + "query", + "cookie" + ] + }, + "description": { + "type": "string" + } + }, + "patternProperties": { + "^x-": { + } + }, + "additionalProperties": false + }, + "HTTPSecurityScheme": { + "type": "object", + "required": [ + "scheme", + "type" + ], + "properties": { + "scheme": { + "type": "string" + }, + "bearerFormat": { + "type": "string" + }, + "description": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "http" + ] + } + }, + "patternProperties": { + "^x-": { + } + }, + "additionalProperties": false, + "oneOf": [ + { + "description": "Bearer", + "properties": { + "scheme": { + "type": "string", + "pattern": "^[Bb][Ee][Aa][Rr][Ee][Rr]$" + } + } + }, + { + "description": "Non Bearer", + "not": { + "required": [ + "bearerFormat" + ] + }, + "properties": { + "scheme": { + "not": { + "type": "string", + "pattern": "^[Bb][Ee][Aa][Rr][Ee][Rr]$" + } + } + } + } + ] + }, + "OAuth2SecurityScheme": { + "type": "object", + "required": [ + "type", + "flows" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "oauth2" + ] + }, + "flows": { + "$ref": "#/definitions/OAuthFlows" + }, + "description": { + "type": "string" + } + }, + "patternProperties": { + "^x-": { + } + }, + "additionalProperties": false + }, + "OpenIdConnectSecurityScheme": { + "type": "object", + "required": [ + "type", + "openIdConnectUrl" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "openIdConnect" + ] + }, + "openIdConnectUrl": { + "type": "string", + "format": "uri-reference" + }, + "description": { + "type": "string" + } + }, + "patternProperties": { + "^x-": { + } + }, + "additionalProperties": false + }, + "OAuthFlows": { + "type": "object", + "properties": { + "implicit": { + "$ref": "#/definitions/ImplicitOAuthFlow" + }, + "password": { + "$ref": "#/definitions/PasswordOAuthFlow" + }, + "clientCredentials": { + "$ref": "#/definitions/ClientCredentialsFlow" + }, + "authorizationCode": { + "$ref": "#/definitions/AuthorizationCodeOAuthFlow" + } + }, + "patternProperties": { + "^x-": { + } + }, + "additionalProperties": false + }, + "ImplicitOAuthFlow": { + "type": "object", + "required": [ + "authorizationUrl", + "scopes" + ], + "properties": { + "authorizationUrl": { + "type": "string", + "format": "uri-reference" + }, + "refreshUrl": { + "type": "string", + "format": "uri-reference" + }, + "scopes": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + }, + "patternProperties": { + "^x-": { + } + }, + "additionalProperties": false + }, + "PasswordOAuthFlow": { + "type": "object", + "required": [ + "tokenUrl", + "scopes" + ], + "properties": { + "tokenUrl": { + "type": "string", + "format": "uri-reference" + }, + "refreshUrl": { + "type": "string", + "format": "uri-reference" + }, + "scopes": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + }, + "patternProperties": { + "^x-": { + } + }, + "additionalProperties": false + }, + "ClientCredentialsFlow": { + "type": "object", + "required": [ + "tokenUrl", + "scopes" + ], + "properties": { + "tokenUrl": { + "type": "string", + "format": "uri-reference" + }, + "refreshUrl": { + "type": "string", + "format": "uri-reference" + }, + "scopes": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + }, + "patternProperties": { + "^x-": { + } + }, + "additionalProperties": false + }, + "AuthorizationCodeOAuthFlow": { + "type": "object", + "required": [ + "authorizationUrl", + "tokenUrl", + "scopes" + ], + "properties": { + "authorizationUrl": { + "type": "string", + "format": "uri-reference" + }, + "tokenUrl": { + "type": "string", + "format": "uri-reference" + }, + "refreshUrl": { + "type": "string", + "format": "uri-reference" + }, + "scopes": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + }, + "patternProperties": { + "^x-": { + } + }, + "additionalProperties": false + }, + "Link": { + "type": "object", + "properties": { + "operationId": { + "type": "string" + }, + "operationRef": { + "type": "string", + "format": "uri-reference" + }, + "parameters": { + "type": "object", + "additionalProperties": { + } + }, + "requestBody": { + }, + "description": { + "type": "string" + }, + "server": { + "$ref": "#/definitions/Server" + } + }, + "patternProperties": { + "^x-": { + } + }, + "additionalProperties": false, + "not": { + "description": "Operation Id and Operation Ref are mutually exclusive", + "required": [ + "operationId", + "operationRef" + ] + } + }, + "Callback": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/PathItem" + }, + "patternProperties": { + "^x-": { + } + } + }, + "Encoding": { + "type": "object", + "properties": { + "contentType": { + "type": "string" + }, + "headers": { + "type": "object", + "additionalProperties": { + "oneOf": [ + { + "$ref": "#/definitions/Header" + }, + { + "$ref": "#/definitions/Reference" + } + ] + } + }, + "style": { + "type": "string", + "enum": [ + "form", + "spaceDelimited", + "pipeDelimited", + "deepObject" + ] + }, + "explode": { + "type": "boolean" + }, + "allowReserved": { + "type": "boolean", + "default": false + } + }, + "additionalProperties": false + } + } +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/schemas/oas31-schema.json b/vendor/github.com/pb33f/libopenapi/datamodel/schemas/oas31-schema.json new file mode 100644 index 0000000000..edd6d573fb --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/schemas/oas31-schema.json @@ -0,0 +1,1449 @@ +{ + "$id": "https://spec.openapis.org/oas/3.1/schema/2022-10-07", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "The description of OpenAPI v3.1.x documents without schema validation, as defined by https://spec.openapis.org/oas/v3.1.0", + "type": "object", + "properties": { + "openapi": { + "type": "string", + "pattern": "^3\\.1\\.\\d+(-.+)?$" + }, + "info": { + "$ref": "#/$defs/info" + }, + "jsonSchemaDialect": { + "type": "string", + "format": "uri", + "default": "https://spec.openapis.org/oas/3.1/dialect/base" + }, + "servers": { + "type": "array", + "items": { + "$ref": "#/$defs/server" + }, + "default": [ + { + "url": "/" + } + ] + }, + "paths": { + "$ref": "#/$defs/paths" + }, + "webhooks": { + "type": "object", + "additionalProperties": { + "$ref": "#/$defs/path-item-or-reference" + } + }, + "components": { + "$ref": "#/$defs/components" + }, + "security": { + "type": "array", + "items": { + "$ref": "#/$defs/security-requirement" + } + }, + "tags": { + "type": "array", + "items": { + "$ref": "#/$defs/tag" + } + }, + "externalDocs": { + "$ref": "#/$defs/external-documentation" + } + }, + "required": [ + "openapi", + "info" + ], + "anyOf": [ + { + "required": [ + "paths" + ] + }, + { + "required": [ + "components" + ] + }, + { + "required": [ + "webhooks" + ] + } + ], + "$ref": "#/$defs/specification-extensions", + "unevaluatedProperties": false, + "$defs": { + "info": { + "$comment": "https://spec.openapis.org/oas/v3.1.0#info-object", + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "summary": { + "type": "string" + }, + "description": { + "type": "string" + }, + "termsOfService": { + "type": "string", + "format": "uri" + }, + "contact": { + "$ref": "#/$defs/contact" + }, + "license": { + "$ref": "#/$defs/license" + }, + "version": { + "type": "string" + } + }, + "required": [ + "title", + "version" + ], + "$ref": "#/$defs/specification-extensions", + "unevaluatedProperties": false + }, + "contact": { + "$comment": "https://spec.openapis.org/oas/v3.1.0#contact-object", + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "url": { + "type": "string", + "format": "uri" + }, + "email": { + "type": "string", + "format": "email" + } + }, + "$ref": "#/$defs/specification-extensions", + "unevaluatedProperties": false + }, + "license": { + "$comment": "https://spec.openapis.org/oas/v3.1.0#license-object", + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "identifier": { + "type": "string" + }, + "url": { + "type": "string", + "format": "uri" + } + }, + "required": [ + "name" + ], + "dependentSchemas": { + "identifier": { + "not": { + "required": [ + "url" + ] + } + } + }, + "$ref": "#/$defs/specification-extensions", + "unevaluatedProperties": false + }, + "server": { + "$comment": "https://spec.openapis.org/oas/v3.1.0#server-object", + "type": "object", + "properties": { + "url": { + "type": "string", + "format": "uri-reference" + }, + "description": { + "type": "string" + }, + "variables": { + "type": "object", + "additionalProperties": { + "$ref": "#/$defs/server-variable" + } + } + }, + "required": [ + "url" + ], + "$ref": "#/$defs/specification-extensions", + "unevaluatedProperties": false + }, + "server-variable": { + "$comment": "https://spec.openapis.org/oas/v3.1.0#server-variable-object", + "type": "object", + "properties": { + "enum": { + "type": "array", + "items": { + "type": "string" + }, + "minItems": 1 + }, + "default": { + "type": "string" + }, + "description": { + "type": "string" + } + }, + "required": [ + "default" + ], + "$ref": "#/$defs/specification-extensions", + "unevaluatedProperties": false + }, + "components": { + "$comment": "https://spec.openapis.org/oas/v3.1.0#components-object", + "type": "object", + "properties": { + "schemas": { + "type": "object", + "additionalProperties": { + "$dynamicRef": "#meta" + } + }, + "responses": { + "type": "object", + "additionalProperties": { + "$ref": "#/$defs/response-or-reference" + } + }, + "parameters": { + "type": "object", + "additionalProperties": { + "$ref": "#/$defs/parameter-or-reference" + } + }, + "examples": { + "type": "object", + "additionalProperties": { + "$ref": "#/$defs/example-or-reference" + } + }, + "requestBodies": { + "type": "object", + "additionalProperties": { + "$ref": "#/$defs/request-body-or-reference" + } + }, + "headers": { + "type": "object", + "additionalProperties": { + "$ref": "#/$defs/header-or-reference" + } + }, + "securitySchemes": { + "type": "object", + "additionalProperties": { + "$ref": "#/$defs/security-scheme-or-reference" + } + }, + "links": { + "type": "object", + "additionalProperties": { + "$ref": "#/$defs/link-or-reference" + } + }, + "callbacks": { + "type": "object", + "additionalProperties": { + "$ref": "#/$defs/callbacks-or-reference" + } + }, + "pathItems": { + "type": "object", + "additionalProperties": { + "$ref": "#/$defs/path-item-or-reference" + } + } + }, + "patternProperties": { + "^(schemas|responses|parameters|examples|requestBodies|headers|securitySchemes|links|callbacks|pathItems)$": { + "$comment": "Enumerating all of the property names in the regex above is necessary for unevaluatedProperties to work as expected", + "propertyNames": { + "pattern": "^[a-zA-Z0-9._-]+$" + } + } + }, + "$ref": "#/$defs/specification-extensions", + "unevaluatedProperties": false + }, + "paths": { + "$comment": "https://spec.openapis.org/oas/v3.1.0#paths-object", + "type": "object", + "patternProperties": { + "^/": { + "$ref": "#/$defs/path-item" + } + }, + "$ref": "#/$defs/specification-extensions", + "unevaluatedProperties": false + }, + "path-item": { + "$comment": "https://spec.openapis.org/oas/v3.1.0#path-item-object", + "type": "object", + "properties": { + "summary": { + "type": "string" + }, + "description": { + "type": "string" + }, + "servers": { + "type": "array", + "items": { + "$ref": "#/$defs/server" + } + }, + "parameters": { + "type": "array", + "items": { + "$ref": "#/$defs/parameter-or-reference" + } + }, + "get": { + "$ref": "#/$defs/operation" + }, + "put": { + "$ref": "#/$defs/operation" + }, + "post": { + "$ref": "#/$defs/operation" + }, + "delete": { + "$ref": "#/$defs/operation" + }, + "options": { + "$ref": "#/$defs/operation" + }, + "head": { + "$ref": "#/$defs/operation" + }, + "patch": { + "$ref": "#/$defs/operation" + }, + "trace": { + "$ref": "#/$defs/operation" + } + }, + "$ref": "#/$defs/specification-extensions", + "unevaluatedProperties": false + }, + "path-item-or-reference": { + "if": { + "type": "object", + "required": [ + "$ref" + ] + }, + "then": { + "$ref": "#/$defs/reference" + }, + "else": { + "$ref": "#/$defs/path-item" + } + }, + "operation": { + "$comment": "https://spec.openapis.org/oas/v3.1.0#operation-object", + "type": "object", + "properties": { + "tags": { + "type": "array", + "items": { + "type": "string" + } + }, + "summary": { + "type": "string" + }, + "description": { + "type": "string" + }, + "externalDocs": { + "$ref": "#/$defs/external-documentation" + }, + "operationId": { + "type": "string" + }, + "parameters": { + "type": "array", + "items": { + "$ref": "#/$defs/parameter-or-reference" + } + }, + "requestBody": { + "$ref": "#/$defs/request-body-or-reference" + }, + "responses": { + "$ref": "#/$defs/responses" + }, + "callbacks": { + "type": "object", + "additionalProperties": { + "$ref": "#/$defs/callbacks-or-reference" + } + }, + "deprecated": { + "default": false, + "type": "boolean" + }, + "security": { + "type": "array", + "items": { + "$ref": "#/$defs/security-requirement" + } + }, + "servers": { + "type": "array", + "items": { + "$ref": "#/$defs/server" + } + } + }, + "$ref": "#/$defs/specification-extensions", + "unevaluatedProperties": false + }, + "external-documentation": { + "$comment": "https://spec.openapis.org/oas/v3.1.0#external-documentation-object", + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "url": { + "type": "string", + "format": "uri" + } + }, + "required": [ + "url" + ], + "$ref": "#/$defs/specification-extensions", + "unevaluatedProperties": false + }, + "parameter": { + "$comment": "https://spec.openapis.org/oas/v3.1.0#parameter-object", + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "in": { + "enum": [ + "query", + "header", + "path", + "cookie" + ] + }, + "description": { + "type": "string" + }, + "required": { + "default": false, + "type": "boolean" + }, + "deprecated": { + "default": false, + "type": "boolean" + }, + "schema": { + "$dynamicRef": "#meta" + }, + "content": { + "$ref": "#/$defs/content", + "minProperties": 1, + "maxProperties": 1 + } + }, + "required": [ + "name", + "in" + ], + "oneOf": [ + { + "required": [ + "schema" + ] + }, + { + "required": [ + "content" + ] + } + ], + "if": { + "properties": { + "in": { + "const": "query" + } + }, + "required": [ + "in" + ] + }, + "then": { + "properties": { + "allowEmptyValue": { + "default": false, + "type": "boolean" + } + } + }, + "dependentSchemas": { + "schema": { + "properties": { + "style": { + "type": "string" + }, + "explode": { + "type": "boolean" + } + }, + "allOf": [ + { + "$ref": "#/$defs/examples" + }, + { + "$ref": "#/$defs/parameter/dependentSchemas/schema/$defs/styles-for-path" + }, + { + "$ref": "#/$defs/parameter/dependentSchemas/schema/$defs/styles-for-header" + }, + { + "$ref": "#/$defs/parameter/dependentSchemas/schema/$defs/styles-for-query" + }, + { + "$ref": "#/$defs/parameter/dependentSchemas/schema/$defs/styles-for-cookie" + }, + { + "$ref": "#/$defs/parameter/dependentSchemas/schema/$defs/styles-for-form" + } + ], + "$defs": { + "styles-for-path": { + "if": { + "properties": { + "in": { + "const": "path" + } + }, + "required": [ + "in" + ] + }, + "then": { + "properties": { + "name": { + "pattern": "[^/#?]+$" + }, + "style": { + "default": "simple", + "enum": [ + "matrix", + "label", + "simple" + ] + }, + "required": { + "const": true + } + }, + "required": [ + "required" + ] + } + }, + "styles-for-header": { + "if": { + "properties": { + "in": { + "const": "header" + } + }, + "required": [ + "in" + ] + }, + "then": { + "properties": { + "style": { + "default": "simple", + "const": "simple" + } + } + } + }, + "styles-for-query": { + "if": { + "properties": { + "in": { + "const": "query" + } + }, + "required": [ + "in" + ] + }, + "then": { + "properties": { + "style": { + "default": "form", + "enum": [ + "form", + "spaceDelimited", + "pipeDelimited", + "deepObject" + ] + }, + "allowReserved": { + "default": false, + "type": "boolean" + } + } + } + }, + "styles-for-cookie": { + "if": { + "properties": { + "in": { + "const": "cookie" + } + }, + "required": [ + "in" + ] + }, + "then": { + "properties": { + "style": { + "default": "form", + "const": "form" + } + } + } + }, + "styles-for-form": { + "if": { + "properties": { + "style": { + "const": "form" + } + }, + "required": [ + "style" + ] + }, + "then": { + "properties": { + "explode": { + "default": true + } + } + }, + "else": { + "properties": { + "explode": { + "default": false + } + } + } + } + } + } + }, + "$ref": "#/$defs/specification-extensions", + "unevaluatedProperties": false + }, + "parameter-or-reference": { + "if": { + "type": "object", + "required": [ + "$ref" + ] + }, + "then": { + "$ref": "#/$defs/reference" + }, + "else": { + "$ref": "#/$defs/parameter" + } + }, + "request-body": { + "$comment": "https://spec.openapis.org/oas/v3.1.0#request-body-object", + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "content": { + "$ref": "#/$defs/content" + }, + "required": { + "default": false, + "type": "boolean" + } + }, + "required": [ + "content" + ], + "$ref": "#/$defs/specification-extensions", + "unevaluatedProperties": false + }, + "request-body-or-reference": { + "if": { + "type": "object", + "required": [ + "$ref" + ] + }, + "then": { + "$ref": "#/$defs/reference" + }, + "else": { + "$ref": "#/$defs/request-body" + } + }, + "content": { + "$comment": "https://spec.openapis.org/oas/v3.1.0#fixed-fields-10", + "type": "object", + "additionalProperties": { + "$ref": "#/$defs/media-type" + }, + "propertyNames": { + "format": "media-range" + } + }, + "media-type": { + "$comment": "https://spec.openapis.org/oas/v3.1.0#media-type-object", + "type": "object", + "properties": { + "schema": { + "$dynamicRef": "#meta" + }, + "encoding": { + "type": "object", + "additionalProperties": { + "$ref": "#/$defs/encoding" + } + } + }, + "allOf": [ + { + "$ref": "#/$defs/specification-extensions" + }, + { + "$ref": "#/$defs/examples" + } + ], + "unevaluatedProperties": false + }, + "encoding": { + "$comment": "https://spec.openapis.org/oas/v3.1.0#encoding-object", + "type": "object", + "properties": { + "contentType": { + "type": "string", + "format": "media-range" + }, + "headers": { + "type": "object", + "additionalProperties": { + "$ref": "#/$defs/header-or-reference" + } + }, + "style": { + "default": "form", + "enum": [ + "form", + "spaceDelimited", + "pipeDelimited", + "deepObject" + ] + }, + "explode": { + "type": "boolean" + }, + "allowReserved": { + "default": false, + "type": "boolean" + } + }, + "allOf": [ + { + "$ref": "#/$defs/specification-extensions" + }, + { + "$ref": "#/$defs/encoding/$defs/explode-default" + } + ], + "unevaluatedProperties": false, + "$defs": { + "explode-default": { + "if": { + "properties": { + "style": { + "const": "form" + } + }, + "required": [ + "style" + ] + }, + "then": { + "properties": { + "explode": { + "default": true + } + } + }, + "else": { + "properties": { + "explode": { + "default": false + } + } + } + } + } + }, + "responses": { + "$comment": "https://spec.openapis.org/oas/v3.1.0#responses-object", + "type": "object", + "properties": { + "default": { + "$ref": "#/$defs/response-or-reference" + } + }, + "patternProperties": { + "^[1-5](?:[0-9]{2}|XX)$": { + "$ref": "#/$defs/response-or-reference" + } + }, + "minProperties": 1, + "$ref": "#/$defs/specification-extensions", + "unevaluatedProperties": false, + "if": { + "$comment": "either default, or at least one response code property must exist", + "patternProperties": { + "^[1-5](?:[0-9]{2}|XX)$": false + } + }, + "then" : { + "required": [ "default" ] + } + }, + "response": { + "$comment": "https://spec.openapis.org/oas/v3.1.0#response-object", + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "headers": { + "type": "object", + "additionalProperties": { + "$ref": "#/$defs/header-or-reference" + } + }, + "content": { + "$ref": "#/$defs/content" + }, + "links": { + "type": "object", + "additionalProperties": { + "$ref": "#/$defs/link-or-reference" + } + } + }, + "required": [ + "description" + ], + "$ref": "#/$defs/specification-extensions", + "unevaluatedProperties": false + }, + "response-or-reference": { + "if": { + "type": "object", + "required": [ + "$ref" + ] + }, + "then": { + "$ref": "#/$defs/reference" + }, + "else": { + "$ref": "#/$defs/response" + } + }, + "callbacks": { + "$comment": "https://spec.openapis.org/oas/v3.1.0#callback-object", + "type": "object", + "$ref": "#/$defs/specification-extensions", + "additionalProperties": { + "$ref": "#/$defs/path-item-or-reference" + } + }, + "callbacks-or-reference": { + "if": { + "type": "object", + "required": [ + "$ref" + ] + }, + "then": { + "$ref": "#/$defs/reference" + }, + "else": { + "$ref": "#/$defs/callbacks" + } + }, + "example": { + "$comment": "https://spec.openapis.org/oas/v3.1.0#example-object", + "type": "object", + "properties": { + "summary": { + "type": "string" + }, + "description": { + "type": "string" + }, + "value": true, + "externalValue": { + "type": "string", + "format": "uri" + } + }, + "not": { + "required": [ + "value", + "externalValue" + ] + }, + "$ref": "#/$defs/specification-extensions", + "unevaluatedProperties": false + }, + "example-or-reference": { + "if": { + "type": "object", + "required": [ + "$ref" + ] + }, + "then": { + "$ref": "#/$defs/reference" + }, + "else": { + "$ref": "#/$defs/example" + } + }, + "link": { + "$comment": "https://spec.openapis.org/oas/v3.1.0#link-object", + "type": "object", + "properties": { + "operationRef": { + "type": "string", + "format": "uri-reference" + }, + "operationId": { + "type": "string" + }, + "parameters": { + "$ref": "#/$defs/map-of-strings" + }, + "requestBody": true, + "description": { + "type": "string" + }, + "body": { + "$ref": "#/$defs/server" + } + }, + "oneOf": [ + { + "required": [ + "operationRef" + ] + }, + { + "required": [ + "operationId" + ] + } + ], + "$ref": "#/$defs/specification-extensions", + "unevaluatedProperties": false + }, + "link-or-reference": { + "if": { + "type": "object", + "required": [ + "$ref" + ] + }, + "then": { + "$ref": "#/$defs/reference" + }, + "else": { + "$ref": "#/$defs/link" + } + }, + "header": { + "$comment": "https://spec.openapis.org/oas/v3.1.0#header-object", + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "required": { + "default": false, + "type": "boolean" + }, + "deprecated": { + "default": false, + "type": "boolean" + }, + "schema": { + "$dynamicRef": "#meta" + }, + "content": { + "$ref": "#/$defs/content", + "minProperties": 1, + "maxProperties": 1 + } + }, + "oneOf": [ + { + "required": [ + "schema" + ] + }, + { + "required": [ + "content" + ] + } + ], + "dependentSchemas": { + "schema": { + "properties": { + "style": { + "default": "simple", + "const": "simple" + }, + "explode": { + "default": false, + "type": "boolean" + } + }, + "$ref": "#/$defs/examples" + } + }, + "$ref": "#/$defs/specification-extensions", + "unevaluatedProperties": false + }, + "header-or-reference": { + "if": { + "type": "object", + "required": [ + "$ref" + ] + }, + "then": { + "$ref": "#/$defs/reference" + }, + "else": { + "$ref": "#/$defs/header" + } + }, + "tag": { + "$comment": "https://spec.openapis.org/oas/v3.1.0#tag-object", + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "externalDocs": { + "$ref": "#/$defs/external-documentation" + } + }, + "required": [ + "name" + ], + "$ref": "#/$defs/specification-extensions", + "unevaluatedProperties": false + }, + "reference": { + "$comment": "https://spec.openapis.org/oas/v3.1.0#reference-object", + "type": "object", + "properties": { + "$ref": { + "type": "string", + "format": "uri-reference" + }, + "summary": { + "type": "string" + }, + "description": { + "type": "string" + } + }, + "unevaluatedProperties": false + }, + "schema": { + "$comment": "https://spec.openapis.org/oas/v3.1.0#schema-object", + "$dynamicAnchor": "meta", + "type": [ + "object", + "boolean" + ] + }, + "security-scheme": { + "$comment": "https://spec.openapis.org/oas/v3.1.0#security-scheme-object", + "type": "object", + "properties": { + "type": { + "enum": [ + "apiKey", + "http", + "mutualTLS", + "oauth2", + "openIdConnect" + ] + }, + "description": { + "type": "string" + } + }, + "required": [ + "type" + ], + "allOf": [ + { + "$ref": "#/$defs/specification-extensions" + }, + { + "$ref": "#/$defs/security-scheme/$defs/type-apikey" + }, + { + "$ref": "#/$defs/security-scheme/$defs/type-http" + }, + { + "$ref": "#/$defs/security-scheme/$defs/type-http-bearer" + }, + { + "$ref": "#/$defs/security-scheme/$defs/type-oauth2" + }, + { + "$ref": "#/$defs/security-scheme/$defs/type-oidc" + } + ], + "unevaluatedProperties": false, + "$defs": { + "type-apikey": { + "if": { + "properties": { + "type": { + "const": "apiKey" + } + }, + "required": [ + "type" + ] + }, + "then": { + "properties": { + "name": { + "type": "string" + }, + "in": { + "enum": [ + "query", + "header", + "cookie" + ] + } + }, + "required": [ + "name", + "in" + ] + } + }, + "type-http": { + "if": { + "properties": { + "type": { + "const": "http" + } + }, + "required": [ + "type" + ] + }, + "then": { + "properties": { + "scheme": { + "type": "string" + } + }, + "required": [ + "scheme" + ] + } + }, + "type-http-bearer": { + "if": { + "properties": { + "type": { + "const": "http" + }, + "scheme": { + "type": "string", + "pattern": "^[Bb][Ee][Aa][Rr][Ee][Rr]$" + } + }, + "required": [ + "type", + "scheme" + ] + }, + "then": { + "properties": { + "bearerFormat": { + "type": "string" + } + } + } + }, + "type-oauth2": { + "if": { + "properties": { + "type": { + "const": "oauth2" + } + }, + "required": [ + "type" + ] + }, + "then": { + "properties": { + "flows": { + "$ref": "#/$defs/oauth-flows" + } + }, + "required": [ + "flows" + ] + } + }, + "type-oidc": { + "if": { + "properties": { + "type": { + "const": "openIdConnect" + } + }, + "required": [ + "type" + ] + }, + "then": { + "properties": { + "openIdConnectUrl": { + "type": "string", + "format": "uri" + } + }, + "required": [ + "openIdConnectUrl" + ] + } + } + } + }, + "security-scheme-or-reference": { + "if": { + "type": "object", + "required": [ + "$ref" + ] + }, + "then": { + "$ref": "#/$defs/reference" + }, + "else": { + "$ref": "#/$defs/security-scheme" + } + }, + "oauth-flows": { + "type": "object", + "properties": { + "implicit": { + "$ref": "#/$defs/oauth-flows/$defs/implicit" + }, + "password": { + "$ref": "#/$defs/oauth-flows/$defs/password" + }, + "clientCredentials": { + "$ref": "#/$defs/oauth-flows/$defs/client-credentials" + }, + "authorizationCode": { + "$ref": "#/$defs/oauth-flows/$defs/authorization-code" + } + }, + "$ref": "#/$defs/specification-extensions", + "unevaluatedProperties": false, + "$defs": { + "implicit": { + "type": "object", + "properties": { + "authorizationUrl": { + "type": "string", + "format": "uri" + }, + "refreshUrl": { + "type": "string", + "format": "uri" + }, + "scopes": { + "$ref": "#/$defs/map-of-strings" + } + }, + "required": [ + "authorizationUrl", + "scopes" + ], + "$ref": "#/$defs/specification-extensions", + "unevaluatedProperties": false + }, + "password": { + "type": "object", + "properties": { + "tokenUrl": { + "type": "string", + "format": "uri" + }, + "refreshUrl": { + "type": "string", + "format": "uri" + }, + "scopes": { + "$ref": "#/$defs/map-of-strings" + } + }, + "required": [ + "tokenUrl", + "scopes" + ], + "$ref": "#/$defs/specification-extensions", + "unevaluatedProperties": false + }, + "client-credentials": { + "type": "object", + "properties": { + "tokenUrl": { + "type": "string", + "format": "uri" + }, + "refreshUrl": { + "type": "string", + "format": "uri" + }, + "scopes": { + "$ref": "#/$defs/map-of-strings" + } + }, + "required": [ + "tokenUrl", + "scopes" + ], + "$ref": "#/$defs/specification-extensions", + "unevaluatedProperties": false + }, + "authorization-code": { + "type": "object", + "properties": { + "authorizationUrl": { + "type": "string", + "format": "uri" + }, + "tokenUrl": { + "type": "string", + "format": "uri" + }, + "refreshUrl": { + "type": "string", + "format": "uri" + }, + "scopes": { + "$ref": "#/$defs/map-of-strings" + } + }, + "required": [ + "authorizationUrl", + "tokenUrl", + "scopes" + ], + "$ref": "#/$defs/specification-extensions", + "unevaluatedProperties": false + } + } + }, + "security-requirement": { + "$comment": "https://spec.openapis.org/oas/v3.1.0#security-requirement-object", + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "specification-extensions": { + "$comment": "https://spec.openapis.org/oas/v3.1.0#specification-extensions", + "patternProperties": { + "^x-": true + } + }, + "examples": { + "properties": { + "example": true, + "examples": { + "type": "object", + "additionalProperties": { + "$ref": "#/$defs/example-or-reference" + } + } + } + }, + "map-of-strings": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } +} diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/schemas/swagger2-schema.json b/vendor/github.com/pb33f/libopenapi/datamodel/schemas/swagger2-schema.json new file mode 100644 index 0000000000..a92e18f2a5 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/schemas/swagger2-schema.json @@ -0,0 +1,1607 @@ +{ + "title": "A JSON Schema for Swagger 2.0 API.", + "id": "http://swagger.io/v2/schema.json#", + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "required": [ + "swagger", + "info", + "paths" + ], + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + }, + "properties": { + "swagger": { + "type": "string", + "enum": [ + "2.0" + ], + "description": "The Swagger version of this document." + }, + "info": { + "$ref": "#/definitions/info" + }, + "host": { + "type": "string", + "pattern": "^[^{}/ :\\\\]+(?::\\d+)?$", + "description": "The host (name or ip) of the API. Example: 'swagger.io'" + }, + "basePath": { + "type": "string", + "pattern": "^/", + "description": "The base path to the API. Example: '/api'." + }, + "schemes": { + "$ref": "#/definitions/schemesList" + }, + "consumes": { + "description": "A list of MIME types accepted by the API.", + "allOf": [ + { + "$ref": "#/definitions/mediaTypeList" + } + ] + }, + "produces": { + "description": "A list of MIME types the API can produce.", + "allOf": [ + { + "$ref": "#/definitions/mediaTypeList" + } + ] + }, + "paths": { + "$ref": "#/definitions/paths" + }, + "definitions": { + "$ref": "#/definitions/definitions" + }, + "parameters": { + "$ref": "#/definitions/parameterDefinitions" + }, + "responses": { + "$ref": "#/definitions/responseDefinitions" + }, + "security": { + "$ref": "#/definitions/security" + }, + "securityDefinitions": { + "$ref": "#/definitions/securityDefinitions" + }, + "tags": { + "type": "array", + "items": { + "$ref": "#/definitions/tag" + }, + "uniqueItems": true + }, + "externalDocs": { + "$ref": "#/definitions/externalDocs" + } + }, + "definitions": { + "info": { + "type": "object", + "description": "General information about the API.", + "required": [ + "version", + "title" + ], + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + }, + "properties": { + "title": { + "type": "string", + "description": "A unique and precise title of the API." + }, + "version": { + "type": "string", + "description": "A semantic version number of the API." + }, + "description": { + "type": "string", + "description": "A longer description of the API. Should be different from the title. GitHub Flavored Markdown is allowed." + }, + "termsOfService": { + "type": "string", + "description": "The terms of service for the API." + }, + "contact": { + "$ref": "#/definitions/contact" + }, + "license": { + "$ref": "#/definitions/license" + } + } + }, + "contact": { + "type": "object", + "description": "Contact information for the owners of the API.", + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "The identifying name of the contact person/organization." + }, + "url": { + "type": "string", + "description": "The URL pointing to the contact information.", + "format": "uri" + }, + "email": { + "type": "string", + "description": "The email address of the contact person/organization.", + "format": "email" + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "license": { + "type": "object", + "required": [ + "name" + ], + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "The name of the license type. It's encouraged to use an OSI compatible license." + }, + "url": { + "type": "string", + "description": "The URL pointing to the license.", + "format": "uri" + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "paths": { + "type": "object", + "description": "Relative paths to the individual endpoints. They must be relative to the 'basePath'.", + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + }, + "^/": { + "$ref": "#/definitions/pathItem" + } + }, + "additionalProperties": false + }, + "definitions": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/schema" + }, + "description": "One or more JSON objects describing the schemas being consumed and produced by the API." + }, + "parameterDefinitions": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/parameter" + }, + "description": "One or more JSON representations for parameters" + }, + "responseDefinitions": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/response" + }, + "description": "One or more JSON representations for responses" + }, + "externalDocs": { + "type": "object", + "additionalProperties": false, + "description": "information about external documentation", + "required": [ + "url" + ], + "properties": { + "description": { + "type": "string" + }, + "url": { + "type": "string", + "format": "uri" + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "examples": { + "type": "object", + "additionalProperties": true + }, + "mimeType": { + "type": "string", + "description": "The MIME type of the HTTP message." + }, + "operation": { + "type": "object", + "required": [ + "responses" + ], + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + }, + "properties": { + "tags": { + "type": "array", + "items": { + "type": "string" + }, + "uniqueItems": true + }, + "summary": { + "type": "string", + "description": "A brief summary of the operation." + }, + "description": { + "type": "string", + "description": "A longer description of the operation, GitHub Flavored Markdown is allowed." + }, + "externalDocs": { + "$ref": "#/definitions/externalDocs" + }, + "operationId": { + "type": "string", + "description": "A unique identifier of the operation." + }, + "produces": { + "description": "A list of MIME types the API can produce.", + "allOf": [ + { + "$ref": "#/definitions/mediaTypeList" + } + ] + }, + "consumes": { + "description": "A list of MIME types the API can consume.", + "allOf": [ + { + "$ref": "#/definitions/mediaTypeList" + } + ] + }, + "parameters": { + "$ref": "#/definitions/parametersList" + }, + "responses": { + "$ref": "#/definitions/responses" + }, + "schemes": { + "$ref": "#/definitions/schemesList" + }, + "deprecated": { + "type": "boolean", + "default": false + }, + "security": { + "$ref": "#/definitions/security" + } + } + }, + "pathItem": { + "type": "object", + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + }, + "properties": { + "$ref": { + "type": "string" + }, + "get": { + "$ref": "#/definitions/operation" + }, + "put": { + "$ref": "#/definitions/operation" + }, + "post": { + "$ref": "#/definitions/operation" + }, + "delete": { + "$ref": "#/definitions/operation" + }, + "options": { + "$ref": "#/definitions/operation" + }, + "head": { + "$ref": "#/definitions/operation" + }, + "patch": { + "$ref": "#/definitions/operation" + }, + "parameters": { + "$ref": "#/definitions/parametersList" + } + } + }, + "responses": { + "type": "object", + "description": "Response objects names can either be any valid HTTP status code or 'default'.", + "minProperties": 1, + "additionalProperties": false, + "patternProperties": { + "^([0-9]{3})$|^(default)$": { + "$ref": "#/definitions/responseValue" + }, + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + }, + "not": { + "type": "object", + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + } + }, + "responseValue": { + "oneOf": [ + { + "$ref": "#/definitions/response" + }, + { + "$ref": "#/definitions/jsonReference" + } + ] + }, + "response": { + "type": "object", + "required": [ + "description" + ], + "properties": { + "description": { + "type": "string" + }, + "schema": { + "oneOf": [ + { + "$ref": "#/definitions/schema" + }, + { + "$ref": "#/definitions/fileSchema" + } + ] + }, + "headers": { + "$ref": "#/definitions/headers" + }, + "examples": { + "$ref": "#/definitions/examples" + } + }, + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "headers": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/header" + } + }, + "header": { + "type": "object", + "additionalProperties": false, + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "string", + "number", + "integer", + "boolean", + "array" + ] + }, + "format": { + "type": "string" + }, + "items": { + "$ref": "#/definitions/primitivesItems" + }, + "collectionFormat": { + "$ref": "#/definitions/collectionFormat" + }, + "default": { + "$ref": "#/definitions/default" + }, + "maximum": { + "$ref": "#/definitions/maximum" + }, + "exclusiveMaximum": { + "$ref": "#/definitions/exclusiveMaximum" + }, + "minimum": { + "$ref": "#/definitions/minimum" + }, + "exclusiveMinimum": { + "$ref": "#/definitions/exclusiveMinimum" + }, + "maxLength": { + "$ref": "#/definitions/maxLength" + }, + "minLength": { + "$ref": "#/definitions/minLength" + }, + "pattern": { + "$ref": "#/definitions/pattern" + }, + "maxItems": { + "$ref": "#/definitions/maxItems" + }, + "minItems": { + "$ref": "#/definitions/minItems" + }, + "uniqueItems": { + "$ref": "#/definitions/uniqueItems" + }, + "enum": { + "$ref": "#/definitions/enum" + }, + "multipleOf": { + "$ref": "#/definitions/multipleOf" + }, + "description": { + "type": "string" + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "vendorExtension": { + "description": "Any property starting with x- is valid.", + "additionalProperties": true, + "additionalItems": true + }, + "bodyParameter": { + "type": "object", + "required": [ + "name", + "in", + "schema" + ], + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + }, + "properties": { + "description": { + "type": "string", + "description": "A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed." + }, + "name": { + "type": "string", + "description": "The name of the parameter." + }, + "in": { + "type": "string", + "description": "Determines the location of the parameter.", + "enum": [ + "body" + ] + }, + "required": { + "type": "boolean", + "description": "Determines whether or not this parameter is required or optional.", + "default": false + }, + "schema": { + "$ref": "#/definitions/schema" + } + }, + "additionalProperties": false + }, + "headerParameterSubSchema": { + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + }, + "properties": { + "required": { + "type": "boolean", + "description": "Determines whether or not this parameter is required or optional.", + "default": false + }, + "in": { + "type": "string", + "description": "Determines the location of the parameter.", + "enum": [ + "header" + ] + }, + "description": { + "type": "string", + "description": "A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed." + }, + "name": { + "type": "string", + "description": "The name of the parameter." + }, + "type": { + "type": "string", + "enum": [ + "string", + "number", + "boolean", + "integer", + "array" + ] + }, + "format": { + "type": "string" + }, + "items": { + "$ref": "#/definitions/primitivesItems" + }, + "collectionFormat": { + "$ref": "#/definitions/collectionFormat" + }, + "default": { + "$ref": "#/definitions/default" + }, + "maximum": { + "$ref": "#/definitions/maximum" + }, + "exclusiveMaximum": { + "$ref": "#/definitions/exclusiveMaximum" + }, + "minimum": { + "$ref": "#/definitions/minimum" + }, + "exclusiveMinimum": { + "$ref": "#/definitions/exclusiveMinimum" + }, + "maxLength": { + "$ref": "#/definitions/maxLength" + }, + "minLength": { + "$ref": "#/definitions/minLength" + }, + "pattern": { + "$ref": "#/definitions/pattern" + }, + "maxItems": { + "$ref": "#/definitions/maxItems" + }, + "minItems": { + "$ref": "#/definitions/minItems" + }, + "uniqueItems": { + "$ref": "#/definitions/uniqueItems" + }, + "enum": { + "$ref": "#/definitions/enum" + }, + "multipleOf": { + "$ref": "#/definitions/multipleOf" + } + } + }, + "queryParameterSubSchema": { + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + }, + "properties": { + "required": { + "type": "boolean", + "description": "Determines whether or not this parameter is required or optional.", + "default": false + }, + "in": { + "type": "string", + "description": "Determines the location of the parameter.", + "enum": [ + "query" + ] + }, + "description": { + "type": "string", + "description": "A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed." + }, + "name": { + "type": "string", + "description": "The name of the parameter." + }, + "allowEmptyValue": { + "type": "boolean", + "default": false, + "description": "allows sending a parameter by name only or with an empty value." + }, + "type": { + "type": "string", + "enum": [ + "string", + "number", + "boolean", + "integer", + "array" + ] + }, + "format": { + "type": "string" + }, + "items": { + "$ref": "#/definitions/primitivesItems" + }, + "collectionFormat": { + "$ref": "#/definitions/collectionFormatWithMulti" + }, + "default": { + "$ref": "#/definitions/default" + }, + "maximum": { + "$ref": "#/definitions/maximum" + }, + "exclusiveMaximum": { + "$ref": "#/definitions/exclusiveMaximum" + }, + "minimum": { + "$ref": "#/definitions/minimum" + }, + "exclusiveMinimum": { + "$ref": "#/definitions/exclusiveMinimum" + }, + "maxLength": { + "$ref": "#/definitions/maxLength" + }, + "minLength": { + "$ref": "#/definitions/minLength" + }, + "pattern": { + "$ref": "#/definitions/pattern" + }, + "maxItems": { + "$ref": "#/definitions/maxItems" + }, + "minItems": { + "$ref": "#/definitions/minItems" + }, + "uniqueItems": { + "$ref": "#/definitions/uniqueItems" + }, + "enum": { + "$ref": "#/definitions/enum" + }, + "multipleOf": { + "$ref": "#/definitions/multipleOf" + } + } + }, + "formDataParameterSubSchema": { + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + }, + "properties": { + "required": { + "type": "boolean", + "description": "Determines whether or not this parameter is required or optional.", + "default": false + }, + "in": { + "type": "string", + "description": "Determines the location of the parameter.", + "enum": [ + "formData" + ] + }, + "description": { + "type": "string", + "description": "A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed." + }, + "name": { + "type": "string", + "description": "The name of the parameter." + }, + "allowEmptyValue": { + "type": "boolean", + "default": false, + "description": "allows sending a parameter by name only or with an empty value." + }, + "type": { + "type": "string", + "enum": [ + "string", + "number", + "boolean", + "integer", + "array", + "file" + ] + }, + "format": { + "type": "string" + }, + "items": { + "$ref": "#/definitions/primitivesItems" + }, + "collectionFormat": { + "$ref": "#/definitions/collectionFormatWithMulti" + }, + "default": { + "$ref": "#/definitions/default" + }, + "maximum": { + "$ref": "#/definitions/maximum" + }, + "exclusiveMaximum": { + "$ref": "#/definitions/exclusiveMaximum" + }, + "minimum": { + "$ref": "#/definitions/minimum" + }, + "exclusiveMinimum": { + "$ref": "#/definitions/exclusiveMinimum" + }, + "maxLength": { + "$ref": "#/definitions/maxLength" + }, + "minLength": { + "$ref": "#/definitions/minLength" + }, + "pattern": { + "$ref": "#/definitions/pattern" + }, + "maxItems": { + "$ref": "#/definitions/maxItems" + }, + "minItems": { + "$ref": "#/definitions/minItems" + }, + "uniqueItems": { + "$ref": "#/definitions/uniqueItems" + }, + "enum": { + "$ref": "#/definitions/enum" + }, + "multipleOf": { + "$ref": "#/definitions/multipleOf" + } + } + }, + "pathParameterSubSchema": { + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + }, + "required": [ + "required" + ], + "properties": { + "required": { + "type": "boolean", + "enum": [ + true + ], + "description": "Determines whether or not this parameter is required or optional." + }, + "in": { + "type": "string", + "description": "Determines the location of the parameter.", + "enum": [ + "path" + ] + }, + "description": { + "type": "string", + "description": "A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed." + }, + "name": { + "type": "string", + "description": "The name of the parameter." + }, + "type": { + "type": "string", + "enum": [ + "string", + "number", + "boolean", + "integer", + "array" + ] + }, + "format": { + "type": "string" + }, + "items": { + "$ref": "#/definitions/primitivesItems" + }, + "collectionFormat": { + "$ref": "#/definitions/collectionFormat" + }, + "default": { + "$ref": "#/definitions/default" + }, + "maximum": { + "$ref": "#/definitions/maximum" + }, + "exclusiveMaximum": { + "$ref": "#/definitions/exclusiveMaximum" + }, + "minimum": { + "$ref": "#/definitions/minimum" + }, + "exclusiveMinimum": { + "$ref": "#/definitions/exclusiveMinimum" + }, + "maxLength": { + "$ref": "#/definitions/maxLength" + }, + "minLength": { + "$ref": "#/definitions/minLength" + }, + "pattern": { + "$ref": "#/definitions/pattern" + }, + "maxItems": { + "$ref": "#/definitions/maxItems" + }, + "minItems": { + "$ref": "#/definitions/minItems" + }, + "uniqueItems": { + "$ref": "#/definitions/uniqueItems" + }, + "enum": { + "$ref": "#/definitions/enum" + }, + "multipleOf": { + "$ref": "#/definitions/multipleOf" + } + } + }, + "nonBodyParameter": { + "type": "object", + "required": [ + "name", + "in", + "type" + ], + "oneOf": [ + { + "$ref": "#/definitions/headerParameterSubSchema" + }, + { + "$ref": "#/definitions/formDataParameterSubSchema" + }, + { + "$ref": "#/definitions/queryParameterSubSchema" + }, + { + "$ref": "#/definitions/pathParameterSubSchema" + } + ] + }, + "parameter": { + "oneOf": [ + { + "$ref": "#/definitions/bodyParameter" + }, + { + "$ref": "#/definitions/nonBodyParameter" + } + ] + }, + "schema": { + "type": "object", + "description": "A deterministic version of a JSON Schema object.", + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + }, + "properties": { + "$ref": { + "type": "string" + }, + "format": { + "type": "string" + }, + "title": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/title" + }, + "description": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/description" + }, + "default": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/default" + }, + "multipleOf": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/multipleOf" + }, + "maximum": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/maximum" + }, + "exclusiveMaximum": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/exclusiveMaximum" + }, + "minimum": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/minimum" + }, + "exclusiveMinimum": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/exclusiveMinimum" + }, + "maxLength": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveInteger" + }, + "minLength": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveIntegerDefault0" + }, + "pattern": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/pattern" + }, + "maxItems": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveInteger" + }, + "minItems": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveIntegerDefault0" + }, + "uniqueItems": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/uniqueItems" + }, + "maxProperties": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveInteger" + }, + "minProperties": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveIntegerDefault0" + }, + "required": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/stringArray" + }, + "enum": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/enum" + }, + "additionalProperties": { + "anyOf": [ + { + "$ref": "#/definitions/schema" + }, + { + "type": "boolean" + } + ], + "default": {} + }, + "type": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/type" + }, + "items": { + "anyOf": [ + { + "$ref": "#/definitions/schema" + }, + { + "type": "array", + "minItems": 1, + "items": { + "$ref": "#/definitions/schema" + } + } + ], + "default": {} + }, + "allOf": { + "type": "array", + "minItems": 1, + "items": { + "$ref": "#/definitions/schema" + } + }, + "properties": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/schema" + }, + "default": {} + }, + "discriminator": { + "type": "string" + }, + "readOnly": { + "type": "boolean", + "default": false + }, + "xml": { + "$ref": "#/definitions/xml" + }, + "externalDocs": { + "$ref": "#/definitions/externalDocs" + }, + "example": {} + }, + "additionalProperties": false + }, + "fileSchema": { + "type": "object", + "description": "A deterministic version of a JSON Schema object.", + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + }, + "required": [ + "type" + ], + "properties": { + "format": { + "type": "string" + }, + "title": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/title" + }, + "description": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/description" + }, + "default": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/default" + }, + "required": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/stringArray" + }, + "type": { + "type": "string", + "enum": [ + "file" + ] + }, + "readOnly": { + "type": "boolean", + "default": false + }, + "externalDocs": { + "$ref": "#/definitions/externalDocs" + }, + "example": {} + }, + "additionalProperties": false + }, + "primitivesItems": { + "type": "object", + "additionalProperties": false, + "properties": { + "type": { + "type": "string", + "enum": [ + "string", + "number", + "integer", + "boolean", + "array" + ] + }, + "format": { + "type": "string" + }, + "items": { + "$ref": "#/definitions/primitivesItems" + }, + "collectionFormat": { + "$ref": "#/definitions/collectionFormat" + }, + "default": { + "$ref": "#/definitions/default" + }, + "maximum": { + "$ref": "#/definitions/maximum" + }, + "exclusiveMaximum": { + "$ref": "#/definitions/exclusiveMaximum" + }, + "minimum": { + "$ref": "#/definitions/minimum" + }, + "exclusiveMinimum": { + "$ref": "#/definitions/exclusiveMinimum" + }, + "maxLength": { + "$ref": "#/definitions/maxLength" + }, + "minLength": { + "$ref": "#/definitions/minLength" + }, + "pattern": { + "$ref": "#/definitions/pattern" + }, + "maxItems": { + "$ref": "#/definitions/maxItems" + }, + "minItems": { + "$ref": "#/definitions/minItems" + }, + "uniqueItems": { + "$ref": "#/definitions/uniqueItems" + }, + "enum": { + "$ref": "#/definitions/enum" + }, + "multipleOf": { + "$ref": "#/definitions/multipleOf" + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "security": { + "type": "array", + "items": { + "$ref": "#/definitions/securityRequirement" + }, + "uniqueItems": true + }, + "securityRequirement": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "type": "string" + }, + "uniqueItems": true + } + }, + "xml": { + "type": "object", + "additionalProperties": false, + "properties": { + "name": { + "type": "string" + }, + "namespace": { + "type": "string" + }, + "prefix": { + "type": "string" + }, + "attribute": { + "type": "boolean", + "default": false + }, + "wrapped": { + "type": "boolean", + "default": false + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "tag": { + "type": "object", + "additionalProperties": false, + "required": [ + "name" + ], + "properties": { + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "externalDocs": { + "$ref": "#/definitions/externalDocs" + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "securityDefinitions": { + "type": "object", + "additionalProperties": { + "oneOf": [ + { + "$ref": "#/definitions/basicAuthenticationSecurity" + }, + { + "$ref": "#/definitions/apiKeySecurity" + }, + { + "$ref": "#/definitions/oauth2ImplicitSecurity" + }, + { + "$ref": "#/definitions/oauth2PasswordSecurity" + }, + { + "$ref": "#/definitions/oauth2ApplicationSecurity" + }, + { + "$ref": "#/definitions/oauth2AccessCodeSecurity" + } + ] + } + }, + "basicAuthenticationSecurity": { + "type": "object", + "additionalProperties": false, + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "basic" + ] + }, + "description": { + "type": "string" + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "apiKeySecurity": { + "type": "object", + "additionalProperties": false, + "required": [ + "type", + "name", + "in" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "apiKey" + ] + }, + "name": { + "type": "string" + }, + "in": { + "type": "string", + "enum": [ + "header", + "query" + ] + }, + "description": { + "type": "string" + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "oauth2ImplicitSecurity": { + "type": "object", + "additionalProperties": false, + "required": [ + "type", + "flow", + "authorizationUrl" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "oauth2" + ] + }, + "flow": { + "type": "string", + "enum": [ + "implicit" + ] + }, + "scopes": { + "$ref": "#/definitions/oauth2Scopes" + }, + "authorizationUrl": { + "type": "string", + "format": "uri" + }, + "description": { + "type": "string" + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "oauth2PasswordSecurity": { + "type": "object", + "additionalProperties": false, + "required": [ + "type", + "flow", + "tokenUrl" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "oauth2" + ] + }, + "flow": { + "type": "string", + "enum": [ + "password" + ] + }, + "scopes": { + "$ref": "#/definitions/oauth2Scopes" + }, + "tokenUrl": { + "type": "string", + "format": "uri" + }, + "description": { + "type": "string" + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "oauth2ApplicationSecurity": { + "type": "object", + "additionalProperties": false, + "required": [ + "type", + "flow", + "tokenUrl" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "oauth2" + ] + }, + "flow": { + "type": "string", + "enum": [ + "application" + ] + }, + "scopes": { + "$ref": "#/definitions/oauth2Scopes" + }, + "tokenUrl": { + "type": "string", + "format": "uri" + }, + "description": { + "type": "string" + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "oauth2AccessCodeSecurity": { + "type": "object", + "additionalProperties": false, + "required": [ + "type", + "flow", + "authorizationUrl", + "tokenUrl" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "oauth2" + ] + }, + "flow": { + "type": "string", + "enum": [ + "accessCode" + ] + }, + "scopes": { + "$ref": "#/definitions/oauth2Scopes" + }, + "authorizationUrl": { + "type": "string", + "format": "uri" + }, + "tokenUrl": { + "type": "string", + "format": "uri" + }, + "description": { + "type": "string" + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "oauth2Scopes": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "mediaTypeList": { + "type": "array", + "items": { + "$ref": "#/definitions/mimeType" + }, + "uniqueItems": true + }, + "parametersList": { + "type": "array", + "description": "The parameters needed to send a valid API call.", + "additionalItems": false, + "items": { + "oneOf": [ + { + "$ref": "#/definitions/parameter" + }, + { + "$ref": "#/definitions/jsonReference" + } + ] + }, + "uniqueItems": true + }, + "schemesList": { + "type": "array", + "description": "The transfer protocol of the API.", + "items": { + "type": "string", + "enum": [ + "http", + "https", + "ws", + "wss" + ] + }, + "uniqueItems": true + }, + "collectionFormat": { + "type": "string", + "enum": [ + "csv", + "ssv", + "tsv", + "pipes" + ], + "default": "csv" + }, + "collectionFormatWithMulti": { + "type": "string", + "enum": [ + "csv", + "ssv", + "tsv", + "pipes", + "multi" + ], + "default": "csv" + }, + "title": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/title" + }, + "description": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/description" + }, + "default": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/default" + }, + "multipleOf": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/multipleOf" + }, + "maximum": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/maximum" + }, + "exclusiveMaximum": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/exclusiveMaximum" + }, + "minimum": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/minimum" + }, + "exclusiveMinimum": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/exclusiveMinimum" + }, + "maxLength": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveInteger" + }, + "minLength": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveIntegerDefault0" + }, + "pattern": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/pattern" + }, + "maxItems": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveInteger" + }, + "minItems": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveIntegerDefault0" + }, + "uniqueItems": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/uniqueItems" + }, + "enum": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/enum" + }, + "jsonReference": { + "type": "object", + "required": [ + "$ref" + ], + "additionalProperties": false, + "properties": { + "$ref": { + "type": "string" + } + } + } + } +} \ No newline at end of file diff --git a/vendor/github.com/pb33f/libopenapi/datamodel/spec_info.go b/vendor/github.com/pb33f/libopenapi/datamodel/spec_info.go new file mode 100644 index 0000000000..cb39e68fb2 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/datamodel/spec_info.go @@ -0,0 +1,190 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package datamodel + +import ( + "encoding/json" + "errors" + "fmt" + "strings" + "time" + + "github.com/pb33f/libopenapi/utils" + "gopkg.in/yaml.v3" +) + +const ( + JSONFileType = "json" + YAMLFileType = "yaml" +) + +// SpecInfo represents a 'ready-to-process' OpenAPI Document. The RootNode is the most important property +// used by the library, this contains the top of the document tree that every single low model is based off. +type SpecInfo struct { + SpecType string `json:"type"` + Version string `json:"version"` + SpecFormat string `json:"format"` + SpecFileType string `json:"fileType"` + SpecBytes *[]byte `json:"bytes"` // the original byte array + RootNode *yaml.Node `json:"-"` // reference to the root node of the spec. + SpecJSONBytes *[]byte `json:"-"` // original bytes converted to JSON + SpecJSON *map[string]interface{} `json:"-"` // standard JSON map of original bytes + Error error `json:"-"` // something go wrong? + APISchema string `json:"-"` // API Schema for supplied spec type (2 or 3) + Generated time.Time `json:"-"` + JsonParsingChannel chan bool `json:"-"` +} + +// GetJSONParsingChannel returns a channel that will close once async JSON parsing is completed. +// This is really useful if your application wants to analyze the JSON via SpecJSON. the library will +// return *SpecInfo BEFORE the JSON is done parsing, so things are as fast as possible. +// +// If you want to know when parsing is done, listen on the channel for a bool. +func (si SpecInfo) GetJSONParsingChannel() chan bool { + return si.JsonParsingChannel +} + +// ExtractSpecInfo accepts an OpenAPI/Swagger specification that has been read into a byte array +// and will return a SpecInfo pointer, which contains details on the version and an un-marshaled +// *yaml.Node root node tree. The root node tree is what's used by the library when building out models. +// +// If the spec cannot be parsed correctly then an error will be returned, otherwise the error is nil. +func ExtractSpecInfo(spec []byte) (*SpecInfo, error) { + + var parsedSpec yaml.Node + + specVersion := &SpecInfo{} + specVersion.JsonParsingChannel = make(chan bool) + + // set original bytes + specVersion.SpecBytes = &spec + + runes := []rune(strings.TrimSpace(string(spec))) + if len(runes) <= 0 { + return specVersion, errors.New("there is nothing in the spec, it's empty - so there is nothing to be done") + } + + if runes[0] == '{' && runes[len(runes)-1] == '}' { + specVersion.SpecFileType = JSONFileType + } else { + specVersion.SpecFileType = YAMLFileType + } + + err := yaml.Unmarshal(spec, &parsedSpec) + if err != nil { + return nil, fmt.Errorf("unable to parse specification: %s", err.Error()) + } + + specVersion.RootNode = &parsedSpec + + _, openAPI3 := utils.FindKeyNode(utils.OpenApi3, parsedSpec.Content) + _, openAPI2 := utils.FindKeyNode(utils.OpenApi2, parsedSpec.Content) + _, asyncAPI := utils.FindKeyNode(utils.AsyncApi, parsedSpec.Content) + + parseJSON := func(bytes []byte, spec *SpecInfo, parsedNode *yaml.Node) { + var jsonSpec map[string]interface{} + + if spec.SpecType == utils.OpenApi3 { + switch spec.Version { + case "3.1.0", "3.1": + spec.APISchema = OpenAPI31SchemaData + default: + spec.APISchema = OpenAPI3SchemaData + } + } + if spec.SpecType == utils.OpenApi2 { + spec.APISchema = OpenAPI2SchemaData + } + + if utils.IsYAML(string(bytes)) { + _ = parsedNode.Decode(&jsonSpec) + b, _ := json.Marshal(&jsonSpec) + spec.SpecJSONBytes = &b + spec.SpecJSON = &jsonSpec + } else { + _ = json.Unmarshal(bytes, &jsonSpec) + spec.SpecJSONBytes = &bytes + spec.SpecJSON = &jsonSpec + } + close(spec.JsonParsingChannel) // this needs removing at some point + } + + // check for specific keys + if openAPI3 != nil { + version, majorVersion, versionError := parseVersionTypeData(openAPI3.Value) + if versionError != nil { + return nil, versionError + } + + specVersion.SpecType = utils.OpenApi3 + specVersion.Version = version + specVersion.SpecFormat = OAS3 + + // parse JSON + parseJSON(spec, specVersion, &parsedSpec) + + // double check for the right version, people mix this up. + if majorVersion < 3 { + specVersion.Error = errors.New("spec is defined as an openapi spec, but is using a swagger (2.0), or unknown version") + return specVersion, specVersion.Error + } + } + + if openAPI2 != nil { + version, majorVersion, versionError := parseVersionTypeData(openAPI2.Value) + if versionError != nil { + return nil, versionError + } + + specVersion.SpecType = utils.OpenApi2 + specVersion.Version = version + specVersion.SpecFormat = OAS2 + + // parse JSON + parseJSON(spec, specVersion, &parsedSpec) + + // I am not certain this edge-case is very frequent, but let's make sure we handle it anyway. + if majorVersion > 2 { + specVersion.Error = errors.New("spec is defined as a swagger (openapi 2.0) spec, but is an openapi 3 or unknown version") + return specVersion, specVersion.Error + } + } + if asyncAPI != nil { + version, majorVersion, versionErr := parseVersionTypeData(asyncAPI.Value) + if versionErr != nil { + return nil, versionErr + } + + specVersion.SpecType = utils.AsyncApi + specVersion.Version = version + // TODO: format for AsyncAPI. + + // parse JSON + parseJSON(spec, specVersion, &parsedSpec) + + // so far there is only 2 as a major release of AsyncAPI + if majorVersion > 2 { + specVersion.Error = errors.New("spec is defined as asyncapi, but has a major version that is invalid") + return specVersion, specVersion.Error + } + } + + if specVersion.SpecType == "" { + // parse JSON + parseJSON(spec, specVersion, &parsedSpec) + specVersion.Error = errors.New("spec type not supported by libopenapi, sorry") + return specVersion, specVersion.Error + } + + return specVersion, nil +} + +// extract version number from specification +func parseVersionTypeData(d interface{}) (string, int, error) { + r := []rune(strings.TrimSpace(fmt.Sprintf("%v", d))) + if len(r) <= 0 { + return "", 0, fmt.Errorf("unable to extract version from: %v", d) + } + return string(r), int(r[0]) - '0', nil +} diff --git a/vendor/github.com/pb33f/libopenapi/document.go b/vendor/github.com/pb33f/libopenapi/document.go new file mode 100644 index 0000000000..f58faeea81 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/document.go @@ -0,0 +1,305 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +// Package libopenapi is a library containing tools for reading and in and manipulating Swagger (OpenAPI 2) and OpenAPI 3+ +// specifications into strongly typed documents. These documents have two APIs, a high level (porcelain) and a +// low level (plumbing). +// +// Every single type has a 'GoLow()' method that drops down from the high API to the low API. Once in the low API, +// the entire original document data is available, including all comments, line and column numbers for keys and values. +// +// There are two steps to creating a using Document. First, create a new Document using the NewDocument() method +// and pass in a specification []byte array that contains the OpenAPI Specification. It doesn't matter if YAML or JSON +// are used. +package libopenapi + +import ( + "errors" + "fmt" + + "github.com/pb33f/libopenapi/index" + + "github.com/pb33f/libopenapi/datamodel" + v2high "github.com/pb33f/libopenapi/datamodel/high/v2" + v3high "github.com/pb33f/libopenapi/datamodel/high/v3" + v2low "github.com/pb33f/libopenapi/datamodel/low/v2" + v3low "github.com/pb33f/libopenapi/datamodel/low/v3" + "github.com/pb33f/libopenapi/resolver" + "github.com/pb33f/libopenapi/utils" + what_changed "github.com/pb33f/libopenapi/what-changed" + "github.com/pb33f/libopenapi/what-changed/model" + "gopkg.in/yaml.v3" +) + +// Document Represents an OpenAPI specification that can then be rendered into a model or serialized back into +// a string document after being manipulated. +type Document interface { + // GetVersion will return the exact version of the OpenAPI specification set for the document. + GetVersion() string + + // GetSpecInfo will return the *datamodel.SpecInfo instance that contains all specification information. + GetSpecInfo() *datamodel.SpecInfo + + // SetConfiguration will set the configuration for the document. This allows for finer grained control over + // allowing remote or local references, as well as a BaseURL to allow for relative file references. + SetConfiguration(configuration *datamodel.DocumentConfiguration) + + // BuildV2Model will build out a Swagger (version 2) model from the specification used to create the document + // If there are any issues, then no model will be returned, instead a slice of errors will explain all the + // problems that occurred. This method will only support version 2 specifications and will throw an error for + // any other types. + BuildV2Model() (*DocumentModel[v2high.Swagger], []error) + + // BuildV3Model will build out an OpenAPI (version 3+) model from the specification used to create the document + // If there are any issues, then no model will be returned, instead a slice of errors will explain all the + // problems that occurred. This method will only support version 3 specifications and will throw an error for + // any other types. + BuildV3Model() (*DocumentModel[v3high.Document], []error) + + // RenderAndReload will render the high level model as it currently exists (including any mutations, additions + // and removals to and from any object in the tree). It will then reload the low level model with the new bytes + // extracted from the model that was re-rendered. This is useful if you want to make changes to the high level model + // and then 'reload' the model into memory, so that line numbers and column numbers are correct and all update + // according to the changes made. + // + // The method returns the raw YAML bytes that were rendered, and any errors that occurred during rebuilding of the model. + // This is a destructive operation, and will re-build the entire model from scratch using the new bytes, so any + // references to the old model will be lost. The second return is the new Document that was created, and the third + // return is any errors hit trying to re-render. + // + // **IMPORTANT** This method only supports OpenAPI Documents. The Swagger model will not support mutations correctly + // and will not update when called. This choice has been made because we don't want to continue supporting Swagger, + // it's too old, so it should be motivation to upgrade to OpenAPI 3. + RenderAndReload() ([]byte, Document, *DocumentModel[v3high.Document], []error) + + // Serialize will re-render a Document back into a []byte slice. If any modifications have been made to the + // underlying data model using low level APIs, then those changes will be reflected in the serialized output. + // + // It's important to know that this should not be used if the resolver has been used on a specification to + // for anything other than checking for circular references. If the resolver is used to resolve the spec, then this + // method may spin out forever if the specification backing the model has circular references. + // Deprecated: This method is deprecated and will be removed in a future release. Use RenderAndReload() instead. + // This method does not support mutations correctly. + Serialize() ([]byte, error) +} + +type document struct { + version string + info *datamodel.SpecInfo + config *datamodel.DocumentConfiguration + highOpenAPI3Model *DocumentModel[v3high.Document] + highSwaggerModel *DocumentModel[v2high.Swagger] +} + +// DocumentModel represents either a Swagger document (version 2) or an OpenAPI document (version 3) that is +// built from a parent Document. +type DocumentModel[T v2high.Swagger | v3high.Document] struct { + Model T + Index *index.SpecIndex // index created from the document. +} + +// NewDocument will create a new OpenAPI instance from an OpenAPI specification []byte array. If anything goes +// wrong when parsing, reading or processing the OpenAPI specification, there will be no document returned, instead +// a slice of errors will be returned that explain everything that failed. +// +// After creating a Document, the option to build a model becomes available, in either V2 or V3 flavors. The models +// are about 70% different between Swagger and OpenAPI 3, which is why two different models are available. +// +// This function will automatically follow (meaning load) any file or remote references that are found anywhere. +// Which means recursively also, like a spider, it will follow every reference found, local or remote. +// +// If this isn't the behavior you want, or that you feel this is a potential security risk, +// then you can use the NewDocumentWithConfiguration() function instead, which allows you to set a configuration that +// will allow you to control if file or remote references are allowed. +func NewDocument(specByteArray []byte) (Document, error) { + info, err := datamodel.ExtractSpecInfo(specByteArray) + if err != nil { + return nil, err + } + d := new(document) + d.version = info.Version + d.info = info + return d, nil +} + +// NewDocumentWithConfiguration is the same as NewDocument, except it's a convenience function that calls NewDocument +// under the hood and then calls SetConfiguration() on the returned Document. +func NewDocumentWithConfiguration(specByteArray []byte, configuration *datamodel.DocumentConfiguration) (Document, error) { + d, err := NewDocument(specByteArray) + if d != nil { + d.SetConfiguration(configuration) + } + return d, err +} + +func (d *document) GetVersion() string { + return d.version +} + +func (d *document) GetSpecInfo() *datamodel.SpecInfo { + return d.info +} + +func (d *document) SetConfiguration(configuration *datamodel.DocumentConfiguration) { + d.config = configuration +} + +func (d *document) Serialize() ([]byte, error) { + if d.info == nil { + return nil, fmt.Errorf("unable to serialize, document has not yet been initialized") + } + if d.info.SpecFileType == datamodel.YAMLFileType { + return yaml.Marshal(d.info.RootNode) + } else { + yamlData, _ := yaml.Marshal(d.info.RootNode) + return utils.ConvertYAMLtoJSON(yamlData) + } +} + +func (d *document) RenderAndReload() ([]byte, Document, *DocumentModel[v3high.Document], []error) { + if d.highSwaggerModel != nil && d.highOpenAPI3Model == nil { + return nil, nil, nil, []error{errors.New("this method only supports OpenAPI 3 documents, not Swagger")} + } + newBytes, err := d.highOpenAPI3Model.Model.Render() + if err != nil { + return newBytes, nil, nil, []error{err} + } + newDoc, err := NewDocumentWithConfiguration(newBytes, d.config) + if err != nil { + return newBytes, newDoc, nil, []error{err} + } + // build the model. + model, errs := newDoc.BuildV3Model() + if errs != nil { + return newBytes, newDoc, model, errs + } + // this document is now dead, long live the new document! + return newBytes, newDoc, model, nil +} + +func (d *document) BuildV2Model() (*DocumentModel[v2high.Swagger], []error) { + if d.highSwaggerModel != nil { + return d.highSwaggerModel, nil + } + var errors []error + if d.info == nil { + errors = append(errors, fmt.Errorf("unable to build swagger document, no specification has been loaded")) + return nil, errors + } + if d.info.SpecFormat != datamodel.OAS2 { + errors = append(errors, fmt.Errorf("unable to build swagger document, "+ + "supplied spec is a different version (%v). Try 'BuildV3Model()'", d.info.SpecFormat)) + return nil, errors + } + + var lowDoc *v2low.Swagger + if d.config == nil { + d.config = &datamodel.DocumentConfiguration{ + AllowFileReferences: false, + AllowRemoteReferences: false, + } + } + + lowDoc, errors = v2low.CreateDocumentFromConfig(d.info, d.config) + // Do not short-circuit on circular reference errors, so the client + // has the option of ignoring them. + for _, err := range errors { + if refErr, ok := err.(*resolver.ResolvingError); ok { + if refErr.CircularReference == nil { + return nil, errors + } + } else { + return nil, errors + } + } + highDoc := v2high.NewSwaggerDocument(lowDoc) + d.highSwaggerModel = &DocumentModel[v2high.Swagger]{ + Model: *highDoc, + Index: lowDoc.Index, + } + return d.highSwaggerModel, errors +} + +func (d *document) BuildV3Model() (*DocumentModel[v3high.Document], []error) { + if d.highOpenAPI3Model != nil { + return d.highOpenAPI3Model, nil + } + var errors []error + if d.info == nil { + errors = append(errors, fmt.Errorf("unable to build document, no specification has been loaded")) + return nil, errors + } + if d.info.SpecFormat != datamodel.OAS3 { + errors = append(errors, fmt.Errorf("unable to build openapi document, "+ + "supplied spec is a different version (%v). Try 'BuildV2Model()'", d.info.SpecFormat)) + return nil, errors + } + + var lowDoc *v3low.Document + if d.config == nil { + d.config = &datamodel.DocumentConfiguration{ + AllowFileReferences: false, + AllowRemoteReferences: false, + } + } + + lowDoc, errors = v3low.CreateDocumentFromConfig(d.info, d.config) + // Do not short-circuit on circular reference errors, so the client + // has the option of ignoring them. + for _, err := range errors { + if refErr, ok := err.(*resolver.ResolvingError); ok { + if refErr.CircularReference == nil { + return nil, errors + } + } else { + return nil, errors + } + } + highDoc := v3high.NewDocument(lowDoc) + d.highOpenAPI3Model = &DocumentModel[v3high.Document]{ + Model: *highDoc, + Index: lowDoc.Index, + } + return d.highOpenAPI3Model, errors +} + +// CompareDocuments will accept a left and right Document implementing struct, build a model for the correct +// version and then compare model documents for changes. +// +// If there are any errors when building the models, those errors are returned with a nil pointer for the +// model.DocumentChanges. If there are any changes found however between either Document, then a pointer to +// model.DocumentChanges is returned containing every single change, broken down, model by model. +func CompareDocuments(original, updated Document) (*model.DocumentChanges, []error) { + var errors []error + if original.GetSpecInfo().SpecType == utils.OpenApi3 && updated.GetSpecInfo().SpecType == utils.OpenApi3 { + v3ModelLeft, errs := original.BuildV3Model() + if len(errs) > 0 { + errors = errs + } + v3ModelRight, errs := updated.BuildV3Model() + if len(errs) > 0 { + errors = append(errors, errs...) + } + if v3ModelLeft != nil && v3ModelRight != nil { + return what_changed.CompareOpenAPIDocuments(v3ModelLeft.Model.GoLow(), v3ModelRight.Model.GoLow()), errors + } else { + return nil, errors + } + } + if original.GetSpecInfo().SpecType == utils.OpenApi2 && updated.GetSpecInfo().SpecType == utils.OpenApi2 { + v2ModelLeft, errs := original.BuildV2Model() + if len(errs) > 0 { + errors = errs + } + v2ModelRight, errs := updated.BuildV2Model() + if len(errs) > 0 { + errors = append(errors, errs...) + } + if v2ModelLeft != nil && v2ModelRight != nil { + return what_changed.CompareSwaggerDocuments(v2ModelLeft.Model.GoLow(), v2ModelRight.Model.GoLow()), errors + } else { + return nil, errors + } + } + return nil, []error{fmt.Errorf("unable to compare documents, one or both documents are not of the same version")} +} diff --git a/vendor/github.com/pb33f/libopenapi/index/circular_reference_result.go b/vendor/github.com/pb33f/libopenapi/index/circular_reference_result.go new file mode 100644 index 0000000000..a710d6a932 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/index/circular_reference_result.go @@ -0,0 +1,29 @@ +package index + +import "strings" + +// CircularReferenceResult contains a circular reference found when traversing the graph. +type CircularReferenceResult struct { + Journey []*Reference + Start *Reference + LoopIndex int + LoopPoint *Reference + IsPolymorphicResult bool // if this result comes from a polymorphic loop. + IsInfiniteLoop bool // if all the definitions in the reference loop are marked as required, this is an infinite circular reference, thus is not allowed. +} + +func (c *CircularReferenceResult) GenerateJourneyPath() string { + buf := strings.Builder{} + for i, ref := range c.Journey { + if i > 0 { + buf.WriteString(" -> ") + } + + buf.WriteString(ref.Name) + // buf.WriteString(" (") + // buf.WriteString(ref.Definition) + // buf.WriteString(")") + } + + return buf.String() +} diff --git a/vendor/github.com/pb33f/libopenapi/index/extract_refs.go b/vendor/github.com/pb33f/libopenapi/index/extract_refs.go new file mode 100644 index 0000000000..984b94d41f --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/index/extract_refs.go @@ -0,0 +1,432 @@ +// Copyright 2023 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package index + +import ( + "errors" + "fmt" + "github.com/pb33f/libopenapi/utils" + "gopkg.in/yaml.v3" + "strings" +) + +// ExtractRefs will return a deduplicated slice of references for every unique ref found in the document. +// The total number of refs, will generally be much higher, you can extract those from GetRawReferenceCount() +func (index *SpecIndex) ExtractRefs(node, parent *yaml.Node, seenPath []string, level int, poly bool, pName string) []*Reference { + if node == nil { + return nil + } + var found []*Reference + if len(node.Content) > 0 { + var prev, polyName string + for i, n := range node.Content { + + if utils.IsNodeMap(n) || utils.IsNodeArray(n) { + level++ + // check if we're using polymorphic values. These tend to create rabbit warrens of circular + // references if every single link is followed. We don't resolve polymorphic values. + isPoly, _ := index.checkPolymorphicNode(prev) + polyName = pName + if isPoly { + poly = true + if prev != "" { + polyName = prev + } + } + found = append(found, index.ExtractRefs(n, node, seenPath, level, poly, polyName)...) + } + + // check if we're dealing with an inline schema definition, that isn't part of an array + // (which means it's being used as a value in an array, and it's not a label) + // https://github.com/pb33f/libopenapi/issues/76 + if i%2 == 0 && n.Value == "schema" && !utils.IsNodeArray(node) && (i+1 < len(node.Content)) { + isRef, _, _ := utils.IsNodeRefValue(node.Content[i+1]) + if isRef { + continue + } + ref := &Reference{ + Node: node.Content[i+1], + Path: fmt.Sprintf("$.%s.schema", strings.Join(seenPath, ".")), + } + index.allInlineSchemaDefinitions = append(index.allInlineSchemaDefinitions, ref) + + // check if the schema is an object or an array, + // and if so, add it to the list of inline schema object definitions. + k, v := utils.FindKeyNodeTop("type", node.Content[i+1].Content) + if k != nil && v != nil { + if v.Value == "object" || v.Value == "array" { + index.allInlineSchemaObjectDefinitions = append(index.allInlineSchemaObjectDefinitions, ref) + } + } + } + + // Perform the same check for all properties in an inline schema definition + // https://github.com/pb33f/libopenapi/issues/76 + if i%2 == 0 && n.Value == "properties" && !utils.IsNodeArray(node) && (i+1 < len(node.Content)) { + isRef, _, _ := utils.IsNodeRefValue(node.Content[i+1]) + if isRef { + continue + } + + // for each property add it to our schema definitions + label := "" + for h, prop := range node.Content[i+1].Content { + + if h%2 == 0 { + label = prop.Value + continue + } + + ref := &Reference{ + Node: prop, + Path: fmt.Sprintf("$.%s.properties.%s", strings.Join(seenPath, "."), label), + } + index.allInlineSchemaDefinitions = append(index.allInlineSchemaDefinitions, ref) + + // check if the schema is an object or an array, + // and if so, add it to the list of inline schema object definitions. + k, v := utils.FindKeyNodeTop("type", node.Content[i+1].Content) + if k != nil && v != nil { + if v.Value == "object" || v.Value == "array" { + index.allInlineSchemaObjectDefinitions = append(index.allInlineSchemaObjectDefinitions, ref) + } + } + } + } + + if i%2 == 0 && n.Value == "$ref" { + + // only look at scalar values, not maps (looking at you k8s) + if !utils.IsNodeStringValue(node.Content[i+1]) { + continue + } + + index.linesWithRefs[n.Line] = true + + fp := make([]string, len(seenPath)) + for x, foundPathNode := range seenPath { + fp[x] = foundPathNode + } + + value := node.Content[i+1].Value + + segs := strings.Split(value, "/") + name := segs[len(segs)-1] + _, p := utils.ConvertComponentIdIntoFriendlyPathSearch(value) + ref := &Reference{ + Definition: value, + Name: name, + Node: node, + Path: p, + } + + // add to raw sequenced refs + index.rawSequencedRefs = append(index.rawSequencedRefs, ref) + + // add ref by line number + refNameIndex := strings.LastIndex(value, "/") + refName := value[refNameIndex+1:] + if len(index.refsByLine[refName]) > 0 { + index.refsByLine[refName][n.Line] = true + } else { + v := make(map[int]bool) + v[n.Line] = true + index.refsByLine[refName] = v + } + + // if this ref value has any siblings (node.Content is larger than two elements) + // then add to refs with siblings + if len(node.Content) > 2 { + copiedNode := *node + copied := Reference{ + Definition: ref.Definition, + Name: ref.Name, + Node: &copiedNode, + Path: p, + } + // protect this data using a copy, prevent the resolver from destroying things. + index.refsWithSiblings[value] = copied + } + + // if this is a polymorphic reference, we're going to leave it out + // allRefs. We don't ever want these resolved, so instead of polluting + // the timeline, we will keep each poly ref in its own collection for later + // analysis. + if poly { + index.polymorphicRefs[value] = ref + + // index each type + switch pName { + case "anyOf": + index.polymorphicAnyOfRefs = append(index.polymorphicAnyOfRefs, ref) + case "allOf": + index.polymorphicAllOfRefs = append(index.polymorphicAllOfRefs, ref) + case "oneOf": + index.polymorphicOneOfRefs = append(index.polymorphicOneOfRefs, ref) + } + continue + } + + // check if this is a dupe, if so, skip it, we don't care now. + if index.allRefs[value] != nil { // seen before, skip. + continue + } + + if value == "" { + + completedPath := fmt.Sprintf("$.%s", strings.Join(fp, ".")) + + indexError := &IndexingError{ + Err: errors.New("schema reference is empty and cannot be processed"), + Node: node.Content[i+1], + Path: completedPath, + } + + index.refErrors = append(index.refErrors, indexError) + + continue + } + + index.allRefs[value] = ref + found = append(found, ref) + } + + if i%2 == 0 && n.Value != "$ref" && n.Value != "" { + + nodePath := fmt.Sprintf("$.%s", strings.Join(seenPath, ".")) + + // capture descriptions and summaries + if n.Value == "description" { + + // if the parent is a sequence, ignore. + if utils.IsNodeArray(node) { + continue + } + + ref := &DescriptionReference{ + Content: node.Content[i+1].Value, + Path: nodePath, + Node: node.Content[i+1], + IsSummary: false, + } + + if !utils.IsNodeMap(ref.Node) { + index.allDescriptions = append(index.allDescriptions, ref) + index.descriptionCount++ + } + } + + if n.Value == "summary" { + + var b *yaml.Node + if len(node.Content) == i+1 { + b = node.Content[i] + } else { + b = node.Content[i+1] + } + ref := &DescriptionReference{ + Content: b.Value, + Path: nodePath, + Node: b, + IsSummary: true, + } + + index.allSummaries = append(index.allSummaries, ref) + index.summaryCount++ + } + + // capture security requirement references (these are not traditional references, but they + // are used as a look-up. This is the only exception to the design. + if n.Value == "security" { + var b *yaml.Node + if len(node.Content) == i+1 { + b = node.Content[i] + } else { + b = node.Content[i+1] + } + if utils.IsNodeArray(b) { + var secKey string + for k := range b.Content { + if utils.IsNodeMap(b.Content[k]) { + for g := range b.Content[k].Content { + if g%2 == 0 { + secKey = b.Content[k].Content[g].Value + continue + } + if utils.IsNodeArray(b.Content[k].Content[g]) { + var refMap map[string][]*Reference + if index.securityRequirementRefs[secKey] == nil { + index.securityRequirementRefs[secKey] = make(map[string][]*Reference) + refMap = index.securityRequirementRefs[secKey] + } else { + refMap = index.securityRequirementRefs[secKey] + } + for r := range b.Content[k].Content[g].Content { + var refs []*Reference + if refMap[b.Content[k].Content[g].Content[r].Value] != nil { + refs = refMap[b.Content[k].Content[g].Content[r].Value] + } + + refs = append(refs, &Reference{ + Definition: b.Content[k].Content[g].Content[r].Value, + Path: fmt.Sprintf("%s.security[%d].%s[%d]", nodePath, k, secKey, r), + Node: b.Content[k].Content[g].Content[r], + }) + + index.securityRequirementRefs[secKey][b.Content[k].Content[g].Content[r].Value] = refs + } + } + } + } + } + } + } + // capture enums + if n.Value == "enum" { + + // all enums need to have a type, extract the type from the node where the enum was found. + _, enumKeyValueNode := utils.FindKeyNodeTop("type", node.Content) + + if enumKeyValueNode != nil { + ref := &EnumReference{ + Path: nodePath, + Node: node.Content[i+1], + Type: enumKeyValueNode, + SchemaNode: node, + ParentNode: parent, + } + + index.allEnums = append(index.allEnums, ref) + index.enumCount++ + } + } + // capture all objects with properties + if n.Value == "properties" { + _, typeKeyValueNode := utils.FindKeyNodeTop("type", node.Content) + + if typeKeyValueNode != nil { + isObject := false + + if typeKeyValueNode.Value == "object" { + isObject = true + } + + for _, v := range typeKeyValueNode.Content { + if v.Value == "object" { + isObject = true + } + } + + if isObject { + index.allObjectsWithProperties = append(index.allObjectsWithProperties, &ObjectReference{ + Path: nodePath, + Node: node, + ParentNode: parent, + }) + } + } + } + + seenPath = append(seenPath, n.Value) + prev = n.Value + } + + // if next node is map, don't add segment. + if i < len(node.Content)-1 { + next := node.Content[i+1] + + if i%2 != 0 && next != nil && !utils.IsNodeArray(next) && !utils.IsNodeMap(next) { + seenPath = seenPath[:len(seenPath)-1] + } + } + } + if len(seenPath) > 0 { + seenPath = seenPath[:len(seenPath)-1] + } + + } + if len(seenPath) > 0 { + seenPath = seenPath[:len(seenPath)-1] + } + + index.refCount = len(index.allRefs) + + return found +} + +// ExtractComponentsFromRefs returns located components from references. The returned nodes from here +// can be used for resolving as they contain the actual object properties. +func (index *SpecIndex) ExtractComponentsFromRefs(refs []*Reference) []*Reference { + var found []*Reference + + //run this async because when things get recursive, it can take a while + c := make(chan bool) + + locate := func(ref *Reference, refIndex int, sequence []*ReferenceMapped) { + located := index.FindComponent(ref.Definition, ref.Node) + if located != nil { + index.refLock.Lock() + if index.allMappedRefs[ref.Definition] == nil { + found = append(found, located) + index.allMappedRefs[ref.Definition] = located + sequence[refIndex] = &ReferenceMapped{ + Reference: located, + Definition: ref.Definition, + } + } + index.refLock.Unlock() + } else { + + _, path := utils.ConvertComponentIdIntoFriendlyPathSearch(ref.Definition) + indexError := &IndexingError{ + Err: fmt.Errorf("component '%s' does not exist in the specification", ref.Definition), + Node: ref.Node, + Path: path, + } + index.errorLock.Lock() + index.refErrors = append(index.refErrors, indexError) + index.errorLock.Unlock() + } + c <- true + } + + var refsToCheck []*Reference + for _, ref := range refs { + + // check reference for backslashes (hah yeah seen this too!) + if strings.Contains(ref.Definition, "\\") { // this was from blazemeter.com haha! + _, path := utils.ConvertComponentIdIntoFriendlyPathSearch(ref.Definition) + indexError := &IndexingError{ + Err: fmt.Errorf("component '%s' contains a backslash '\\'. It's not valid", ref.Definition), + Node: ref.Node, + Path: path, + } + index.refErrors = append(index.refErrors, indexError) + continue + + } + refsToCheck = append(refsToCheck, ref) + } + mappedRefsInSequence := make([]*ReferenceMapped, len(refsToCheck)) + + for r := range refsToCheck { + // expand our index of all mapped refs + go locate(refsToCheck[r], r, mappedRefsInSequence) + //locate(refsToCheck[r], r, mappedRefsInSequence) // used for sync testing. + } + + completedRefs := 0 + for completedRefs < len(refsToCheck) { + select { + case <-c: + completedRefs++ + } + } + for m := range mappedRefsInSequence { + if mappedRefsInSequence[m] != nil { + index.allMappedRefsSequenced = append(index.allMappedRefsSequenced, mappedRefsInSequence[m]) + } + } + return found +} diff --git a/vendor/github.com/pb33f/libopenapi/index/find_component.go b/vendor/github.com/pb33f/libopenapi/index/find_component.go new file mode 100644 index 0000000000..50e2473088 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/index/find_component.go @@ -0,0 +1,399 @@ +// Copyright 2023 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package index + +import ( + "fmt" + "github.com/pb33f/libopenapi/utils" + "github.com/vmware-labs/yaml-jsonpath/pkg/yamlpath" + "gopkg.in/yaml.v3" + "io/ioutil" + "net/http" + "net/url" + "os" + "path/filepath" + "strings" + "time" +) + +// FindComponent will locate a component by its reference, returns nil if nothing is found. +// This method will recurse through remote, local and file references. For each new external reference +// a new index will be created. These indexes can then be traversed recursively. +func (index *SpecIndex) FindComponent(componentId string, parent *yaml.Node) *Reference { + if index.root == nil { + return nil + } + + remoteLookup := func(id string) (*yaml.Node, *yaml.Node, error) { + if index.config.AllowRemoteLookup { + return index.lookupRemoteReference(id) + } else { + return nil, nil, fmt.Errorf("remote lookups are not permitted, " + + "please set AllowRemoteLookup to true in the configuration") + } + } + + fileLookup := func(id string) (*yaml.Node, *yaml.Node, error) { + if index.config.AllowFileLookup { + return index.lookupFileReference(id) + } else { + return nil, nil, fmt.Errorf("local lookups are not permitted, " + + "please set AllowFileLookup to true in the configuration") + } + } + + switch DetermineReferenceResolveType(componentId) { + case LocalResolve: // ideally, every single ref in every single spec is local. however, this is not the case. + return index.FindComponentInRoot(componentId) + + case HttpResolve: + uri := strings.Split(componentId, "#") + if len(uri) >= 2 { + return index.performExternalLookup(uri, componentId, remoteLookup, parent) + } + if len(uri) == 1 { + // if there is no reference, second segment is empty / has no name + // this means there is no component to look-up and the entire file should be pulled in. + // to stop all the other code from breaking (that is expecting a component), let's just post-pend + // a hash to the end of the componentId and ensure the uri slice is as expected. + // described in https://github.com/pb33f/libopenapi/issues/37 + componentId = fmt.Sprintf("%s#", componentId) + uri = append(uri, "") + return index.performExternalLookup(uri, componentId, remoteLookup, parent) + } + + case FileResolve: + uri := strings.Split(componentId, "#") + if len(uri) == 2 { + return index.performExternalLookup(uri, componentId, fileLookup, parent) + } + if len(uri) == 1 { + // if there is no reference, second segment is empty / has no name + // this means there is no component to look-up and the entire file should be pulled in. + // to stop all the other code from breaking (that is expecting a component), let's just post-pend + // a hash to the end of the componentId and ensure the uri slice is as expected. + // described in https://github.com/pb33f/libopenapi/issues/37 + // + // ^^ this same issue was re-reported in file based lookups in vacuum. + // more info here: https://github.com/daveshanley/vacuum/issues/225 + componentId = fmt.Sprintf("%s#", componentId) + uri = append(uri, "") + return index.performExternalLookup(uri, componentId, fileLookup, parent) + } + } + return nil +} + +var httpClient = &http.Client{Timeout: time.Duration(60) * time.Second} + +func getRemoteDoc(u string, d chan []byte, e chan error) { + resp, err := httpClient.Get(u) + if err != nil { + e <- err + close(e) + close(d) + return + } + var body []byte + body, _ = ioutil.ReadAll(resp.Body) + d <- body + close(e) + close(d) +} + +func (index *SpecIndex) lookupRemoteReference(ref string) (*yaml.Node, *yaml.Node, error) { + // split string to remove file reference + uri := strings.Split(ref, "#") + + // have we already seen this remote source? + var parsedRemoteDocument *yaml.Node + alreadySeen, foundDocument := index.CheckForSeenRemoteSource(uri[0]) + + if alreadySeen { + parsedRemoteDocument = foundDocument + } else { + + d := make(chan bool) + var body []byte + var err error + + go func(uri string) { + bc := make(chan []byte) + ec := make(chan error) + go getRemoteDoc(uri, bc, ec) + select { + case v := <-bc: + body = v + break + case er := <-ec: + err = er + break + } + var remoteDoc yaml.Node + er := yaml.Unmarshal(body, &remoteDoc) + if er != nil { + err = er + d <- true + return + } + parsedRemoteDocument = &remoteDoc + if index.config != nil { + index.config.seenRemoteSources.Store(uri, &remoteDoc) + } + d <- true + }(uri[0]) + + // wait for double go fun. + <-d + if err != nil { + // no bueno. + return nil, nil, err + } + } + + // lookup item from reference by using a path query. + var query string + if len(uri) >= 2 { + query = fmt.Sprintf("$%s", strings.ReplaceAll(uri[1], "/", ".")) + } else { + query = "$" + } + + // remove any URL encoding + query = strings.Replace(query, "~1", "./", 1) + query = strings.ReplaceAll(query, "~1", "/") + + path, err := yamlpath.NewPath(query) + if err != nil { + return nil, nil, err + } + result, _ := path.Find(parsedRemoteDocument) + if len(result) == 1 { + return result[0], parsedRemoteDocument, nil + } + return nil, nil, nil +} + +func (index *SpecIndex) lookupFileReference(ref string) (*yaml.Node, *yaml.Node, error) { + // split string to remove file reference + uri := strings.Split(ref, "#") + file := strings.ReplaceAll(uri[0], "file:", "") + filePath := filepath.Dir(file) + fileName := filepath.Base(file) + + var parsedRemoteDocument *yaml.Node + + if index.seenRemoteSources[file] != nil { + parsedRemoteDocument = index.seenRemoteSources[file] + } else { + + base := index.config.BasePath + fileToRead := filepath.Join(base, filePath, fileName) + + // try and read the file off the local file system, if it fails + // check for a baseURL and then ask our remote lookup function to go try and get it. + body, err := os.ReadFile(fileToRead) + + if err != nil { + + // if we have a baseURL, then we can try and get the file from there. + if index.config != nil && index.config.BaseURL != nil { + + u := index.config.BaseURL + remoteRef := GenerateCleanSpecConfigBaseURL(u, ref, true) + a, b, e := index.lookupRemoteReference(remoteRef) + if e != nil { + // give up, we can't find the file, not locally, not remotely. It's toast. + return nil, nil, e + } + return a, b, nil + + } else { + // no baseURL? then we can't do anything, give up. + return nil, nil, err + } + } + + var remoteDoc yaml.Node + err = yaml.Unmarshal(body, &remoteDoc) + if err != nil { + return nil, nil, err + } + parsedRemoteDocument = &remoteDoc + if index.seenLocalSources != nil { + index.sourceLock.Lock() + index.seenLocalSources[file] = &remoteDoc + index.sourceLock.Unlock() + } + } + + // lookup item from reference by using a path query. + var query string + if len(uri) >= 2 { + query = fmt.Sprintf("$%s", strings.ReplaceAll(uri[1], "/", ".")) + } else { + query = "$" + } + + // remove any URL encoding + query = strings.Replace(query, "~1", "./", 1) + query = strings.ReplaceAll(query, "~1", "/") + + path, err := yamlpath.NewPath(query) + if err != nil { + return nil, nil, err + } + result, _ := path.Find(parsedRemoteDocument) + if len(result) == 1 { + return result[0], parsedRemoteDocument, nil + } + + return nil, parsedRemoteDocument, nil +} + +func (index *SpecIndex) FindComponentInRoot(componentId string) *Reference { + if index.root != nil { + + // check component for url encoding. + if strings.Contains(componentId, "%") { + // decode the url. + componentId, _ = url.QueryUnescape(componentId) + } + + name, friendlySearch := utils.ConvertComponentIdIntoFriendlyPathSearch(componentId) + path, err := yamlpath.NewPath(friendlySearch) + if path == nil || err != nil { + return nil // no component found + } + res, _ := path.Find(index.root) + + if len(res) == 1 { + resNode := res[0] + if res[0].Kind == yaml.DocumentNode { + resNode = res[0].Content[0] + } + ref := &Reference{ + Definition: componentId, + Name: name, + Node: resNode, + Path: friendlySearch, + RequiredRefProperties: index.extractDefinitionRequiredRefProperties(res[0], map[string][]string{}), + } + + return ref + } + } + return nil +} + +func (index *SpecIndex) performExternalLookup(uri []string, componentId string, + lookupFunction ExternalLookupFunction, parent *yaml.Node) *Reference { + if len(uri) > 0 { + index.externalLock.RLock() + externalSpecIndex := index.externalSpecIndex[uri[0]] + index.externalLock.RUnlock() + + if externalSpecIndex == nil { + _, newRoot, err := lookupFunction(componentId) + if err != nil { + indexError := &IndexingError{ + Err: err, + Node: parent, + Path: componentId, + } + index.errorLock.Lock() + index.refErrors = append(index.refErrors, indexError) + index.errorLock.Unlock() + return nil + } + + // cool, cool, lets index this spec also. This is a recursive action and will keep going + // until all remote references have been found. + var bp *url.URL + var bd string + + if index.config.BaseURL != nil { + bp = index.config.BaseURL + } + if index.config.BasePath != "" { + bd = index.config.BasePath + } + + var path, newBasePath string + var newUrl *url.URL + + if bp != nil { + path = GenerateCleanSpecConfigBaseURL(bp, uri[0], false) + newUrl, _ = url.Parse(path) + newBasePath = filepath.Dir(filepath.Join(index.config.BasePath, filepath.Dir(newUrl.Path))) + } + if bd != "" { + if len(uri[0]) > 0 { + // if there is no base url defined, but we can know we have been requested remotely, + // set the base url to the remote url base path. + // first check if the first param is actually a URL + io, er := url.ParseRequestURI(uri[0]) + if er != nil { + newBasePath = filepath.Dir(filepath.Join(bd, uri[0])) + } else { + if newUrl == nil || newUrl.String() != io.String() { + newUrl, _ = url.Parse(fmt.Sprintf("%s://%s%s", io.Scheme, io.Host, filepath.Dir(io.Path))) + } + newBasePath = filepath.Dir(filepath.Join(bd, uri[1])) + } + } else { + newBasePath = filepath.Dir(filepath.Join(bd, uri[0])) + } + } + + if newUrl != nil || newBasePath != "" { + newConfig := &SpecIndexConfig{ + BaseURL: newUrl, + BasePath: newBasePath, + AllowRemoteLookup: index.config.AllowRemoteLookup, + AllowFileLookup: index.config.AllowFileLookup, + ParentIndex: index, + seenRemoteSources: index.config.seenRemoteSources, + remoteLock: index.config.remoteLock, + uri: uri, + } + + var newIndex *SpecIndex + seen := index.SearchAncestryForSeenURI(uri[0]) + if seen == nil { + + newIndex = NewSpecIndexWithConfig(newRoot, newConfig) + index.refLock.Lock() + index.externalLock.Lock() + index.externalSpecIndex[uri[0]] = newIndex + index.externalLock.Unlock() + newIndex.relativePath = path + newIndex.parentIndex = index + index.AddChild(newIndex) + index.refLock.Unlock() + externalSpecIndex = newIndex + } else { + externalSpecIndex = seen + } + } + } + + if externalSpecIndex != nil { + foundRef := externalSpecIndex.FindComponentInRoot(uri[1]) + if foundRef != nil { + nameSegs := strings.Split(uri[1], "/") + ref := &Reference{ + Definition: componentId, + Name: nameSegs[len(nameSegs)-1], + Node: foundRef.Node, + IsRemote: true, + RemoteLocation: componentId, + Path: foundRef.Path, + } + return ref + } + } + } + return nil +} diff --git a/vendor/github.com/pb33f/libopenapi/index/index_model.go b/vendor/github.com/pb33f/libopenapi/index/index_model.go new file mode 100644 index 0000000000..ddb811b64e --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/index/index_model.go @@ -0,0 +1,279 @@ +// Copyright 2023 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package index + +import ( + "golang.org/x/sync/syncmap" + "gopkg.in/yaml.v3" + "net/http" + "net/url" + "os" + "sync" +) + +// Constants used to determine if resolving is local, file based or remote file based. +const ( + LocalResolve = iota + HttpResolve + FileResolve +) + +// Reference is a wrapper around *yaml.Node results to make things more manageable when performing +// algorithms on data models. the *yaml.Node def is just a bit too low level for tracking state. +type Reference struct { + Definition string + Name string + Node *yaml.Node + ParentNode *yaml.Node + Resolved bool + Circular bool + Seen bool + IsRemote bool + RemoteLocation string + Path string // this won't always be available. + RequiredRefProperties map[string][]string // definition names (eg, #/definitions/One) to a list of required properties on this definition which reference that definition +} + +// ReferenceMapped is a helper struct for mapped references put into sequence (we lose the key) +type ReferenceMapped struct { + Reference *Reference + Definition string +} + +// SpecIndexConfig is a configuration struct for the SpecIndex introduced in 0.6.0 that provides an expandable +// set of granular options. The first being the ability to set the Base URL for resolving relative references, and +// allowing or disallowing remote or local file lookups. +// - https://github.com/pb33f/libopenapi/issues/73 +type SpecIndexConfig struct { + // The BaseURL will be the root from which relative references will be resolved from if they can't be found locally. + // + // For example: + // - $ref: somefile.yaml#/components/schemas/SomeSchema + // + // Might not be found locally, if the file was pulled in from a remote server (a good example is the DigitalOcean API). + // so by setting a BaseURL, the reference will try to be resolved from the remote server. + // + // If our baseURL is set to https://pb33f.io/libopenapi then our reference will try to be resolved from: + // - $ref: https://pb33f.io/libopenapi/somefile.yaml#/components/schemas/SomeSchema + // + // More details on relative references can be found in issue #73: https://github.com/pb33f/libopenapi/issues/73 + BaseURL *url.URL // set the Base URL for resolving relative references if the spec is exploded. + + // If resolving locally, the BasePath will be the root from which relative references will be resolved from + BasePath string // set the Base Path for resolving relative references if the spec is exploded. + + // In an earlier version of libopenapi (pre 0.6.0) the index would automatically resolve all references + // They could have been local, or they could have been remote. This was a problem because it meant + // There was a potential for a remote exploit if a remote reference was malicious. There aren't any known + // exploits, but it's better to be safe than sorry. + // + // To read more about this, you can find a discussion here: https://github.com/pb33f/libopenapi/pull/64 + AllowRemoteLookup bool // Allow remote lookups for references. Defaults to false + AllowFileLookup bool // Allow file lookups for references. Defaults to false + + // ParentIndex allows the index to be created with knowledge of a parent, before being parsed. This allows + // a breakglass to be used to prevent loops, checking the tree before recursing down. + ParentIndex *SpecIndex + + // private fields + seenRemoteSources *syncmap.Map + remoteLock *sync.Mutex + uri []string +} + +// CreateOpenAPIIndexConfig is a helper function to create a new SpecIndexConfig with the AllowRemoteLookup and +// AllowFileLookup set to true. This is the default behaviour of the index in previous versions of libopenapi. (pre 0.6.0) +// +// The default BasePath is the current working directory. +func CreateOpenAPIIndexConfig() *SpecIndexConfig { + cw, _ := os.Getwd() + return &SpecIndexConfig{ + BasePath: cw, + AllowRemoteLookup: true, + AllowFileLookup: true, + seenRemoteSources: &syncmap.Map{}, + } +} + +// CreateClosedAPIIndexConfig is a helper function to create a new SpecIndexConfig with the AllowRemoteLookup and +// AllowFileLookup set to false. This is the default behaviour of the index in versions 0.6.0+ +// +// The default BasePath is the current working directory. +func CreateClosedAPIIndexConfig() *SpecIndexConfig { + cw, _ := os.Getwd() + return &SpecIndexConfig{ + BasePath: cw, + AllowRemoteLookup: false, + AllowFileLookup: false, + seenRemoteSources: &syncmap.Map{}, + } +} + +// SpecIndex is a complete pre-computed index of the entire specification. Numbers are pre-calculated and +// quick direct access to paths, operations, tags are all available. No need to walk the entire node tree in rules, +// everything is pre-walked if you need it. +type SpecIndex struct { + allRefs map[string]*Reference // all (deduplicated) refs + rawSequencedRefs []*Reference // all raw references in sequence as they are scanned, not deduped. + linesWithRefs map[int]bool // lines that link to references. + allMappedRefs map[string]*Reference // these are the located mapped refs + allMappedRefsSequenced []*ReferenceMapped // sequenced mapped refs + refsByLine map[string]map[int]bool // every reference and the lines it's referenced from + pathRefs map[string]map[string]*Reference // all path references + paramOpRefs map[string]map[string]map[string][]*Reference // params in operations. + paramCompRefs map[string]*Reference // params in components + paramAllRefs map[string]*Reference // combined components and ops + paramInlineDuplicateNames map[string][]*Reference // inline params all with the same name + globalTagRefs map[string]*Reference // top level global tags + securitySchemeRefs map[string]*Reference // top level security schemes + requestBodiesRefs map[string]*Reference // top level request bodies + responsesRefs map[string]*Reference // top level responses + headersRefs map[string]*Reference // top level responses + examplesRefs map[string]*Reference // top level examples + securityRequirementRefs map[string]map[string][]*Reference // (NOT $ref) but a name based lookup for requirements + callbacksRefs map[string]map[string][]*Reference // all links + linksRefs map[string]map[string][]*Reference // all callbacks + operationTagsRefs map[string]map[string][]*Reference // tags found in operations + operationDescriptionRefs map[string]map[string]*Reference // descriptions in operations. + operationSummaryRefs map[string]map[string]*Reference // summaries in operations + callbackRefs map[string]*Reference // top level callback refs + serversRefs []*Reference // all top level server refs + rootServersNode *yaml.Node // servers root node + opServersRefs map[string]map[string][]*Reference // all operation level server overrides. + polymorphicRefs map[string]*Reference // every reference to a polymorphic ref + polymorphicAllOfRefs []*Reference // every reference to 'allOf' references + polymorphicOneOfRefs []*Reference // every reference to 'oneOf' references + polymorphicAnyOfRefs []*Reference // every reference to 'anyOf' references + externalDocumentsRef []*Reference // all external documents in spec + rootSecurity []*Reference // root security definitions. + rootSecurityNode *yaml.Node // root security node. + refsWithSiblings map[string]Reference // references with sibling elements next to them + pathRefsLock sync.Mutex // create lock for all refs maps, we want to build data as fast as we can + externalDocumentsCount int // number of externalDocument nodes found + operationTagsCount int // number of unique tags in operations + globalTagsCount int // number of global tags defined + totalTagsCount int // number unique tags in spec + securitySchemesCount int // security schemes + globalRequestBodiesCount int // component request bodies + globalResponsesCount int // component responses + globalHeadersCount int // component headers + globalExamplesCount int // component examples + globalLinksCount int // component links + globalCallbacksCount int // component callbacks + globalCallbacks int // component callbacks. + pathCount int // number of paths + operationCount int // number of operations + operationParamCount int // number of params defined in operations + componentParamCount int // number of params defined in components + componentsInlineParamUniqueCount int // number of inline params with unique names + componentsInlineParamDuplicateCount int // number of inline params with duplicate names + schemaCount int // number of schemas + refCount int // total ref count + root *yaml.Node // the root document + pathsNode *yaml.Node // paths node + tagsNode *yaml.Node // tags node + componentsNode *yaml.Node // components node + parametersNode *yaml.Node // components/parameters node + allParametersNode map[string]*Reference // all parameters node + allParameters map[string]*Reference // all parameters (components/defs) + schemasNode *yaml.Node // components/schemas node + allInlineSchemaDefinitions []*Reference // all schemas found in document outside of components (openapi) or definitions (swagger). + allInlineSchemaObjectDefinitions []*Reference // all schemas that are objects found in document outside of components (openapi) or definitions (swagger). + allComponentSchemaDefinitions map[string]*Reference // all schemas found in components (openapi) or definitions (swagger). + securitySchemesNode *yaml.Node // components/securitySchemes node + allSecuritySchemes map[string]*Reference // all security schemes / definitions. + requestBodiesNode *yaml.Node // components/requestBodies node + allRequestBodies map[string]*Reference // all request bodies + responsesNode *yaml.Node // components/responses node + allResponses map[string]*Reference // all responses + headersNode *yaml.Node // components/headers node + allHeaders map[string]*Reference // all headers + examplesNode *yaml.Node // components/examples node + allExamples map[string]*Reference // all components examples + linksNode *yaml.Node // components/links node + allLinks map[string]*Reference // all links + callbacksNode *yaml.Node // components/callbacks node + allCallbacks map[string]*Reference // all components examples + externalDocumentsNode *yaml.Node // external documents node + allExternalDocuments map[string]*Reference // all external documents + externalSpecIndex map[string]*SpecIndex // create a primary index of all external specs and componentIds + refErrors []error // errors when indexing references + operationParamErrors []error // errors when indexing parameters + allDescriptions []*DescriptionReference // every single description found in the spec. + allSummaries []*DescriptionReference // every single summary found in the spec. + allEnums []*EnumReference // every single enum found in the spec. + allObjectsWithProperties []*ObjectReference // every single object with properties found in the spec. + enumCount int + descriptionCount int + summaryCount int + seenRemoteSources map[string]*yaml.Node + seenLocalSources map[string]*yaml.Node + refLock sync.Mutex + sourceLock sync.Mutex + componentLock sync.RWMutex + externalLock sync.RWMutex + errorLock sync.RWMutex + circularReferences []*CircularReferenceResult // only available when the resolver has been used. + allowCircularReferences bool // decide if you want to error out, or allow circular references, default is false. + relativePath string // relative path of the spec file. + config *SpecIndexConfig // configuration for the index + httpClient *http.Client + componentIndexChan chan bool + polyComponentIndexChan chan bool + + // when things get complex (looking at you digital ocean) then we need to know + // what we have seen across indexes, so we need to be able to travel back up to the root + // cto avoid re-downloading sources. + parentIndex *SpecIndex + uri []string + children []*SpecIndex +} + +func (index *SpecIndex) AddChild(child *SpecIndex) { + index.children = append(index.children, child) +} + +// GetChildren returns the children of this index. +func (index *SpecIndex) GetChildren() []*SpecIndex { + return index.children +} + +// ExternalLookupFunction is for lookup functions that take a JSONSchema reference and tries to find that node in the +// URI based document. Decides if the reference is local, remote or in a file. +type ExternalLookupFunction func(id string) (foundNode *yaml.Node, rootNode *yaml.Node, lookupError error) + +// IndexingError holds data about something that went wrong during indexing. +type IndexingError struct { + Err error + Node *yaml.Node + Path string +} + +func (i *IndexingError) Error() string { + return i.Err.Error() +} + +// DescriptionReference holds data about a description that was found and where it was found. +type DescriptionReference struct { + Content string + Path string + Node *yaml.Node + IsSummary bool +} + +type EnumReference struct { + Node *yaml.Node + Type *yaml.Node + Path string + SchemaNode *yaml.Node + ParentNode *yaml.Node +} + +type ObjectReference struct { + Node *yaml.Node + Path string + ParentNode *yaml.Node +} + +var methodTypes = []string{"get", "post", "put", "patch", "options", "head", "delete"} diff --git a/vendor/github.com/pb33f/libopenapi/index/index_utils.go b/vendor/github.com/pb33f/libopenapi/index/index_utils.go new file mode 100644 index 0000000000..a1c0fd00d5 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/index/index_utils.go @@ -0,0 +1,91 @@ +// Copyright 2023 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package index + +import ( + "gopkg.in/yaml.v3" + "net/http" + "strings" + "time" +) + +func isHttpMethod(val string) bool { + switch strings.ToLower(val) { + case methodTypes[0]: + return true + case methodTypes[1]: + return true + case methodTypes[2]: + return true + case methodTypes[3]: + return true + case methodTypes[4]: + return true + case methodTypes[5]: + return true + case methodTypes[6]: + return true + } + return false +} + +func DetermineReferenceResolveType(ref string) int { + if ref != "" && ref[0] == '#' { + return LocalResolve + } + if ref != "" && len(ref) >= 5 && (ref[:5] == "https" || ref[:5] == "http:") { + return HttpResolve + } + if strings.Contains(ref, ".json") || + strings.Contains(ref, ".yaml") || + strings.Contains(ref, ".yml") { + return FileResolve + } + return -1 +} + +func boostrapIndexCollections(rootNode *yaml.Node, index *SpecIndex) { + index.root = rootNode + index.allRefs = make(map[string]*Reference) + index.allMappedRefs = make(map[string]*Reference) + index.refsByLine = make(map[string]map[int]bool) + index.linesWithRefs = make(map[int]bool) + index.pathRefs = make(map[string]map[string]*Reference) + index.paramOpRefs = make(map[string]map[string]map[string][]*Reference) + index.operationTagsRefs = make(map[string]map[string][]*Reference) + index.operationDescriptionRefs = make(map[string]map[string]*Reference) + index.operationSummaryRefs = make(map[string]map[string]*Reference) + index.paramCompRefs = make(map[string]*Reference) + index.paramAllRefs = make(map[string]*Reference) + index.paramInlineDuplicateNames = make(map[string][]*Reference) + index.globalTagRefs = make(map[string]*Reference) + index.securitySchemeRefs = make(map[string]*Reference) + index.requestBodiesRefs = make(map[string]*Reference) + index.responsesRefs = make(map[string]*Reference) + index.headersRefs = make(map[string]*Reference) + index.examplesRefs = make(map[string]*Reference) + index.callbacksRefs = make(map[string]map[string][]*Reference) + index.linksRefs = make(map[string]map[string][]*Reference) + index.callbackRefs = make(map[string]*Reference) + index.externalSpecIndex = make(map[string]*SpecIndex) + index.allComponentSchemaDefinitions = make(map[string]*Reference) + index.allParameters = make(map[string]*Reference) + index.allSecuritySchemes = make(map[string]*Reference) + index.allRequestBodies = make(map[string]*Reference) + index.allResponses = make(map[string]*Reference) + index.allHeaders = make(map[string]*Reference) + index.allExamples = make(map[string]*Reference) + index.allLinks = make(map[string]*Reference) + index.allCallbacks = make(map[string]*Reference) + index.allExternalDocuments = make(map[string]*Reference) + index.securityRequirementRefs = make(map[string]map[string][]*Reference) + index.polymorphicRefs = make(map[string]*Reference) + index.refsWithSiblings = make(map[string]Reference) + index.seenRemoteSources = make(map[string]*yaml.Node) + index.seenLocalSources = make(map[string]*yaml.Node) + index.opServersRefs = make(map[string]map[string][]*Reference) + index.httpClient = &http.Client{Timeout: time.Duration(5) * time.Second} + index.componentIndexChan = make(chan bool) + index.polyComponentIndexChan = make(chan bool) +} diff --git a/vendor/github.com/pb33f/libopenapi/index/search_index.go b/vendor/github.com/pb33f/libopenapi/index/search_index.go new file mode 100644 index 0000000000..0c8f69880a --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/index/search_index.go @@ -0,0 +1,34 @@ +// Copyright 2023 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package index + +// SearchIndexForReference searches the index for a reference, first looking through the mapped references +// and then externalSpecIndex for a match. If no match is found, it will recursively search the child indexes +// extracted when parsing the OpenAPI Spec. +func (index *SpecIndex) SearchIndexForReference(ref string) []*Reference { + if r, ok := index.allMappedRefs[ref]; ok { + return []*Reference{r} + } + for c := range index.children { + found := goFindMeSomething(index.children[c], ref) + if found != nil { + return found + } + } + return nil +} + +func (index *SpecIndex) SearchAncestryForSeenURI(uri string) *SpecIndex { + if index.parentIndex == nil { + return nil + } + if index.uri[0] != uri { + return index.parentIndex.SearchAncestryForSeenURI(uri) + } + return index +} + +func goFindMeSomething(i *SpecIndex, ref string) []*Reference { + return i.SearchIndexForReference(ref) +} diff --git a/vendor/github.com/pb33f/libopenapi/index/spec_index.go b/vendor/github.com/pb33f/libopenapi/index/spec_index.go new file mode 100644 index 0000000000..4e401ab539 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/index/spec_index.go @@ -0,0 +1,1173 @@ +// Copyright 2022-2033 Dave Shanley / Quobix +// SPDX-License-Identifier: MIT + +// Package index contains an OpenAPI indexer that will very quickly scan through an OpenAPI specification (all versions) +// and extract references to all the important nodes you might want to look up, as well as counts on total objects. +// +// When extracting references, the index can determine if the reference is local to the file (recommended) or the +// reference is located in another local file, or a remote file. The index will then attempt to load in those remote +// files and look up the references there, or continue following the chain. +// +// When the index loads in a local or remote file, it will also index that remote spec as well. This means everything +// is indexed and stored as a tree, depending on how deep the remote references go. +package index + +import ( + "fmt" + "github.com/pb33f/libopenapi/utils" + "github.com/vmware-labs/yaml-jsonpath/pkg/yamlpath" + "golang.org/x/sync/syncmap" + "gopkg.in/yaml.v3" + "strings" + "sync" +) + +// NewSpecIndexWithConfig will create a new index of an OpenAPI or Swagger spec. It uses the same logic as NewSpecIndex +// except it sets a base URL for resolving relative references, except it also allows for granular control over +// how the index is set up. +func NewSpecIndexWithConfig(rootNode *yaml.Node, config *SpecIndexConfig) *SpecIndex { + index := new(SpecIndex) + if config != nil && config.seenRemoteSources == nil { + config.seenRemoteSources = &syncmap.Map{} + } + config.remoteLock = &sync.Mutex{} + index.config = config + index.parentIndex = config.ParentIndex + index.uri = config.uri + if rootNode == nil || len(rootNode.Content) <= 0 { + return index + } + boostrapIndexCollections(rootNode, index) + return createNewIndex(rootNode, index) +} + +// NewSpecIndex will create a new index of an OpenAPI or Swagger spec. It's not resolved or converted into anything +// other than a raw index of every node for every content type in the specification. This process runs as fast as +// possible so dependencies looking through the tree, don't need to walk the entire thing over, and over. +// +// Deprecated: Use NewSpecIndexWithConfig instead, this function will be removed in the future because it +// defaults to allowing remote references and file references. This is a potential security risk and should be controlled by +// providing a SpecIndexConfig that explicitly sets the AllowRemoteLookup and AllowFileLookup to true. +// This function also does not support specifications with relative references that may not exist locally. +// - https://github.com/pb33f/libopenapi/issues/73 +func NewSpecIndex(rootNode *yaml.Node) *SpecIndex { + index := new(SpecIndex) + index.config = CreateOpenAPIIndexConfig() + boostrapIndexCollections(rootNode, index) + return createNewIndex(rootNode, index) +} + +func createNewIndex(rootNode *yaml.Node, index *SpecIndex) *SpecIndex { + // there is no node! return an empty index. + if rootNode == nil { + return index + } + + // boot index. + results := index.ExtractRefs(index.root.Content[0], index.root, []string{}, 0, false, "") + + // map poly refs + poly := make([]*Reference, len(index.polymorphicRefs)) + z := 0 + for i := range index.polymorphicRefs { + poly[z] = index.polymorphicRefs[i] + z++ + } + + // pull out references + index.ExtractComponentsFromRefs(results) + index.ExtractComponentsFromRefs(poly) + + index.ExtractExternalDocuments(index.root) + index.GetPathCount() + + countFuncs := []func() int{ + index.GetOperationCount, + index.GetComponentSchemaCount, + index.GetGlobalTagsCount, + index.GetComponentParameterCount, + index.GetOperationsParameterCount, + } + + var wg sync.WaitGroup + wg.Add(len(countFuncs)) + runIndexFunction(countFuncs, &wg) // run as fast as we can. + wg.Wait() + + // these functions are aggregate and can only run once the rest of the datamodel is ready + countFuncs = []func() int{ + index.GetInlineUniqueParamCount, + index.GetOperationTagsCount, + index.GetGlobalLinksCount, + index.GetGlobalCallbacksCount, + } + + wg.Add(len(countFuncs)) + runIndexFunction(countFuncs, &wg) // run as fast as we can. + wg.Wait() + + // these have final calculation dependencies + index.GetInlineDuplicateParamCount() + index.GetAllDescriptionsCount() + index.GetTotalTagsCount() + + // do a copy! + index.config.seenRemoteSources.Range(func(k, v any) bool { + index.seenRemoteSources[k.(string)] = v.(*yaml.Node) + return true + }) + return index +} + +// GetRootNode returns document root node. +func (index *SpecIndex) GetRootNode() *yaml.Node { + return index.root +} + +// GetGlobalTagsNode returns document root tags node. +func (index *SpecIndex) GetGlobalTagsNode() *yaml.Node { + return index.tagsNode +} + +// SetCircularReferences is a convenience method for the resolver to pass in circular references +// if the resolver is used. +func (index *SpecIndex) SetCircularReferences(refs []*CircularReferenceResult) { + index.circularReferences = refs +} + +// GetCircularReferences will return any circular reference results that were found by the resolver. +func (index *SpecIndex) GetCircularReferences() []*CircularReferenceResult { + return index.circularReferences +} + +// GetPathsNode returns document root node. +func (index *SpecIndex) GetPathsNode() *yaml.Node { + return index.pathsNode +} + +// GetDiscoveredReferences will return all unique references found in the spec +func (index *SpecIndex) GetDiscoveredReferences() map[string]*Reference { + return index.allRefs +} + +// GetPolyReferences will return every polymorphic reference in the doc +func (index *SpecIndex) GetPolyReferences() map[string]*Reference { + return index.polymorphicRefs +} + +// GetPolyAllOfReferences will return every 'allOf' polymorphic reference in the doc +func (index *SpecIndex) GetPolyAllOfReferences() []*Reference { + return index.polymorphicAllOfRefs +} + +// GetPolyAnyOfReferences will return every 'anyOf' polymorphic reference in the doc +func (index *SpecIndex) GetPolyAnyOfReferences() []*Reference { + return index.polymorphicAnyOfRefs +} + +// GetPolyOneOfReferences will return every 'allOf' polymorphic reference in the doc +func (index *SpecIndex) GetPolyOneOfReferences() []*Reference { + return index.polymorphicOneOfRefs +} + +// GetAllCombinedReferences will return the number of unique and polymorphic references discovered. +func (index *SpecIndex) GetAllCombinedReferences() map[string]*Reference { + combined := make(map[string]*Reference) + for k, ref := range index.allRefs { + combined[k] = ref + } + for k, ref := range index.polymorphicRefs { + combined[k] = ref + } + return combined +} + +// GetRefsByLine will return all references and the lines at which they were found. +func (index *SpecIndex) GetRefsByLine() map[string]map[int]bool { + return index.refsByLine +} + +// GetLinesWithReferences will return a map of lines that have a $ref +func (index *SpecIndex) GetLinesWithReferences() map[int]bool { + return index.linesWithRefs +} + +// GetMappedReferences will return all references that were mapped successfully to actual property nodes. +// this collection is completely unsorted, traversing it may produce random results when resolving it and +// encountering circular references can change results depending on where in the collection the resolver started +// its journey through the index. +func (index *SpecIndex) GetMappedReferences() map[string]*Reference { + return index.allMappedRefs +} + +// GetMappedReferencesSequenced will return all references that were mapped successfully to nodes, performed in sequence +// as they were read in from the document. +func (index *SpecIndex) GetMappedReferencesSequenced() []*ReferenceMapped { + return index.allMappedRefsSequenced +} + +// GetOperationParameterReferences will return all references to operation parameters +func (index *SpecIndex) GetOperationParameterReferences() map[string]map[string]map[string][]*Reference { + return index.paramOpRefs +} + +// GetAllSchemas will return references to all schemas found in the document both inline and those under components +// The first elements of at the top of the slice, are all the inline references (using GetAllInlineSchemas), +// and then following on are all the references extracted from the components section (using GetAllComponentSchemas). +func (index *SpecIndex) GetAllSchemas() []*Reference { + + componentSchemas := index.GetAllComponentSchemas() + inlineSchemas := index.GetAllInlineSchemas() + + combined := make([]*Reference, len(inlineSchemas)+len(componentSchemas)) + i := 0 + for x := range inlineSchemas { + combined[i] = inlineSchemas[x] + i++ + } + for x := range componentSchemas { + combined[i] = componentSchemas[x] + i++ + } + return combined +} + +// GetAllInlineSchemaObjects will return all schemas that are inline (not inside components) and that are also typed +// as 'object' or 'array' (not primitives). +func (index *SpecIndex) GetAllInlineSchemaObjects() []*Reference { + return index.allInlineSchemaObjectDefinitions +} + +// GetAllInlineSchemas will return all schemas defined in the components section of the document. +func (index *SpecIndex) GetAllInlineSchemas() []*Reference { + return index.allInlineSchemaDefinitions +} + +// GetAllComponentSchemas will return all schemas defined in the components section of the document. +func (index *SpecIndex) GetAllComponentSchemas() map[string]*Reference { + return index.allComponentSchemaDefinitions +} + +// GetAllSecuritySchemes will return all security schemes / definitions found in the document. +func (index *SpecIndex) GetAllSecuritySchemes() map[string]*Reference { + return index.allSecuritySchemes +} + +// GetAllHeaders will return all headers found in the document (under components) +func (index *SpecIndex) GetAllHeaders() map[string]*Reference { + return index.allHeaders +} + +// GetAllExternalDocuments will return all external documents found +func (index *SpecIndex) GetAllExternalDocuments() map[string]*Reference { + return index.allExternalDocuments +} + +// GetAllExamples will return all examples found in the document (under components) +func (index *SpecIndex) GetAllExamples() map[string]*Reference { + return index.allExamples +} + +// GetAllDescriptions will return all descriptions found in the document +func (index *SpecIndex) GetAllDescriptions() []*DescriptionReference { + return index.allDescriptions +} + +// GetAllEnums will return all enums found in the document +func (index *SpecIndex) GetAllEnums() []*EnumReference { + return index.allEnums +} + +// GetAllObjectsWithProperties will return all objects with properties found in the document +func (index *SpecIndex) GetAllObjectsWithProperties() []*ObjectReference { + return index.allObjectsWithProperties +} + +// GetAllSummaries will return all summaries found in the document +func (index *SpecIndex) GetAllSummaries() []*DescriptionReference { + return index.allSummaries +} + +// GetAllRequestBodies will return all requestBodies found in the document (under components) +func (index *SpecIndex) GetAllRequestBodies() map[string]*Reference { + return index.allRequestBodies +} + +// GetAllLinks will return all links found in the document (under components) +func (index *SpecIndex) GetAllLinks() map[string]*Reference { + return index.allLinks +} + +// GetAllParameters will return all parameters found in the document (under components) +func (index *SpecIndex) GetAllParameters() map[string]*Reference { + return index.allParameters +} + +// GetAllResponses will return all responses found in the document (under components) +func (index *SpecIndex) GetAllResponses() map[string]*Reference { + return index.allResponses +} + +// GetAllCallbacks will return all links found in the document (under components) +func (index *SpecIndex) GetAllCallbacks() map[string]*Reference { + return index.allCallbacks +} + +// GetInlineOperationDuplicateParameters will return a map of duplicates located in operation parameters. +func (index *SpecIndex) GetInlineOperationDuplicateParameters() map[string][]*Reference { + return index.paramInlineDuplicateNames +} + +// GetReferencesWithSiblings will return a map of all the references with sibling nodes (illegal) +func (index *SpecIndex) GetReferencesWithSiblings() map[string]Reference { + return index.refsWithSiblings +} + +// GetAllReferences will return every reference found in the spec, after being de-duplicated. +func (index *SpecIndex) GetAllReferences() map[string]*Reference { + return index.allRefs +} + +// GetAllSequencedReferences will return every reference (in sequence) that was found (non-polymorphic) +func (index *SpecIndex) GetAllSequencedReferences() []*Reference { + return index.rawSequencedRefs +} + +// GetSchemasNode will return the schema's node found in the spec +func (index *SpecIndex) GetSchemasNode() *yaml.Node { + return index.schemasNode +} + +// GetParametersNode will return the schema's node found in the spec +func (index *SpecIndex) GetParametersNode() *yaml.Node { + return index.parametersNode +} + +// GetReferenceIndexErrors will return any errors that occurred when indexing references +func (index *SpecIndex) GetReferenceIndexErrors() []error { + return index.refErrors +} + +// GetOperationParametersIndexErrors any errors that occurred when indexing operation parameters +func (index *SpecIndex) GetOperationParametersIndexErrors() []error { + return index.operationParamErrors +} + +// GetAllPaths will return all paths indexed in the document +func (index *SpecIndex) GetAllPaths() map[string]map[string]*Reference { + return index.pathRefs +} + +// GetOperationTags will return all references to all tags found in operations. +func (index *SpecIndex) GetOperationTags() map[string]map[string][]*Reference { + return index.operationTagsRefs +} + +// GetAllParametersFromOperations will return all paths indexed in the document +func (index *SpecIndex) GetAllParametersFromOperations() map[string]map[string]map[string][]*Reference { + return index.paramOpRefs +} + +// GetRootSecurityReferences will return all root security settings +func (index *SpecIndex) GetRootSecurityReferences() []*Reference { + return index.rootSecurity +} + +// GetSecurityRequirementReferences will return all security requirement definitions found in the document +func (index *SpecIndex) GetSecurityRequirementReferences() map[string]map[string][]*Reference { + return index.securityRequirementRefs +} + +// GetRootSecurityNode will return the root security node +func (index *SpecIndex) GetRootSecurityNode() *yaml.Node { + return index.rootSecurityNode +} + +// GetRootServersNode will return the root servers node +func (index *SpecIndex) GetRootServersNode() *yaml.Node { + return index.rootServersNode +} + +// GetAllRootServers will return all root servers defined +func (index *SpecIndex) GetAllRootServers() []*Reference { + return index.serversRefs +} + +// GetAllOperationsServers will return all operation overrides for servers. +func (index *SpecIndex) GetAllOperationsServers() map[string]map[string][]*Reference { + return index.opServersRefs +} + +// GetAllExternalIndexes will return all indexes for external documents +func (index *SpecIndex) GetAllExternalIndexes() map[string]*SpecIndex { + return index.externalSpecIndex +} + +// SetAllowCircularReferenceResolving will flip a bit that can be used by any consumers to determine if they want +// to allow or disallow circular references to be resolved or visited +func (index *SpecIndex) SetAllowCircularReferenceResolving(allow bool) { + index.allowCircularReferences = allow +} + +// AllowCircularReferenceResolving will return a bit that allows developers to determine what to do with circular refs. +func (index *SpecIndex) AllowCircularReferenceResolving() bool { + return index.allowCircularReferences +} + +func (index *SpecIndex) checkPolymorphicNode(name string) (bool, string) { + switch name { + case "anyOf": + return true, "anyOf" + case "allOf": + return true, "allOf" + case "oneOf": + return true, "oneOf" + } + return false, "" +} + +// GetPathCount will return the number of paths found in the spec +func (index *SpecIndex) GetPathCount() int { + if index.root == nil { + return -1 + } + + if index.pathCount > 0 { + return index.pathCount + } + pc := 0 + for i, n := range index.root.Content[0].Content { + if i%2 == 0 { + if n.Value == "paths" { + pn := index.root.Content[0].Content[i+1].Content + index.pathsNode = index.root.Content[0].Content[i+1] + pc = len(pn) / 2 + } + } + } + index.pathCount = pc + return pc +} + +// ExtractExternalDocuments will extract the number of externalDocs nodes found in the document. +func (index *SpecIndex) ExtractExternalDocuments(node *yaml.Node) []*Reference { + if node == nil { + return nil + } + var found []*Reference + if len(node.Content) > 0 { + for i, n := range node.Content { + if utils.IsNodeMap(n) || utils.IsNodeArray(n) { + found = append(found, index.ExtractExternalDocuments(n)...) + } + + if i%2 == 0 && n.Value == "externalDocs" { + docNode := node.Content[i+1] + _, urlNode := utils.FindKeyNode("url", docNode.Content) + if urlNode != nil { + ref := &Reference{ + Definition: urlNode.Value, + Name: urlNode.Value, + Node: docNode, + } + index.externalDocumentsRef = append(index.externalDocumentsRef, ref) + } + } + } + } + index.externalDocumentsCount = len(index.externalDocumentsRef) + return found +} + +// GetGlobalTagsCount will return the number of tags found in the top level 'tags' node of the document. +func (index *SpecIndex) GetGlobalTagsCount() int { + if index.root == nil { + return -1 + } + + if index.globalTagsCount > 0 { + return index.globalTagsCount + } + + for i, n := range index.root.Content[0].Content { + if i%2 == 0 { + if n.Value == "tags" { + tagsNode := index.root.Content[0].Content[i+1] + if tagsNode != nil { + index.tagsNode = tagsNode + index.globalTagsCount = len(tagsNode.Content) // tags is an array, don't divide by 2. + for x, tagNode := range index.tagsNode.Content { + + _, name := utils.FindKeyNode("name", tagNode.Content) + _, description := utils.FindKeyNode("description", tagNode.Content) + + var desc string + if description == nil { + desc = "" + } + if name != nil { + ref := &Reference{ + Definition: desc, + Name: name.Value, + Node: tagNode, + Path: fmt.Sprintf("$.tags[%d]", x), + } + index.globalTagRefs[name.Value] = ref + } + } + } + } + } + } + return index.globalTagsCount +} + +// GetOperationTagsCount will return the number of operation tags found (tags referenced in operations) +func (index *SpecIndex) GetOperationTagsCount() int { + if index.root == nil { + return -1 + } + + if index.operationTagsCount > 0 { + return index.operationTagsCount + } + + // this is an aggregate count function that can only be run after operations + // have been calculated. + seen := make(map[string]bool) + count := 0 + for _, path := range index.operationTagsRefs { + for _, method := range path { + for _, tag := range method { + if !seen[tag.Name] { + seen[tag.Name] = true + count++ + } + } + } + } + index.operationTagsCount = count + return index.operationTagsCount +} + +// GetTotalTagsCount will return the number of global and operation tags found that are unique. +func (index *SpecIndex) GetTotalTagsCount() int { + if index.root == nil { + return -1 + } + if index.totalTagsCount > 0 { + return index.totalTagsCount + } + + seen := make(map[string]bool) + count := 0 + + for _, gt := range index.globalTagRefs { + // TODO: do we still need this? + if !seen[gt.Name] { + seen[gt.Name] = true + count++ + } + } + for _, ot := range index.operationTagsRefs { + for _, m := range ot { + for _, t := range m { + if !seen[t.Name] { + seen[t.Name] = true + count++ + } + } + } + } + index.totalTagsCount = count + return index.totalTagsCount +} + +// GetGlobalCallbacksCount for each response of each operation method, multiple callbacks can be defined +func (index *SpecIndex) GetGlobalCallbacksCount() int { + if index.root == nil { + return -1 + } + + if index.globalCallbacksCount > 0 { + return index.globalCallbacksCount + } + + // index.pathRefsLock.Lock() + for path, p := range index.pathRefs { + for _, m := range p { + + // look through method for callbacks + callbacks, _ := yamlpath.NewPath("$..callbacks") + res, _ := callbacks.Find(m.Node) + + if len(res) > 0 { + for _, callback := range res[0].Content { + if utils.IsNodeMap(callback) { + + ref := &Reference{ + Definition: m.Name, + Name: m.Name, + Node: callback, + } + + if index.callbacksRefs[path] == nil { + index.callbacksRefs[path] = make(map[string][]*Reference) + } + if len(index.callbacksRefs[path][m.Name]) > 0 { + index.callbacksRefs[path][m.Name] = append(index.callbacksRefs[path][m.Name], ref) + } else { + index.callbacksRefs[path][m.Name] = []*Reference{ref} + } + index.globalCallbacksCount++ + } + } + } + } + } + // index.pathRefsLock.Unlock() + return index.globalCallbacksCount +} + +// GetGlobalLinksCount for each response of each operation method, multiple callbacks can be defined +func (index *SpecIndex) GetGlobalLinksCount() int { + if index.root == nil { + return -1 + } + + if index.globalLinksCount > 0 { + return index.globalLinksCount + } + + // index.pathRefsLock.Lock() + for path, p := range index.pathRefs { + for _, m := range p { + + // look through method for links + links, _ := yamlpath.NewPath("$..links") + res, _ := links.Find(m.Node) + + if len(res) > 0 { + for _, link := range res[0].Content { + if utils.IsNodeMap(link) { + + ref := &Reference{ + Definition: m.Name, + Name: m.Name, + Node: link, + } + if index.linksRefs[path] == nil { + index.linksRefs[path] = make(map[string][]*Reference) + } + if len(index.linksRefs[path][m.Name]) > 0 { + index.linksRefs[path][m.Name] = append(index.linksRefs[path][m.Name], ref) + } + index.linksRefs[path][m.Name] = []*Reference{ref} + index.globalLinksCount++ + } + } + } + } + } + // index.pathRefsLock.Unlock() + return index.globalLinksCount +} + +// GetRawReferenceCount will return the number of raw references located in the document. +func (index *SpecIndex) GetRawReferenceCount() int { + return len(index.rawSequencedRefs) +} + +// GetComponentSchemaCount will return the number of schemas located in the 'components' or 'definitions' node. +func (index *SpecIndex) GetComponentSchemaCount() int { + if index.root == nil { + return -1 + } + + if index.schemaCount > 0 { + return index.schemaCount + } + + for i, n := range index.root.Content[0].Content { + if i%2 == 0 { + + // servers + if n.Value == "servers" { + index.rootServersNode = index.root.Content[0].Content[i+1] + if i+1 < len(index.root.Content[0].Content) { + serverDefinitions := index.root.Content[0].Content[i+1] + for x, def := range serverDefinitions.Content { + ref := &Reference{ + Definition: "servers", + Name: "server", + Node: def, + Path: fmt.Sprintf("$.servers[%d]", x), + ParentNode: index.rootServersNode, + } + index.serversRefs = append(index.serversRefs, ref) + } + } + } + + // root security definitions + if n.Value == "security" { + index.rootSecurityNode = index.root.Content[0].Content[i+1] + if i+1 < len(index.root.Content[0].Content) { + securityDefinitions := index.root.Content[0].Content[i+1] + for x, def := range securityDefinitions.Content { + if len(def.Content) > 0 { + name := def.Content[0] + ref := &Reference{ + Definition: name.Value, + Name: name.Value, + Node: def, + Path: fmt.Sprintf("$.security[%d]", x), + } + index.rootSecurity = append(index.rootSecurity, ref) + } + } + } + } + + if n.Value == "components" { + _, schemasNode := utils.FindKeyNode("schemas", index.root.Content[0].Content[i+1].Content) + + // while we are here, go ahead and extract everything in components. + _, parametersNode := utils.FindKeyNode("parameters", index.root.Content[0].Content[i+1].Content) + _, requestBodiesNode := utils.FindKeyNode("requestBodies", index.root.Content[0].Content[i+1].Content) + _, responsesNode := utils.FindKeyNode("responses", index.root.Content[0].Content[i+1].Content) + _, securitySchemesNode := utils.FindKeyNode("securitySchemes", index.root.Content[0].Content[i+1].Content) + _, headersNode := utils.FindKeyNode("headers", index.root.Content[0].Content[i+1].Content) + _, examplesNode := utils.FindKeyNode("examples", index.root.Content[0].Content[i+1].Content) + _, linksNode := utils.FindKeyNode("links", index.root.Content[0].Content[i+1].Content) + _, callbacksNode := utils.FindKeyNode("callbacks", index.root.Content[0].Content[i+1].Content) + + // extract schemas + if schemasNode != nil { + index.extractDefinitionsAndSchemas(schemasNode, "#/components/schemas/") + index.schemasNode = schemasNode + index.schemaCount = len(schemasNode.Content) / 2 + } + + // extract parameters + if parametersNode != nil { + index.extractComponentParameters(parametersNode, "#/components/parameters/") + index.componentLock.Lock() + index.parametersNode = parametersNode + index.componentLock.Unlock() + } + + // extract requestBodies + if requestBodiesNode != nil { + index.extractComponentRequestBodies(requestBodiesNode, "#/components/requestBodies/") + index.requestBodiesNode = requestBodiesNode + } + + // extract responses + if responsesNode != nil { + index.extractComponentResponses(responsesNode, "#/components/responses/") + index.responsesNode = responsesNode + } + + // extract security schemes + if securitySchemesNode != nil { + index.extractComponentSecuritySchemes(securitySchemesNode, "#/components/securitySchemes/") + index.securitySchemesNode = securitySchemesNode + } + + // extract headers + if headersNode != nil { + index.extractComponentHeaders(headersNode, "#/components/headers/") + index.headersNode = headersNode + } + + // extract examples + if examplesNode != nil { + index.extractComponentExamples(examplesNode, "#/components/examples/") + index.examplesNode = examplesNode + } + + // extract links + if linksNode != nil { + index.extractComponentLinks(linksNode, "#/components/links/") + index.linksNode = linksNode + } + + // extract callbacks + if callbacksNode != nil { + index.extractComponentCallbacks(callbacksNode, "#/components/callbacks/") + index.callbacksNode = callbacksNode + } + + } + + // swagger + if n.Value == "definitions" { + schemasNode := index.root.Content[0].Content[i+1] + if schemasNode != nil { + + // extract schemas + index.extractDefinitionsAndSchemas(schemasNode, "#/definitions/") + index.schemasNode = schemasNode + index.schemaCount = len(schemasNode.Content) / 2 + } + } + + // swagger + if n.Value == "parameters" { + parametersNode := index.root.Content[0].Content[i+1] + if parametersNode != nil { + // extract params + index.extractComponentParameters(parametersNode, "#/parameters/") + index.componentLock.Lock() + index.parametersNode = parametersNode + index.componentLock.Unlock() + } + } + + if n.Value == "responses" { + responsesNode := index.root.Content[0].Content[i+1] + if responsesNode != nil { + + // extract responses + index.extractComponentResponses(responsesNode, "#/responses/") + index.responsesNode = responsesNode + } + } + + if n.Value == "securityDefinitions" { + securityDefinitionsNode := index.root.Content[0].Content[i+1] + if securityDefinitionsNode != nil { + + // extract security definitions. + index.extractComponentSecuritySchemes(securityDefinitionsNode, "#/securityDefinitions/") + index.securitySchemesNode = securityDefinitionsNode + } + } + + } + } + return index.schemaCount +} + +// GetComponentParameterCount returns the number of parameter components defined +func (index *SpecIndex) GetComponentParameterCount() int { + if index.root == nil { + return -1 + } + + if index.componentParamCount > 0 { + return index.componentParamCount + } + + for i, n := range index.root.Content[0].Content { + if i%2 == 0 { + // openapi 3 + if n.Value == "components" { + _, parametersNode := utils.FindKeyNode("parameters", index.root.Content[0].Content[i+1].Content) + if parametersNode != nil { + index.componentLock.Lock() + index.parametersNode = parametersNode + index.componentParamCount = len(parametersNode.Content) / 2 + index.componentLock.Unlock() + } + } + // openapi 2 + if n.Value == "parameters" { + parametersNode := index.root.Content[0].Content[i+1] + if parametersNode != nil { + index.componentLock.Lock() + index.parametersNode = parametersNode + index.componentParamCount = len(parametersNode.Content) / 2 + index.componentLock.Unlock() + } + } + } + } + return index.componentParamCount +} + +// GetOperationCount returns the number of operations (for all paths) located in the document +func (index *SpecIndex) GetOperationCount() int { + if index.root == nil { + return -1 + } + + if index.pathsNode == nil { + return -1 + } + + if index.operationCount > 0 { + return index.operationCount + } + + opCount := 0 + + for x, p := range index.pathsNode.Content { + if x%2 == 0 { + + var method *yaml.Node + if utils.IsNodeArray(index.pathsNode) { + method = index.pathsNode.Content[x] + } else { + method = index.pathsNode.Content[x+1] + } + + // extract methods for later use. + for y, m := range method.Content { + if y%2 == 0 { + + // check node is a valid method + valid := false + for _, methodType := range methodTypes { + if m.Value == methodType { + valid = true + } + } + if valid { + ref := &Reference{ + Definition: m.Value, + Name: m.Value, + Node: method.Content[y+1], + } + index.pathRefsLock.Lock() + if index.pathRefs[p.Value] == nil { + index.pathRefs[p.Value] = make(map[string]*Reference) + } + index.pathRefs[p.Value][ref.Name] = ref + index.pathRefsLock.Unlock() + // update + opCount++ + } + } + } + } + } + + index.operationCount = opCount + return opCount +} + +// GetOperationsParameterCount returns the number of parameters defined in paths and operations. +// this method looks in top level (path level) and inside each operation (get, post etc.). Parameters can +// be hiding within multiple places. +func (index *SpecIndex) GetOperationsParameterCount() int { + if index.root == nil { + return -1 + } + + if index.pathsNode == nil { + return -1 + } + + if index.operationParamCount > 0 { + return index.operationParamCount + } + + // parameters are sneaky, they can be in paths, in path operations or in components. + // sometimes they are refs, sometimes they are inline definitions, just for fun. + // some authors just LOVE to mix and match them all up. + // check paths first + for x, pathItemNode := range index.pathsNode.Content { + if x%2 == 0 { + + var pathPropertyNode *yaml.Node + if utils.IsNodeArray(index.pathsNode) { + pathPropertyNode = index.pathsNode.Content[x] + } else { + pathPropertyNode = index.pathsNode.Content[x+1] + } + + // extract methods for later use. + for y, prop := range pathPropertyNode.Content { + if y%2 == 0 { + + // while we're here, lets extract any top level servers + if prop.Value == "servers" { + serversNode := pathPropertyNode.Content[y+1] + if index.opServersRefs[pathItemNode.Value] == nil { + index.opServersRefs[pathItemNode.Value] = make(map[string][]*Reference) + } + var serverRefs []*Reference + for i, serverRef := range serversNode.Content { + ref := &Reference{ + Definition: serverRef.Value, + Name: serverRef.Value, + Node: serverRef, + ParentNode: prop, + Path: fmt.Sprintf("$.paths.%s.servers[%d]", pathItemNode.Value, i), + } + serverRefs = append(serverRefs, ref) + } + index.opServersRefs[pathItemNode.Value]["top"] = serverRefs + } + + // top level params + if prop.Value == "parameters" { + + // let's look at params, check if they are refs or inline. + params := pathPropertyNode.Content[y+1].Content + index.scanOperationParams(params, pathItemNode, "top") + } + + // method level params. + if isHttpMethod(prop.Value) { + for z, httpMethodProp := range pathPropertyNode.Content[y+1].Content { + if z%2 == 0 { + if httpMethodProp.Value == "parameters" { + params := pathPropertyNode.Content[y+1].Content[z+1].Content + index.scanOperationParams(params, pathItemNode, prop.Value) + } + + // extract operation tags if set. + if httpMethodProp.Value == "tags" { + tags := pathPropertyNode.Content[y+1].Content[z+1] + + if index.operationTagsRefs[pathItemNode.Value] == nil { + index.operationTagsRefs[pathItemNode.Value] = make(map[string][]*Reference) + } + + var tagRefs []*Reference + for _, tagRef := range tags.Content { + ref := &Reference{ + Definition: tagRef.Value, + Name: tagRef.Value, + Node: tagRef, + } + tagRefs = append(tagRefs, ref) + } + index.operationTagsRefs[pathItemNode.Value][prop.Value] = tagRefs + } + + // extract description and summaries + if httpMethodProp.Value == "description" { + desc := pathPropertyNode.Content[y+1].Content[z+1].Value + ref := &Reference{ + Definition: desc, + Name: "description", + Node: pathPropertyNode.Content[y+1].Content[z+1], + } + if index.operationDescriptionRefs[pathItemNode.Value] == nil { + index.operationDescriptionRefs[pathItemNode.Value] = make(map[string]*Reference) + } + + index.operationDescriptionRefs[pathItemNode.Value][prop.Value] = ref + } + if httpMethodProp.Value == "summary" { + summary := pathPropertyNode.Content[y+1].Content[z+1].Value + ref := &Reference{ + Definition: summary, + Name: "summary", + Node: pathPropertyNode.Content[y+1].Content[z+1], + } + + if index.operationSummaryRefs[pathItemNode.Value] == nil { + index.operationSummaryRefs[pathItemNode.Value] = make(map[string]*Reference) + } + + index.operationSummaryRefs[pathItemNode.Value][prop.Value] = ref + } + + // extract servers from method operation. + if httpMethodProp.Value == "servers" { + serversNode := pathPropertyNode.Content[y+1].Content[z+1] + + var serverRefs []*Reference + for i, serverRef := range serversNode.Content { + ref := &Reference{ + Definition: "servers", + Name: "servers", + Node: serverRef, + ParentNode: httpMethodProp, + Path: fmt.Sprintf("$.paths.%s.%s.servers[%d]", pathItemNode.Value, prop.Value, i), + } + serverRefs = append(serverRefs, ref) + } + + if index.opServersRefs[pathItemNode.Value] == nil { + index.opServersRefs[pathItemNode.Value] = make(map[string][]*Reference) + } + + index.opServersRefs[pathItemNode.Value][prop.Value] = serverRefs + } + + } + } + } + } + } + } + } + + // Now that all the paths and operations are processed, lets pick out everything from our pre + // mapped refs and populate our ready to roll index of component params. + for key, component := range index.allMappedRefs { + if strings.Contains(key, "/parameters/") { + index.paramCompRefs[key] = component + index.paramAllRefs[key] = component + } + } + + // now build main index of all params by combining comp refs with inline params from operations. + // use the namespace path:::param for inline params to identify them as inline. + for path, params := range index.paramOpRefs { + for mName, mValue := range params { + for pName, pValue := range mValue { + if !strings.HasPrefix(pName, "#") { + index.paramInlineDuplicateNames[pName] = append(index.paramInlineDuplicateNames[pName], pValue...) + for i := range pValue { + if pValue[i] != nil { + _, in := utils.FindKeyNodeTop("in", pValue[i].Node.Content) + if in != nil { + index.paramAllRefs[fmt.Sprintf("%s:::%s:::%s", path, mName, in.Value)] = pValue[i] + } else { + index.paramAllRefs[fmt.Sprintf("%s:::%s", path, mName)] = pValue[i] + } + } + } + } + } + } + } + + index.operationParamCount = len(index.paramCompRefs) + len(index.paramInlineDuplicateNames) + return index.operationParamCount +} + +// GetInlineDuplicateParamCount returns the number of inline duplicate parameters (operation params) +func (index *SpecIndex) GetInlineDuplicateParamCount() int { + if index.componentsInlineParamDuplicateCount > 0 { + return index.componentsInlineParamDuplicateCount + } + dCount := len(index.paramInlineDuplicateNames) - index.countUniqueInlineDuplicates() + index.componentsInlineParamDuplicateCount = dCount + return dCount +} + +// GetInlineUniqueParamCount returns the number of unique inline parameters (operation params) +func (index *SpecIndex) GetInlineUniqueParamCount() int { + return index.countUniqueInlineDuplicates() +} + +// GetAllDescriptionsCount will collect together every single description found in the document +func (index *SpecIndex) GetAllDescriptionsCount() int { + return len(index.allDescriptions) +} + +// GetAllSummariesCount will collect together every single summary found in the document +func (index *SpecIndex) GetAllSummariesCount() int { + return len(index.allSummaries) +} + +// CheckForSeenRemoteSource will check to see if we have already seen this remote source and return it, +// to avoid making duplicate remote calls for document data. +func (index *SpecIndex) CheckForSeenRemoteSource(url string) (bool, *yaml.Node) { + if index.config == nil || index.config.seenRemoteSources == nil { + return false, nil + } + j, _ := index.config.seenRemoteSources.Load(url) + if j != nil { + return true, j.(*yaml.Node) + } + return false, nil +} diff --git a/vendor/github.com/pb33f/libopenapi/index/utility_methods.go b/vendor/github.com/pb33f/libopenapi/index/utility_methods.go new file mode 100644 index 0000000000..8a0cf40bba --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/index/utility_methods.go @@ -0,0 +1,450 @@ +// Copyright 2023 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package index + +import ( + "fmt" + "github.com/pb33f/libopenapi/utils" + "gopkg.in/yaml.v3" + "net/url" + "strings" + "sync" +) + +func (index *SpecIndex) extractDefinitionsAndSchemas(schemasNode *yaml.Node, pathPrefix string) { + var name string + for i, schema := range schemasNode.Content { + if i%2 == 0 { + name = schema.Value + continue + } + + def := fmt.Sprintf("%s%s", pathPrefix, name) + ref := &Reference{ + Definition: def, + Name: name, + Node: schema, + Path: fmt.Sprintf("$.components.schemas.%s", name), + ParentNode: schemasNode, + RequiredRefProperties: index.extractDefinitionRequiredRefProperties(schemasNode, map[string][]string{}), + } + index.allComponentSchemaDefinitions[def] = ref + } +} + +// extractDefinitionRequiredRefProperties goes through the direct properties of a schema and extracts the map of required definitions from within it +func (index *SpecIndex) extractDefinitionRequiredRefProperties(schemaNode *yaml.Node, reqRefProps map[string][]string) map[string][]string { + if schemaNode == nil { + return reqRefProps + } + + // If the node we're looking at is a direct ref to another model without any properties, mark it as required, but still continue to look for required properties + isRef, _, defPath := utils.IsNodeRefValue(schemaNode) + if isRef { + if _, ok := reqRefProps[defPath]; !ok { + reqRefProps[defPath] = []string{} + } + } + + // Check for a required parameters list, and return if none exists, as any properties will be optional + _, requiredSeqNode := utils.FindKeyNodeTop("required", schemaNode.Content) + if requiredSeqNode == nil { + return reqRefProps + } + + _, propertiesMapNode := utils.FindKeyNodeTop("properties", schemaNode.Content) + if propertiesMapNode == nil { + // TODO: Log a warning on the resolver, because if you have required properties, but no actual properties, something is wrong + return reqRefProps + } + + name := "" + for i, param := range propertiesMapNode.Content { + if i%2 == 0 { + name = param.Value + continue + } + + // Check to see if the current property is directly embedded within the current schema, and handle its properties if so + _, paramPropertiesMapNode := utils.FindKeyNodeTop("properties", param.Content) + if paramPropertiesMapNode != nil { + reqRefProps = index.extractDefinitionRequiredRefProperties(param, reqRefProps) + } + + // Check to see if the current property is polymorphic, and dive into that model if so + for _, key := range []string{"allOf", "oneOf", "anyOf"} { + _, ofNode := utils.FindKeyNodeTop(key, param.Content) + if ofNode != nil { + for _, ofNodeItem := range ofNode.Content { + reqRefProps = index.extractRequiredReferenceProperties(ofNodeItem, name, reqRefProps) + } + } + } + } + + // Run through each of the required properties and extract _their_ required references + for _, requiredPropertyNode := range requiredSeqNode.Content { + _, requiredPropDefNode := utils.FindKeyNodeTop(requiredPropertyNode.Value, propertiesMapNode.Content) + if requiredPropDefNode == nil { + continue + } + + reqRefProps = index.extractRequiredReferenceProperties(requiredPropDefNode, requiredPropertyNode.Value, reqRefProps) + } + + return reqRefProps +} + +// extractRequiredReferenceProperties returns a map of definition names to the property or properties which reference it within a node +func (index *SpecIndex) extractRequiredReferenceProperties(requiredPropDefNode *yaml.Node, propName string, reqRefProps map[string][]string) map[string][]string { + isRef, _, defPath := utils.IsNodeRefValue(requiredPropDefNode) + if !isRef { + _, defItems := utils.FindKeyNodeTop("items", requiredPropDefNode.Content) + if defItems != nil { + isRef, _, defPath = utils.IsNodeRefValue(defItems) + } + } + + if /* still */ !isRef { + return reqRefProps + } + + if _, ok := reqRefProps[defPath]; !ok { + reqRefProps[defPath] = []string{} + } + reqRefProps[defPath] = append(reqRefProps[defPath], propName) + + return reqRefProps +} + +func (index *SpecIndex) extractComponentParameters(paramsNode *yaml.Node, pathPrefix string) { + var name string + for i, param := range paramsNode.Content { + if i%2 == 0 { + name = param.Value + continue + } + def := fmt.Sprintf("%s%s", pathPrefix, name) + ref := &Reference{ + Definition: def, + Name: name, + Node: param, + } + index.allParameters[def] = ref + } +} + +func (index *SpecIndex) extractComponentRequestBodies(requestBodiesNode *yaml.Node, pathPrefix string) { + var name string + for i, reqBod := range requestBodiesNode.Content { + if i%2 == 0 { + name = reqBod.Value + continue + } + def := fmt.Sprintf("%s%s", pathPrefix, name) + ref := &Reference{ + Definition: def, + Name: name, + Node: reqBod, + } + index.allRequestBodies[def] = ref + } +} + +func (index *SpecIndex) extractComponentResponses(responsesNode *yaml.Node, pathPrefix string) { + var name string + for i, response := range responsesNode.Content { + if i%2 == 0 { + name = response.Value + continue + } + def := fmt.Sprintf("%s%s", pathPrefix, name) + ref := &Reference{ + Definition: def, + Name: name, + Node: response, + } + index.allResponses[def] = ref + } +} + +func (index *SpecIndex) extractComponentHeaders(headersNode *yaml.Node, pathPrefix string) { + var name string + for i, header := range headersNode.Content { + if i%2 == 0 { + name = header.Value + continue + } + def := fmt.Sprintf("%s%s", pathPrefix, name) + ref := &Reference{ + Definition: def, + Name: name, + Node: header, + } + index.allHeaders[def] = ref + } +} + +func (index *SpecIndex) extractComponentCallbacks(callbacksNode *yaml.Node, pathPrefix string) { + var name string + for i, callback := range callbacksNode.Content { + if i%2 == 0 { + name = callback.Value + continue + } + def := fmt.Sprintf("%s%s", pathPrefix, name) + ref := &Reference{ + Definition: def, + Name: name, + Node: callback, + } + index.allCallbacks[def] = ref + } +} + +func (index *SpecIndex) extractComponentLinks(linksNode *yaml.Node, pathPrefix string) { + var name string + for i, link := range linksNode.Content { + if i%2 == 0 { + name = link.Value + continue + } + def := fmt.Sprintf("%s%s", pathPrefix, name) + ref := &Reference{ + Definition: def, + Name: name, + Node: link, + } + index.allLinks[def] = ref + } +} + +func (index *SpecIndex) extractComponentExamples(examplesNode *yaml.Node, pathPrefix string) { + var name string + for i, example := range examplesNode.Content { + if i%2 == 0 { + name = example.Value + continue + } + def := fmt.Sprintf("%s%s", pathPrefix, name) + ref := &Reference{ + Definition: def, + Name: name, + Node: example, + } + index.allExamples[def] = ref + } +} + +func (index *SpecIndex) extractComponentSecuritySchemes(securitySchemesNode *yaml.Node, pathPrefix string) { + var name string + for i, secScheme := range securitySchemesNode.Content { + if i%2 == 0 { + name = secScheme.Value + continue + } + def := fmt.Sprintf("%s%s", pathPrefix, name) + ref := &Reference{ + Definition: def, + Name: name, + Node: secScheme, + ParentNode: securitySchemesNode, + Path: fmt.Sprintf("$.components.securitySchemes.%s", name), + } + index.allSecuritySchemes[def] = ref + } +} + +func (index *SpecIndex) countUniqueInlineDuplicates() int { + if index.componentsInlineParamUniqueCount > 0 { + return index.componentsInlineParamUniqueCount + } + unique := 0 + for _, p := range index.paramInlineDuplicateNames { + if len(p) == 1 { + unique++ + } + } + index.componentsInlineParamUniqueCount = unique + return unique +} + +func (index *SpecIndex) scanOperationParams(params []*yaml.Node, pathItemNode *yaml.Node, method string) { + for i, param := range params { + // param is ref + if len(param.Content) > 0 && param.Content[0].Value == "$ref" { + + paramRefName := param.Content[1].Value + paramRef := index.allMappedRefs[paramRefName] + + if index.paramOpRefs[pathItemNode.Value] == nil { + index.paramOpRefs[pathItemNode.Value] = make(map[string]map[string][]*Reference) + index.paramOpRefs[pathItemNode.Value][method] = make(map[string][]*Reference) + + } + // if we know the path, but it's a new method + if index.paramOpRefs[pathItemNode.Value][method] == nil { + index.paramOpRefs[pathItemNode.Value][method] = make(map[string][]*Reference) + } + + // if this is a duplicate, add an error and ignore it + if index.paramOpRefs[pathItemNode.Value][method][paramRefName] != nil { + path := fmt.Sprintf("$.paths.%s.%s.parameters[%d]", pathItemNode.Value, method, i) + if method == "top" { + path = fmt.Sprintf("$.paths.%s.parameters[%d]", pathItemNode.Value, i) + } + + index.operationParamErrors = append(index.operationParamErrors, &IndexingError{ + Err: fmt.Errorf("the `%s` operation parameter at path `%s`, "+ + "index %d has a duplicate ref `%s`", method, pathItemNode.Value, i, paramRefName), + Node: param, + Path: path, + }) + } else { + if paramRef != nil { + index.paramOpRefs[pathItemNode.Value][method][paramRefName] = + append(index.paramOpRefs[pathItemNode.Value][method][paramRefName], paramRef) + } + } + + continue + + } else { + + // param is inline. + _, vn := utils.FindKeyNode("name", param.Content) + + path := fmt.Sprintf("$.paths.%s.%s.parameters[%d]", pathItemNode.Value, method, i) + if method == "top" { + path = fmt.Sprintf("$.paths.%s.parameters[%d]", pathItemNode.Value, i) + } + + if vn == nil { + index.operationParamErrors = append(index.operationParamErrors, &IndexingError{ + Err: fmt.Errorf("the '%s' operation parameter at path '%s', index %d has no 'name' value", + method, pathItemNode.Value, i), + Node: param, + Path: path, + }) + continue + } + + ref := &Reference{ + Definition: vn.Value, + Name: vn.Value, + Node: param, + Path: path, + } + if index.paramOpRefs[pathItemNode.Value] == nil { + index.paramOpRefs[pathItemNode.Value] = make(map[string]map[string][]*Reference) + index.paramOpRefs[pathItemNode.Value][method] = make(map[string][]*Reference) + } + + // if we know the path but this is a new method. + if index.paramOpRefs[pathItemNode.Value][method] == nil { + index.paramOpRefs[pathItemNode.Value][method] = make(map[string][]*Reference) + } + + // if this is a duplicate name, check if the `in` type is also the same, if so, it's a duplicate. + if len(index.paramOpRefs[pathItemNode.Value][method][ref.Name]) > 0 { + + currentNode := ref.Node + checkNodes := index.paramOpRefs[pathItemNode.Value][method][ref.Name] + _, currentIn := utils.FindKeyNodeTop("in", currentNode.Content) + + for _, checkNode := range checkNodes { + + _, checkIn := utils.FindKeyNodeTop("in", checkNode.Node.Content) + + if currentIn != nil && checkIn != nil && currentIn.Value == checkIn.Value { + + path := fmt.Sprintf("$.paths.%s.%s.parameters[%d]", pathItemNode.Value, method, i) + if method == "top" { + path = fmt.Sprintf("$.paths.%s.parameters[%d]", pathItemNode.Value, i) + } + + index.operationParamErrors = append(index.operationParamErrors, &IndexingError{ + Err: fmt.Errorf("the `%s` operation parameter at path `%s`, "+ + "index %d has a duplicate name `%s` and `in` type", method, pathItemNode.Value, i, vn.Value), + Node: param, + Path: path, + }) + } else { + index.paramOpRefs[pathItemNode.Value][method][ref.Name] = + append(index.paramOpRefs[pathItemNode.Value][method][ref.Name], ref) + } + } + } else { + index.paramOpRefs[pathItemNode.Value][method][ref.Name] = + append(index.paramOpRefs[pathItemNode.Value][method][ref.Name], ref) + } + continue + } + } +} + +func runIndexFunction(funcs []func() int, wg *sync.WaitGroup) { + for _, cFunc := range funcs { + go func(wg *sync.WaitGroup, cf func() int) { + cf() + wg.Done() + }(wg, cFunc) + } +} + +func GenerateCleanSpecConfigBaseURL(baseURL *url.URL, dir string, includeFile bool) string { + + cleanedPath := baseURL.Path // not cleaned yet! + + // create a slice of path segments from existing path + pathSegs := strings.Split(cleanedPath, "/") + dirSegs := strings.Split(dir, "/") + + var cleanedSegs []string + if !includeFile { + dirSegs = dirSegs[:len(dirSegs)-1] + } + + // relative paths are a pain in the ass, damn you digital ocean, use a single spec, and break them + // down into services, please don't blast apart specs into a billion shards. + if strings.Contains(dir, "../") { + for s := range dirSegs { + if dirSegs[s] == ".." { + // chop off the last segment of the base path. + if len(pathSegs) > 0 { + pathSegs = pathSegs[:len(pathSegs)-1] + } + } else { + cleanedSegs = append(cleanedSegs, dirSegs[s]) + } + } + cleanedPath = fmt.Sprintf("%s/%s", strings.Join(pathSegs, "/"), strings.Join(cleanedSegs, "/")) + } else { + if !strings.HasPrefix(dir, "http") { + if len(pathSegs) > 1 || len(dirSegs) > 1 { + cleanedPath = fmt.Sprintf("%s/%s", strings.Join(pathSegs, "/"), strings.Join(dirSegs, "/")) + } + } else { + cleanedPath = strings.Join(dirSegs, "/") + } + } + var p string + if baseURL.Scheme != "" && !strings.HasPrefix(dir, "http") { + p = fmt.Sprintf("%s://%s%s", baseURL.Scheme, baseURL.Host, cleanedPath) + } else { + if !strings.Contains(cleanedPath, "/") { + p = "" + } else { + p = cleanedPath + } + + } + if strings.HasSuffix(p, "/") { + p = p[:len(p)-1] + } + return p + +} + + diff --git a/vendor/github.com/pb33f/libopenapi/libopenapi-logo.png b/vendor/github.com/pb33f/libopenapi/libopenapi-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..78bf7e5fc62fea7556372f62e137b3bcfe1caac6 GIT binary patch literal 94065 zcmXV11ymIM+g-Z5rKLNiOAzU9X^`%a5S9)B>265{5eccKyIZ6aGg0cQa#-lE&_N&&mV*2{O%Mov6a<1>MMVa_G20ek0sbM{yj6J%0#(Oj zJeVVaKHw}mA#M`LJPa3KsyF-#x-KCRUXHv@Psj|qeD0UcZ_JH0Z==6_h|w_;I-*|w zUI+ese0X?2ci*y`v->dSJB|~ChtHU}Q)mwo)(jUDnWv6dlkXX94T2|9Qs$t*_?FVze((+SpO zhwtbDeXEdq&577i2^VBg&npKX)QSZ1iqlWPkun1XWlFP;fM|r^K{8YXqX;z02;aD; z+SkiWUBesY;Xob3siWyiQ+$MtsS~ff&ra4iX*atZtEJ6JSa7Y;wqEC?XVVeL?;JJZmjANPHZ{wxd;6S74#ZVBaWslV8M+%8@A1Vm+?prWx)ms$IPQr=~ z?3_-@mJSklbL4kYnDiZDxYEd5K@{i(q-k%-v^zxR5$mcDUVX#M+Q9wO$s>fdyN+)Z zyzfeaY(|>bMcNX9hWK^>mB5@<7DM zr0o-p<>}5i+zEwajil}pmIi2eqaUJMCEq$fX)aZp;J z!{n9Z0M#T6x63gkAwf=GSzqP{!vWnNd9jN@-HI!9~7Lvd8u=0MV1lpf68JQ%_f!^F6JnjnaHxUvAeeAf_XyFRzj&{(L(9Aw$K&u;%ta z*$e5O+>6UkSxd&F+`7U#(K>g>Z4?f>uX_DNcp*n|jCKrb%#Qi=s=Cf5)@OlhlIT{HOv6WR5&SmM0?#mU|8vc8!xKVH-d2hHW8GCE)3YJBDe%ZWe?wBLlrW5+?v+lW<@7!J zyL0~M;neL{N06zy>C2+*=IrHP3r>GmM#Ou;KkrpIv&jdIyTy;+UYuO(Z@P^@bH8VQ z?>bM|ZF{{Y z-bNQN8;}`*@{o5gdN=$Sf78CoZCc|_ZV=^t%!nU?rbB}-hb-jLsQda^Gzg6YN9(=(S0|&S~0%hw!k5rl9Q5Cq={vh_J?hb zyMehu&6IdbTFi|*Fre2K_0TzRtSk7lJhHnB3-4>lh|QbV6c`BwQ4 zfBDv|pZ?v_VT2I-wCR(IWBYYUm8E}z9|hEA1~$gqXz@u!xh3=TV2UVLb>Br;F^sB>(eK4YjG$V!rGTH#vp zqw=QeedErio~r4L|D~_f;^L}e!_eWr{C@GibH%km`)|co`?oU_5hqx`$WLRp$xWRU zS3L_p+h4|w{uvz_MR;TW=Fo7YzGCUDK%nUAb8evVukoKK`l}0&lwcfmVzY;%`E7{|Hdrud~<=^e? zHE2$n0L6TluKzsDc9EU9B|A7wfxloCSEV^TQ0Ns>FriXGW7e$?|HeZ zlHz|emwm65A2J<`HH=$rWXAI(Nj#5~8%(bU&sTTjjZa!!FJ50;EHN}F{SvPfmkV%x z+>rlm=(2BhJ$$GqR_S@6vM)M$JRNvv-!bDccQeOnobTIu+;>3U;LNx}(Z~R~yz#m^ zB=JT+QeHOx9Pjh{p>6T;AIcrhzra6F)m9x&>o;Z{X5-xkILFv%k$F!k&(o0`Q*tA6 zGj#9iV&ikEsmZZkwVr((OWyci^POOPC_wkwci-dZ?%Lz#z0$b;!~6-xZOnLkrEl4} z`|;1R-y;2V{nRaEzT&5)55LBiz{icpkhT6+>P+SbsVDXG$veyb?-Od*61)CS4_wz_ z=l2|PLgN6)q_LFOQ~`lLGlD=tVIa^Q@Kw+r2=s{?1o~$N0*PdRKqRg?5DhWl1e&Y7 zfd>eLLGbbi2g=GJ1;KqxQh4`P+b8E><&zJ^+|14CF{S=0QIVB__0GKNCbxiH7Nb*= zKuN=h$}NXXv`Z#WuPLp{lz?4^u-8CTW@gV6@7T!WBTo{v79%?yF!X^jRVm8E*Oca)&cIz>A8%y1`#tcP2?aq zDN@>cgq4l}GwLdIc_KD-S>Z{J=HnfUNbd3+!vF4|$uHsx=ZeSO&ADZ>q-*}wi6|lN z-Snq05Ux;tYzlS+tn=h<0@DLaQvz-oRm`BL{~Iv${|0R}VAqk^v5k8Ap}&T4OViDK z`y6rTC#v2Y6hrnTTso}$l~hnES+QkqaghdZ6!T;~c)n?M;i+b50b<@_sCY}g9vGY} z3;q~gnDgg`z*-n=Pv{0Q)Ro{(3Uw~=T&x3gc^kb`nc1*F5^_y%b=s++SMmw z`l?OIz}M=!FoXaEb|maNlV8lyyj%ajq_YdCr*i!@eKwn|e^oR3SbqEQB@=V?Uc439 zU>tGQ`wFFB=8X+O``)_2;d#6;R7sM)!Sz!=Bt;M5nKYyp*lUVZ#s6m5c~gPAxwP<+ zB5bThuRWMSuRT`1Bwrc+jO;o&g5G?m#By5;_eYTIZ$HsP!&%LNVjl358k``)*hH?1 z2I2O^-*-}gZCZT`U=O=G^sGQ}`JtTm+@|J!KaEbClp z+H^R5RCdz7T2^2T-~MNDG|q?;SfF`CfX#k?vNvRrK;GABc0} zV3%~1DC;wHt}l+IlUMLEg&8dAFM^DI%|FN_W0fS`#NR;66+EvQhUpTyyMsrAFO#h| zu@I}#eGwO1@I;ymnVE#^{&P`^L7QN2n@x@KY$i7tQ=9T=qkWP%-5=i)}Sn;cn znc?lse-R?mz4gywpJzonu+~h|W5VH{{u$%UaBx)ZqFCxzZ<2<;ch;LK&X$Bpb7Ey7 ztMB<~5z3P3{x5cz*wLPJ`ZLNN-jt2BU$CMZRAF>C4za)G>!gm*_sasDX{yeKykJO# zky98Wemv4Lv{XhQvB3M8({mbOBI4h41@jQxjS+KXlj)#;uw7U@agv~*m#|AM6iHZ1YutXQOyaNKI=4bd0%;l%r?+660$s*L!G*0A8tTcDLq$~_s z&fmx)vOhIKT=mxLLF1c@#M!}liT*UQTS%;K1W?~b5>jYTTHAFxlyT4soKGz@c3$FB z2CvuO`USSLt>E$J_z|RF=DjvI-$)`s?5x?AoSt++ns6){@Z2A1$mbfKI<5&sD(Fsb zL@Ie(n1Lc{noJ8{w@mvj_CD1U&Ud3H-87?fNo@h00`i0dH#s{DsX6mq3^j{wUQ%na z4sbU?W+C&?a2XK!75n+u71vqKf}!*BOMTT&6iZ#z90$^H)4NRSy1`IvFR5uycNjg) zmL$u(&`u<)QqKXR!Qlx`E49-@S3&W{I%OkjGH_o%&(INA!AVK=NXDT zOm!duKLJ0=Gtznh3hAakc#d)1cWnJF*5D&6V@Vr!uZD)|w*Gn#cTzB!{E5Sb1 zHv~c9W01)G6P0)#3VcosZlWXa*iE>NrtUsj{fC{Wu%?DLLzHW`?9C?r(H?8}!ec(e z*{+WA{ZflTuE}20D6LKkSHA-BX!&t1h^p*;3IT)k6$Xr7@pKde@j7S z3Uc}JRo+RQD3&8-=FKKX>IR0~33B)2^aO5}Ds47nx?+;r_b=XcNe8fRHsjb+t;U3B z2I!fXkbb@~C{BRU^q+VomVA^aga^EaVoQD=Hzl1h*P@0NmyA#GkQ+?)J{0E1=KTW5jdL>Y) z-xs#ekEP;mn)Sw5&i2DQ;F$IdE9KaGo@bL^riU~f{~{1fTn)}PbLns0$3>`-^Q9+Q zx}|uM7ml6YX^Q{J&rY*eTirZ8d~;OZwpyx)PDb%1q=&|Lh^h+`!RW$BLN53{|(nk|sdWX~c}1=-|{Z{wz|>@iVY@K_%KL`<)t!YUg7- zLDqZ5RV4vDIX=t->Aa6>C{xu{7y?b&@U)0cp7?CX5_wNCWkxj^{K1vvDEN*lbK#}r zI)GU>4cCAQk8$9R-Zv3CFN}Rye)k#S=-HR;C|oP>diyrqF#Mw5cQ3mM-a4teb3Vr?DDd;w zZcr|8K4T9HvfVeiaxv;%tsAcngtDT;5FzHeS#2HZZ~alXeg_>xE8nMu@GfhnVgxZX zGLWLohl}Y-#6X2eOGygsZlulsy|Pi)U3+IW?E`OR1z;xB6dn8uR47&>30YjIVbVs6 zHu4dL%QF&e=X+vSjZA>P?X(GGqVsVXfrzZ@Fpm+D&^^Ut(4D3CDRvht_Z--+*MA49RD2TDN;4VYdw!ra z_VeO~F2|JRiy^Iej;E?Mlh8+?)JxnnITneN`)tpoTw;GfKlJa_NxBaHmz&e@m9Y7tU?(h<8bSQ9omJtWHc`|?rDK9uC`k%z z$4>?W3J3n!Z27%IHiJDD^q&_8dp^s1dME8I%L!!Cr>iC?^$nIJe}uY)RhoYWJ4Z$L z-`8Z>FV&yih5r4c{H?|geTE~M`KJRtu!L1pk^LyQn1sCGaTraz$|K(V#TMW4WB0hn zV1HZh)--VqxYu4l?6c_PtS-L_uP>}uS#n?6zu?Q#Zv*+K^IvL%^&Af2T-vip%G+BD z^X1Il77JiO645XXSs>H#)<}H8ZFhByaTHVR{wvJhw$sY5oEMkcz`Vsf5c*vR6Jh1T z>@yhTdAQhh7wKZNC>wUZCAv$CylE zZTdTJ^0HNDP4Qp!5J*(rG2O!S+ZIbnUE284CX^XZtbVtub0p7cDa9xz++v6?K9S{z z9~69X|J;(xa=FP|Ccteap7|cl9e7Gc%G6t$2F?#_-cv$giFEMYG@(1#LlN}2@&^0A_Z|@Q;Pn0ZINL^xD+ntMT;Y)bN+G6zn{rYc$-~!^;YnM;IB@S zXfvOd<77=v|zwI%zd79#ja~|7a1z99WrMDx?JO2=wITINV`EFk7y& zJk`%vhu{3h1vU@w6__lJhCEq=OZN$D$beCpU;neglcqB=Rw}Mf94aM##W-HzHH8_H zsuRY#JR+Wb;6QL4?PAl7A)03zS!$PaI(u!oy^N1}9sG8s=ahe(YCI>#WVbS!sgpcx zGLFL{apOoh{81B{3_jiyIys{T^BC7q05lups;~%B%Y|n2>;KffQ$MhpDbY z_twH+wLFFMWv!^c0wJZeVc!x)&9-Y$Rl1?qMdVZsu->R=O##p1W;boYWyv=PuFJf{ z{UOq0F9;Lj?NZ=(%n2;Tm--{x#d>lU28cO?QnCU*%Nf`Yp9eU5rm=5si$>*!eOi)s zoE!hz@aDlKJaGsRTDz4$c%%GwS#P2a%#W;m;GJ{g5EgvWngdP@L>gRr$fF&5RtU4m znwXR|RF&;Z0Q&#{e)sQJ`m~hI!s*J~hs(o4P!8(O8g%_k&q@3pJ>J#;F*qEkx}84j>nfeP?-8zZJRy*Dh_vb_^y&~sFWM^wxuZ7c1Z%_BnzF@b_psq!-mg*&vBI~s$ya>b%0wJ$&7c}6xlguf;JmY4 zd+J1=KkZ_4e!l82>8Hk(wk_wE(TMn>n1v#jYQsEqau2~R6wX%Flyu^ZF@5HwSSn3W zXhL|U_)a3bk98~4e{mtq;g!#(nq;xxxYt7gFBYwHm&#M1FJ`0($RE*%&pBHhL^1q2 zJ9+~njpr$a&n~k)g@HwqG*3@9SiUcAzI6(RLxUsP=+IfOIN?RilXWU_Z z7=mDMrF~_QvnC}0F$Yb4+DCjhk$RWHPf(1DgC&*myxbnqYfGONc~}*YIj@}bdrO&) zn2e0a=Y?ZzvzihjSoos;W^M5~Q=TWzI)%CFwfS8i_6%8t3z8zUq{sJo0JYtjqJ4>h zM#P+Un7++!4dm$5eIv3RSSGS!=;RY8gh3vcIVK_c>TJN}Ilk3FZ#^cZU>{j?NDW?+ zVm+7`F294LcW*d|;w+Oe&Jv1|%I7v|plsxhT}NO;!~a$yxwE?BIctomBy_@4tPK=l z_e1mRYy1yuJ2ETA90D!QV9(vF!#^%7^8Ht_2gdCoo)skhHE%`sN>SMIW%xY*F^(1j z=Gw<477K|=<^em0V1wyf8@f+9lvZF6fh_=HDb%AaB#m_c$ za>uUu@76J^Y1dS>`!Cr?{6T!x3^@9-RTKXWcg}|iJ)bi!Ng(z`0)PxJ>j@#@7lkj~ ztk7~W$1&nVNAQO&BM}8zOFjbP{O%rE8!etvq*2`BA~!)EiJsQaFd*dcuN~Kn&g%gA3qW&!&v~)pf3uze6xAxEcWDX1$?r?YVD3> z{$wxruWC+TF~cseb)OMyzxHd&0s1|MkB5xAw_l6F`=9x{LEc|)b}S?UWHnSxfYLK% zV;Z%EBV84*veIVAj>KZysn{x2neu!CRfR77>jp-;$Ig;uoF{v|#G`HC<^#zx&nQmY z=5R|R0kR~LHXKcfXrE{{t>$z`1xBUW*;EX(i(?ndJm4RWKPLnewsFyFJttHM;w6Jh z%fg!I(Y#B92)v&w$<>8RvxZ7*Ge31MTpS!)jc0vdXb8Z%pKYJeYd@mP{!;BXQ+r@? ziMfqsX=mVyOhBAFmI2ek_LSxkt8(f7T==VbMPjomFS$?>AZJSCU-GVhrL>~TA~DwV zEKF~W;KXtBeI?j6~xtE;dze%^BStc;Cd7_((3FQ z<}#l}N}s56;JO#Aw7##6pKNj<2Z}$cz=V%_DC5ufYK}e^oUgu*TK&r;nHIBwBZ?JS z%J=&U1a&jnHyxC+{+%zvk-Ha)_->-8jmkMJz%4GL$}Qi9{xlR z5wTr^U1x zYRg@WVNy{)T8?uyo9Bqsj5ZKWJ^VB4m5e6g_Ew1iJnPWO3A_WvaF(MF*ywK1g`m>z zTLNY7FRPN2n{K>9C%>j+CR4_Rl{i5{VdiWic^H7q@T9o|HpoU=))o6kG881VXz~@P zPj9$H)9EI$C|$V2aHSbWm}pcy?zzdS_7-P)D|OiB?=C|BI4wxgrg!e+YzkqAJH84m z?mEQa$n}N~WcNCVc7Lrw4)^~)X^U*{*eoThf{`aRaL6O3h(xkdXLkfy7)+d$~l<>z% zI`s_@V{8bSM%Nj~7PKRxV#ckm%WdY*F6a=4*#II-`FFhUTuXW;Nei(Hw-jR{eR@5P z|B9463mznn3HP0CmSTpQCw#(DqZ6$ZpJ!=aQwobxdX3-AD*=g9kf`Yk(2jv!THL`; zyDd?+5!|3Tp8=FLuZ5ybO-NymJ}aDzV${ZE5ln=st29tFUyhHTG1rThDlo`jAQo4| zre(Vb0HhznoD&XUz14?rsSI9&;>Y7F_gT#)1_#=(!eAMqJXPB%3r05uYOc37fgK~~ zCb2NAglMnpwYm(XWsn$_k>=I}k*sjkk5p?}GAb@ZU8*FCDi?;?i#yz`fG;>o3Hbdr zRTU2>2YCbu3iM=rmQ+|;*0m1X?qQ~M$zPL(r6iK2Z9`j$)8$!sS_3fS%NB=nd+xrA zmHMs3hF&IT+httwd=PAlAUS?uTFMWkXjbnaKrPJ9W03b1bR|F0G1Jiq)g#;v`wmc# zWK@(=Z}%XX|A6$f&E47t6)l`Nxq<)VWH7vAg)`CWM;_;7d57@Mo*clx4m_q`9JQ+IK18G96Q<$0; z6YD==vQ=^IVnyhK*CY+xmh#ck^zfK}7AK5PwfeC&n;Jz3;&u^4s|&h`jC!b*_>Nfs zB@y$-b3%8S`8t^wOdC<=adH!?f6HEd_4sb-3b(wXd&maGpBW&|N-ggm9vLd5&rEsU zxWy-G%tT_R+eYfYQ`_`X3Qkso5mu#8yZ12=OpzDwO8aQw~(-8EI2J#NUb;sc^~oXJjWxDt)8*y&16YNh&eOG`~5+-<)2kMbRH#GOI`a#GkpvTZ%)&xea{*Y0(J} zuZghICd)<~>rmqX1o#zhQo&<>fIrQ(-RBhXcD8;A6_=a5RJVuEliW_&yKTE3+5&G9 zRX$dsH(9FYm81aAqcRNwc$$r@&tfK$2$X5`CGYl^{{FD%P3gpkcV`jwt#l^qF3EqO z$j%puw0XWnfp|Ifl5lok_%O+{Jfj;S`lHwV1Gr*0O^#hctD9vwLLlpm9cJ6E{CQ<6 zB(~n;?n+;;LjzD0YD~;Ooh+WLNHqA&UxBDh6I%C8wg84KCl<)&81lwT_=c9s%_dWHyfiizZ1ooUr<#9UIOd%mld-5^C@yI!i>uNbYd9PPnR(6k8t<8O zrp1KH#ehO$PQ2qBQkksMqklc|ODGNC>appxaYw;PeHO zwg^XFl@@Wu(Xc@vh|OjAK5aYtA8_V91WI;Rb109yT_jNTtgto^FGiL+01+=D4`e69 ziaZ0gZ@eHd-TCXVilUjM&~qob&$`ZI7H|r$LukdX3DBRI?c?$+r^wweP>npl5hYN_ zbD%7sUs^GW%ji94?t0?d6ZQ4Ox`*~xvi?-lCnU?#aR#DTs6G;Ih%$dP49D%NS)#jZ zcx~uT&e`S=p~3v-p?^iglE%#*61Q=Rx$m2jY-HMf?D@AfPxMhm&jZHP4zwxqm926D zZDu1ql-*z_9vNUTo*FBBfHjL_KCEzyySP`tb3N>G0mM&%^QQJx^}I&=&6naHlIVoJ zqxE1@|5VCx@lHT1OXOR<(s z28dmu9n4^02n%49iFyOx=|MXR>j~AfhM9ozgh8zG-gPET1JjMdob^&EzD?VkND%g4N zkCTZ^VRLMZgu6K3SW}okBfx|TpKVFfz7S-Axx3uy)}Xyo?+b>JDPx|in@$2(!|amJ z%d-J6pRXVF$gATXi$6CH^!N?ZTM+WHPz)C)jJIt*cQ~DzU8Q#Uz|+E8r6LZoqUp@2 zo2)5+YY73gy*BkPQsMUuxBP_20$lHfLzF36;6gpt&I3Yp>cqg)SRb{}{0mU0+$4~- z5nK-MFYLfBN^TDM*+K3d2lwZx&(&_BDNiFLQrRVgc7THVTYJF&z?#8$%7LGJ z9RwZcjgN)Lazs#O2I*h?IB|fmY_;`>e*=;dnN>PJ=wb* zXH!Vd7;a?eHIW1!{MLWWwGw6!vhnHu;e&y^C)3`1TNHTT^qXZrF@El^9?=hp_2Doa z3m>t)2pD4vJo|8|dR5gy+tyG$i$3vYDv1=l^7K0bc;jhqOoVBEYvbs}bv+v~-DS@v%40?@(`ABOez=K6-rQHPD1%Mtw|jFq2T4hEhSzC8fnGQNbpvkHGW#B58d0^m8jf@%CF5 z?u$T5o4`Qsq!^YK6wi>5ywtMc3E0T|np+q2ZwDRSpuxXeBlQnLq2IE5_LWn!K6pHE z{%YCsC`^fEV8^|O0PUZ>Lx!XSGPM5>LO{_a9mp392vA0Kfc?^jd_u-TR;u>gt;7TxLLqV2b4XbMF5s$!Nxh- zDZ&8(8B)>2QYnTfezgdJ~(k9vcK4FA=s!shO8)Ze+8DRn&= z6&;3cD|6`r8k2Yh8r+UuaZiWVcf7KlH3Qbmh`+uIzIS2o8(X^0?T@nS7S4=|-LcwKmFDeSa1D!EK%*-B-qb3oV~e;<^0dbQ}a5 zpBpkUw-Zq%@*4u_Hm%oPI>z0uC7Fl5s4JYWzcda-?}v5>hU0F>Sps=`0y7!l*faiY zi2<0Y6yj@PDi=XN#%!pXqPcmA!Y!7UB%c-T+RQvp4Aj9x5&cKz{n6j$uRWVBGeYtB zjhXVfaASKXv2vq0M*r{&@;D74?u=v%jlhywFd|QVM$DslQpYA{R=S7k$PJo4i;H?4 znh#$YAFMX#yE4BMB9xl@o=S84d;OqiGI#bk;jCFnRP@K zpq(vX#_4?XJpvjn4len}4T7Ad1pxJ(d^75>C>j^HB1qh!!R=VBl4-RKXOx^iQLz@7 zY^C4Yk`VYb1TWs9cc@P6Y-@V?^Dcs?rx*0x7cDZxnJhlVF!&g*o$|CJB{}+q^S8V!is^X7sKlP6PAw9g zTWesUkJ(o>J8gm0Rtw!*Q)mwxyqNLnKCczT5{sM45@pYAPRlXItdA<}fYm1AIO=wz zh@@=3a$oCKJLx&weVKNqW8A+XMSi%=YNFak zLzooK*h`wbmLYar-r#4CVn8kw5$O!d=K|l!7zGU8_F|t})gR6Gu08vrJhwq5Y8EK0 z61gMHX-bq4^7}cK)Kh3nl6E>ZUfO9YVI934bsg|`5qJyXVhbO0&LXOnC3ksC^L){Q zYj9z<6#Z_B7TXKCAm$U~F1poh1I3d_I5@*J4rr#~6E)@190Bw1t`i>^42ER(ltX6p z>6Rg<)ssgjb(@Z4om;=wnIQ1tzTL@liQBJB z-gojIE~CdNwQ{DP+j z0+M&?0-!KGbmEDX88#o_0PQkk(+v-qD)B3kP{I>rx{n^hNrQx1jB&fUF0EN?rr?cE z1ZGv#@wTcg$+a67s(=SOPh&d56F}yk5SQ3#zk5a8{=|_X;a#*Ir98b{lY%5Y@=?o;f7EQ}Hl6RhYfeMgP=?k9s9R%5N>YFXSvn{B`sc`$uif9v zv~4zkm~St%Irf6LBHH4J)E86LlA&~g+_|s1_WopH!@vntm-T$6Q#)CbTn z1lejoZslPuK47#+O+tpAqU-qja!w=={pM|Ax0WjCWe$%&O&{&6ElIuFpZ7U>vEOP$ zC~}?9yONu|?vb9}C(#r+SUQ0}%$}w3#CdWRE+|)|KxybdmnVSl20A1n0~z!b8)9=x zyZIWHM+gF+kjhrEyHej2^9fJEFn_o08MR%OsJV3tE5)>(I?yXqNX89w2~(>~`?!rF zYi6=r5v6(_Esq@OaN(9YmwH(s#DOP>sG+a|(HE=YoIT$Tr6GG?dQkxOzGJGlsJ32cVG$YFr$=z1@v#JpA0JzJxy7&XEF(0THO-SVzGA+E&d z;=0`o3iXD@r-WKhtV}CeT2h+c^q@4}wD3iW$7#M;ciUyR>G{J@T}pa5UO0uV$oFwtKK(=HzxO3NPiKAm`AAO=WDx=+|T|pTZ0gJ9?gfP z4#PVK?n*PpI+HqY>~iy960C?_ylW{StO%=I$z6U7{as_(Yx&OpAIm(pcq@;I$7z%Q z@!fcp>uQC0d{N5G+^p;E&oQR#;nRa?ojoe*(t>K}Efe!c`caRa0`eozp2<8Ra;gDF zr@W?Zv}==)rF#>xLbL~SnB>3gXxzXd%q-tiVP3Za=UMN{@FOmQk43^ zjw&bFqQrMr_V;TV_>2tsPfSX}ZeY@zOkDUS)`an5w~DUdRMYAGZgNaI%E%IzM^p}s zv?LYG$2e{lhSIrs*g5uitYuVlp*~u(p3_F+T0nf|is4H~5r8rHWA|6@1y=8`1hKmZ z|ttvg*Zl8aQxp+J%h!$EG?6s_S`}?TtA#`cb0GVkncP{#86*&(SyR$ANb5M1C1! zwwtnL>X*?~RV4xG--@-lk^#M1xMh?wfaES^z>p_J+F$SH7$eOYD&RPn_-^jfT&XSW zh;amv+`CsKZ{Wr6y>QFROPF32mDl7@2kyrJ1ozir(@zqCH@Dsy6I04AuT{QPB+Xnu zCPxOGV}!Yis(#)1M5q!<$t9*Bk=|WHIraf^6Q-B}*T?_&be|fWE6n$OdU18~*~1IT z)lvgND2ovG|H(b94geme2gqpcMu9)2Nq3|CSb)StpT8sm-`506H^$ z2wiBtFyVGlmjTTF)T#NNC?i1O((*ga*E1opne9f$E49*qFG#hWqG)ZG=)x^-bw0Ke2}v;$f(14z)+bJx?Z8~Ab0f>j;|jLhQMWJ z$nIXn&Zo&T6Kd~ds2;-G;#e}&2{CV;I0iJm84aMVVn;ZpELSME2Es#X z!ex=c`x*^ZMb36{Vt1rVC8I&SHo`C9!K!AExlKLnYRox})1bpN@E#$R8%Nzki%#(2 z!Z4@K6VG^3Xw_BN;iz@HBf55j9LzQrfg|F5NV6~g&|Qho-PgWfjZS+yD0SR|=nNqRl4kFp$#WL}Pn$NC2bLF+&QfHWOk66eF2~kn^h+HN8gVDQ)vKw&k zhLM|`D+1Zv|9C&&+))dm`dwk*tGzi_u0kSNG7F|FwxPEaG@NQDJo-a}<;X%fv;!r{ zUo)FPfkI)xi!^Ep2ZnZ3UEz)_og^Vg;wxe|!!F53hd|f3f{h-IQabxO$=W?DkyT=W z=!OFQ`t^B{3plt|RW!VE6>(KPWB2J&bXNR=^r>dDmPH-4isQ@CTC5JUnP^hxG!uzv z1s;#xgHYRTZ@lFzWSBDY=%d;_+Yt>t&~iVakPM_!v;+2UBV)U$I z-z6Effz+`d!Zq|VE164FUSza8V{|}ID5DS!9^!!xmc(c@bFDD6(;DURi+%H3hXp<) z8nXd}Kt(|_lcEe5OY)}Arp(`NAk>|Lb$IyZw4trzCat<>+PCJEG=BL++=7w^-m1iO zt-{W1n-b{Ey$$Kjh!C+?t8veDF!5t?X*`?pyu7$--}hY4mc>-iQ2nn+nRIb`E_dI~ zAbzld%aIP)DoO~#MWv1SSO7pfB=bXr_}aU?Y}7Qpq`_@8WU&9SL%#Xujhl=safzvp zmGIj0qD>h)SGPdRyX)iiD9LBye&pI7rg#i2^d`&&A3_x7m@qUHgkEfi9`FVMwb^9L z!o|h=`~40c)5tJ{qut~?e?m`Q2Rb zE9!u8!)0g8tj_a>$IN<;UpI6m#z6MJZ?!QX?o4(~ZCV5H{cT5cCBrKkatkWXmUT`mq@<<*}>bU=f zxQqw<_LtS`I0xbTi(YznB;HA9U}4D74NyD?EA-H5U2`<5{M<-e_c`WVckI3cMf1I0 zwj?Gyi@Sa_@4x?+nu{O-8 zAt7$7cCIy2UP#QdlQq)n6|(8$!6$9q6ey{Qm)JA?K2^X3$29ZCjCC(?F8^`<{^TC~ z(WB|9=a#8AP6-e>{sXTw%Fl|mP8!126cPRJ;v%TbBMbJwWmlb5W&^$(3Ok>knI7Kf zY|ofhGuA&iQDuep#ce>Y+hX5|#7=zDU46uXc**fRrhMFFr$p(mf3M~NGZ*k!{8-ug z@6EfS)2GyHh9HPe5p)0B7k~O3i|{a2eR?B<$mXC#V=B~^P8f)IRk1Ku%5>aG!pW36 z#v5QnK<#^M7|ASQ#a-ESra30zgh!?{Rck~3^QZ|)4HRZ_Fkqsp$lWU8U%*@JL?oJ% zbXwV9G`gh#jp|K){EcObqHXCREByYyy>nm$H2aboJBr{l)(RuMQV>;fV8~VVgeUWs z+34dleg5eB>HXlxnwCo}J#|B{`{gnRQK|V!6izF~@3|NlPAzQEZ=pSas}28WQX)3c ze(>bl)Vx>$QrFQKlUscxrs#*Q^%$V|S2b#|4DFS?Xql}$Axrjb+8RnUno&AmpGIWf zhQK1h`vSG+y;g`_+w=qqjDNmvmk*oj9PFvu1G!|QEXeFNJQ=96zX^b)D;X5Bb&C zMIC{Hrk{Tus2&7?7jRhkEus)zns(~KWI8P(y{G(k4J!-lA^1w9j;5!GesfNpTGDl+ zQ^;z#A*pX{rKhF|*u3N!WTyEgZjJ;kvyd~5u)h)C*d}&srf4Xb5QAuHQwS|{C7I7zu8@-luk z%Gup0S2H3B+NgzrK%`?URnBa=r8GCifB_^us%oFYXXE3ySYjF}Z(n-Zzp5q&qxXBA zAj-V-D!2NS>eh4JJw@+D7djUY!}A zsxMjj<;0n|&)**m0JLD&FnzK2BH0|k1h+q>8;6ZUVaLUjs78ic34~UEUn*%98#ZhFnM6P1;n36k_YZEB=6u+$B-ddt`Z zlbpKgm*<8W%s~>+V4Lib)7o>K%2FEjPg3Tx4DF@TFf&$ubEdj)N_6{)7I19^$)}7% z7Mj#-V8EH5Ce+Wm*bAAHy;BZ}I@}MfKLm<&KN)b-?e`=}NcY0XQ_o&& z={+$^c2g$nH;A6IpN{GdDxv*;jZLTLBewlwOO-vmIG6NrQ$JzO*qtKL5_(Dp9L5$o0{y&X|veI zp`-=%?QxIRa$)K3Qb69d+H&*U=~_CRTzycd#gyuj=bx#gTN_9NE(tCzj65kf;_ZL$ zX2~0I3liYH%wIAX)1`h@h?t-DYiD%4!ETsC8Ee9Ogl@;B_C z)pARKu4uHi5YYN7{J|e3MV+$sX*+8WW##b`hQrQABt*}>7O>-~ zn>l-qnbpKPx#f0xO`!dVveimU0ubunorB8AnD7J{AGhMI&VHQW$MT^ZIBLI_-T3`u z+IH)zm11L#plq(g5xYhkp=t)Pr(MyA1R3_Ve^R*6Zt&M{ zh8rFqYw&nv`>@;pb$4f{u(mdWBhp#!b~527j=w9Xyp-4b=j(daI@7hq+&^EG);|8? zQV|In`Pvw_V`VnBXI`9jvA51J(ggcm22rNRd0k@<{min^PgE$ukZ5+kzw(^X`FxIb zRo{Sjau0}?z;lMU!X=5CA8$4LJCa=Jn%#O&S|z%#q@&oyNZ-5*X7e>$0PKyw zX(A@tCc^Q{+UeL{d+r_QairC+-$r8A-?S|!(fx&M_5>-TcAOSOXT_sAb~=t}M-=XA zfA)(yBpozcM9(&MwEC$zqrv5ZumC>F&&%`B9tzs&i1XUde(mpt$|(aIq3>sV^1T+2*AMN5>BePxYr07}i?g@`l&HJ6 z4uwJ<$Obi2RXvZs3SZ1R?0qi-bk@fu#wSIV%>0hZU<$AObEOn+?*S8mw=I=iCiApb z+v1bL0TZ*UdTL?f|4qn9a2f~*64`A-dX^wFZcO#|3|bGt2~6xnYc8`hS0xkEB$m#z zima0p*f23vJH#b$n5(6d8;U05q1F57g4BR#92&+e~&cKkxs3@1AtEdusJ*9pd< z9W?|td*It2iwul+K;Nrn20G(ViG)#I`304)87M=DR4eFLTc!4MW0*U!)tPLAysy$a zaWIg_QEGLR#2rH`h~7fWcQuO3O6YBMoDLQvG^i1o&Y6mBh!tUfO01UJQldt4N`8!P zpFi9lKNo&vT;&+a^X{+~3hbq#k9gNU%IsYKZ%R`umW_<)CwJw4>(NWIoY-p*E+2-) zJApCwMyu^Ze7p?{V(~90D><3g9NVB7?ua+mJlET#wgq)%+h$8xQ6He1yXKw5Pno+~0trxnCbji`^j{ zoZx*N=x!1SuMQdvR+ft67Q22Rc^zP3RAfn#VwKo%HA*G${PA^&KVVzLv5_^2WCQ(g zGr0f#b3o#PyqShCRqmm6hEd6;+iaSQJT`9hEkVDXQP_{F8A*=;PG2r(`7B}*dh zMEzY!ADopg=kf(bEnCG=q^T<=CP0Q z@GrI62vLI7X>ODrg5<)Yz|U!$U7u5V254dYQIX?FiPm_bfq;)ogF_?yxTs*YAYfHi zEp>Y9d9YlUg#z+EOCD`@xI}((KR=}N7=F@L${hDEB;A;lH$J>qG$|mqBSV#bP)e@* zMW|Jg)1J5A6qPixwR5ls(ljURWfxa?I*VQyFjX)-8-Ax5FT>cT2_<9x#uCQ)<;7I| zkcB7|o*&O2K*Y$|cDLnY0@=2K|t z>nry7xI(K@BH>kGz3^~q`<&ZalysE2likq}A8A?M8-oj<@6kG7&J^164FVsHoob#T zX{#E)t*`5$3sE$y{oUZ)6nX+D&s0*(Xad`^_Bdj!= zfH{#FV-!I$OnU#VeB0S(o0D=$_wweer0_xGi>X+P?gpJ>ArP*I&PMRTycBn07nwLp zV8A7VL|TK@cG=3)Zg$62n%E7&JAK{o8JN*|1D?6Dy$-FCo-Kfh+P1yb7L=_ZT>OdIdN zmzJK~2m8=uo9WC(^-?l(Vf~8AFRk@oIQCAK>|Tcg`@=$x%aF&1%w;06r_HRU-RV|F zHguB(tWfDY{#>^A5}jFqFE@X6Op_!ZH&%EWtO!%_VSSZg^3F0@Fpa0|bIjn@3B|X0 z*aQ-y==UFGb9Ge&$X=-OW-DRmmn*jdop+Cs5#$=tW(&U?z_sSK?A3kKNWP;pCiuyc}ba4Sm*B}Oy@fnUu}pY5(6qifs` z>GeJ4UcER{T!ku@w1w*f> zq44$GOy?JcIUk{iz-&tr(JYkEuF>u4*S98Lx+$7tb~A}8fT?+o-E+?r^^_`Ik}JC)!xo@X4asOHU}J7Kw-chWUhem zyS9V$9e3RzUgh1ml4R)*S^SM+_+~^U6hMzNI0{E@m#p6QH_Vq!Gx+G#-)TSGdZE7| zq|;d+P+r&MetLG;U8sWKl<|Nc18g+94Sfx}fMACV^mme;5D*O-gBeLG?nZtR1*MMT zw5YHqzo-LH>X0N{v?e+XN)0f(5=iR3mwmhaA+@LK^Z=%Va08Y$ycQ z3(6YXHq+IhiQ=j)TTC>Ael$=#PY!+~a%>kjY5gf@S5OkF_(Mo%ML8Ns3ap36JI=IY zlh3RzyZ$p{N#=@Mwm4|=J_^J^nSZN)-O-3u`h5OzcV~}2Md4DFe^F{>91uIPRR5ct zE(oMwr*{xkO)8|x80_}F5tTt80SXp!v_OzjsX)%$kp_2d&YVR8TK{GNl`fDnW6*9s z_SS-7{6p77*O269@)!Cn2l{ByJEC0}5jQT@tL7(k3OZaY=)WZorO-Nhq!guKZQ<^1 zv0Lv%mQ?WHQ?h6)UR65uVX}rS6khfc8}Q8jS29F|H`z8 z7_H0<(6To8fZCX+#QnCYz9McuRl)mYWbAb9y5q757$bq7hk}jwUy@YZ^1Ui14dy^B zgM>flP_=;lyeJbx2BOGZzJ@y&8dB3`k5>jQmW;xQcxkA+;jzwsf1(cP4&r zc@%B&a4%tGBW+NRRH6sA0>l)aGigf`eGJI~$foh-l5d$IpE)d_j1$Gqxev+pfQSgi z3`bfT$?fA<=ZJyr9X5FBnlY{6DBEky8v$M{*r-ViWs)jm)HwBJe^=`?hyZAee1HzY z#f^PHRKP_n*xGv9_It9e{lB5kev)>C$&%w!#3tFHZf0W^4U49#lG)TeVm2u~(7r9V zdRq}6ThsBauffEGs6S_zo7Mt3kokwb)vz_RaQ|Sw)#p!7d0E949)&wf*3%?-VEf!v zIFm~GX_4TAJlHl~)$=CfZ>E6rK$M=s`YBSO5oLy_Ji}O2V2Zi!zzV1(&TOo5b!eDX z^vL9UYX3rIdu*eg2c0UbL3gn7*SVS>*fp-WOmzBHFN>2>=4_8;__l_|Cjq4Bjhnu8 zc|k#UER|H%^tq!j&Ipy%d;uxH)7&r_V~*$(b|YXoi}+%L8DNK^Fq`N+OR$t1gKH@y z>ltKk1>gs8OG+4$RB}iK7hI00(nf$Z4Aygy)Xvb1?w|gVh1(H|X9+L8%U_kL3QU&A zI~$(})B9w@Jl}aY0YNxhmMHozQq=WR6n=%q?p*uVM#VdKq)V=K`FZud6*)yoZLV;RIf$Mns3nDefPrwc`Frf(5sdg^Y;t$c-41 zs1o#`_d~ya(b#)*&C8ZIH=F@(U}3E#0?;Gs9p63LH9PDdp&?{EDT(e#d&k=9dlkj% z(EMNzcxf}$N4EQ`@wat1cZ6cWg&E0g_077OO7!Ts!cTC8Y`z+~3AQev9v<&+EFxJ9 zS=#+u)Xt<#^`_x@sy`C@#bDw6{*R7dGMO zc2@U4o7*x%41+$nNpS^Pz15ouWl%3CUCW>2#^`vC9D8|R^MN6SBs`BClDuKc+4nS! z^Tw$>^OTz6*?1vhx6&yFmm;Y z@|7lnXv>RE8>_-&NnN#gn*Ve@QG3c@xLvu)8XK^bp?reH&kibvvuY#xU6=9V@0mY$ zu_^Ou<3?&7E`wt*3BYD2cVj;Bww}9qz|2rxRUhEl;S0kkp9V~RGo6DU`{Ga@QRk)B zo4M;wNm@_iBtNrSfqB7J4sJgNqJBKoqyq&man@JLT!k7!M$FM7cl>jUg92kFOTi;3 zE03-<$u)pR_X4gW_WI(-Ysa@}7RQkvPxsGD1$9m3m9PSGf}%w4hK_XUK2V?!M1beD znUesk9;3?KIsEtP-@t%I)w8ZL`wl~l(!}zdvMu)q!3?S_Ho*VbK!3%V!ZM-l4_J|4 z=Pyv#eV!yo7=`y==i}$B+&^NISBJJVS!|T#C;+R&mVW@Q1@moWLV$Qm|3SfaoelIe z$j#HOMvBC~_3FT6?CJ3_4vy|bGe!!~XJPqssHoYnX>Rku+?=(Kxk5m-W&l@Qi2W0_ zybG9`vAOnJK5UgASJ`g1(lv-oGpZt|)>0Vg@E}RO0VJ`$dCW8ckKNcek&Ol>UhfSa zrcm5~?g%hHWg5+Ky_;Q`mjK&FNK?z_d<3p95O*BeG@F{y;_^9CVih)L!h`S;(rp>f z)q}+(@w8J|fS5?PLxxiMtQxtWuO|updx4}AYaf^xcnLyBn5lPA{9%e~tSYya;X~Ik z;w*~r|EjS3C9zw@zxic_!p+v1+|97P*VtU-fb~YOOIZmzVbjPBLmjkKL#;kU2sQ!T zLXm)|=}*0PSs!K=C#F?d4Ag$-HycRlVZPjkmw&rX!Al-rcXuOW#|XzUBg1MrQ%Uxj z*rM@yMvdp2J=i82I56VultohY-3e{0ObN0}n`27QRX1xO6yJKc4wbSvb6)&GARO>Z zsSuE*;Gz)+sYCJsaX~(Tn}M-fPRXQ=XiT)3Pz)GtKU9dorB=o%GRR#ytz##dd<`;& zIO8-*OSSljSV^+cMWndBUjB%*Pz$(iZpJ{i%H;GZQCo%(^(Msym+muSz4y6`)dDpU zmfB}AP#nH7O6q{`^uvpgx)A2hOZJOM=vJirIGq|r`-K{u-Ibdq> z6I=PEmeX%&SH)jg2F43;frT0ah4Pn9Im89dm@Gh;z=B`4va#X(qrSm#vZdo-!8%dl z;M25AruNg~&%RO&{jaiwxOvHkK z=4cFLHUpRP1u%s*Uxaf_0VXa;Q$&gTH?!XhsB+3PKoT-PH)E$iW|%Tess-;ks*BmT z6XVNP) z@;UBjToVfAzxgjb#(^2=LF|Dy{`voYXWZ89ykwhe4BaQVQpSKJy= zjVng-3tnlzZ>*TV@88T=gJVZc!vVYh`;X)GQ?oJPO5gjOKbAGU0URDjb^4JizDjzQ zp6~TK#3NU5LV@EzcR+hV|Fr;VPQo%iC&VSn-R;YOcs{TA@IwKAlycWL4N0W^eg<}w zT*S~Se^f6J1Z7vovs?fG2!2M1i#!W!Xan>{eAR~;{ax6 zvJLUfht=i(p1e`{6mE!_F5TauP(yT}^b`~25*I}`p-?R?rLb@~=b7KL)$!R-W2`Oy zquF~PRQlgW(Cyb@>s6F?`B0bDazh-UR#g!TnKYj;&@B5FQ*FEt*otHAEXemZr| zjuFtg;(*fNW&ET+uz9xlyo2X^K!NwnmmLThXH>8h+>QMPuRUuzP(0#0WYLJw#V$hI zvM@lOM+8!>F>xoRLW+V>l5ZEgMd|sLZoRZx1C%&}A+Q|2x7!rYEsoO0pOBB53CcqI z@c4tsoa4-|A|)w;@#Jw*(-!X}kJ1=`Ue`(%{0Z{?@-bKp%pTfm-P_b$G{NmAI3|29 z+_>Usd=&1nb81$u-x|XSmNdh-k^1lRSMs}IAsUWU9)|)mH%4X7FJw}I6Wh)(?*fejP@A&z%)q1HM(h4y~}`)efl4DZ~M>fCM-fr7Zd9~@ZhgmFgK9xaYO zg0wj~fyVtNbQ3869$;|ryw^aTNj6=Va`o>poio^~L}d`H%ZG{lS-8eK{!WvnLd{K1 zg|xQk-ot|#{|}f#&;v}nYVbL6O3pbCBhcqs++X=TZy&bZtvjA3GmKV!7;d;-c;9HU zgZz^6e0WveIcv`}WZ|^l#)fb`iw}K9gJCb6JT{lCOvD#cGAT+bH;%>H5~t3?Ri@VXvUnZ&8y`(ZtQfc9U)n(w}dkv zKYa>~=R|w>J<9?7hny$rMpmcuY2|)V1w=(vD73~;STa;&ZIF$ejMte90hJ0I67|H< z>kGxlRB~=TA!E^FZJU(-Ma3$!nIUuF!2-m}vnrt@*kx67GO-3jr0(hv)so9hfRoGR z$1Sd6s}z;tE)_lYkXst4b}MxT(4>Gj_Bz#n&@sR{%yK`S{Z>hjs(XO$NK zQ!2_+@1j?wHrbpAh__L{3+(EQ)aoAwLuk zP%#Y^y8z!Z5zaAzdEG>dqBjZceOR(;QII-d9g8_QqFtT{E==0Oq+Mu0Zj&7z?L7#u z%Jx1}nyg_YAlMYX*x|Hk-}f_$R1>K60C`5dUjV;BLpcqiR?_tZMR^4#EYj?jeZ9J& z(#6yl6TWQ}J0HMY$@`^@S64I0!lXnwKt8=!@^GH<7uzKgP%6FMAxyD z!Y#tdzA*$C9+rSlxRlSn0D8$C&%3;ZaPhRlT_85>etrCBpU}o&1D855ja#Ter23OQ z{4SA_Zkun3d0Utjr;3hFpq|I|X`aEO{VeR$(}Fcv?9ZL@*Arso)N$bTf92|bM0DZD z>1C5!o>u*Mn;`7ai@A9DIA*^vBi3K)Vbf3e+Qi*!0Jc29%+W6TEB5^`1#MdVj;y6o zW@vAdn}(&1s~|k$(~6jlS?`uLgjm*o@#a{ldD{7HXTL!ub6 z6x6@!^@-VbMt?nS^GROU#G*?Zc08{D1AKsH&2)f}1a!tlcV{QIBL+G+Bg6%?1;XpG zMS6TX9tDo>2QS;~?pJo^n_n$a{2?q6x46Th{rk9`;2L1$eq{q0LdQ6c5nE|k3~x=@ z)|Y6?ja^>W_r4gO0Q)uA54(8Z)UCj!-mw0!u%AE77~dgX!F^6?m$cHB z7yzGDSC_u;rOeEBWGP6MG6`mkL%#$pGk~Q#1$~We+_QQ=X0fd4Y7FN z?1E3%ez3v*25~j7FKP^Koo$>+L3!0s0lRAupUjFIh(+@WUxgSL6Ot*hh3MIj7G&GI zb7_pV;Nyk33U^01Txjs}oh+SJRO9%u0|Htn2_&|66 zL>Muy230`zpnf*wxp_G?1zD_Q#J^H_vq1;|`vh|0x)en~CygL!VbR~Uu#UDyKl1eR zLvMT#5aq!y$;9%H;mq{*ri1Uy3UV~ZG8kv53863;eSW-Y43v^^7-R%y!ax}$;82Q_W)2@SIrHPw?QynkN#6q?9--X3x|z3721+{N zPVaYvN^i3u0fpoXEm1iBQJIV|k{@o*JW17FJ`C-HWaMd|jlTkT;J*-itVg1JMATx- zlu-cYVq65XT7W8Ofw2kGz3w>rxE8%HLpsl422Xx_r3y-5q#G^YECK-*Gkn+oV-*a^ zXKq~!mDvU=$3w#j`&lI7==A?Cd7GLuAgDB&NeBYaa_-cPLbBOr#li|F8k%vzLm z)YRS2DHX%*@Zqk8Q`dIk<^wmt{q71(tm(x&mS=vedNMKQm0`*mIW~SG%gn#6mqq;% zM4u(%WEmW9^XPE=WOH=Cd->-M_ZxgZrw)c5O!3%*MoZ5Xxx^~dR1oIES!)%DlP(B; zt?c~ow~I?%V|$vFX!Hy>a{U>L-{>+?eS+D;@j}(Qb5dp`6Vh1uoWG5`#nKIRf-)4K z9tKNZ;h^la%7srQ6J>sPsdV)hXYUFxn*nUPWIm5O4$-_`SXSf8FxdNn^ue1#6zBzR zX8Ee(3$dCxy_EIRr{wDpr%>5c`N!%MD)W`%BdrX>IGt*{TE&T6L>2Q3{QxRQ^;vVQ>U1PU-t$NGQ-M@mNoX5Jt5^++PrT9IE z%j$ggETKn46=|Q>v4dTAPKzupZA|y_(Rwe+u}5v6J@Hna)~bNe0uq9EetaW>EwhX6 z&`u6eEn*s(Frtx$Bc}b78-_z=W%WC*@$XmSrD;UcARNaE&!|ehujAZ}CNd?F|6E!v zv>!EwkZ=2bg?6WhkJ8{ppHHoL2eaW*CH_5W-tUAQ``lRr&lCTJM3(8()0j}xW`oCz z2~WOX;C5xa)v;F}qMsu2lMm^B`uN*E6dM4a@}IOPDVPiF$Lr|2Etfc5_uG?gcjDSo z0q!gmPZ8(D%@tZ;?l@t2KDRJ2(y&xfzSNL5J!<2Q$K=r5A;gFP6!0)I!sLDu7u7D`dD66W##_%_~ww}c}>Oq;`W!iC{kNZu>{i)+EKnr zD!h9^-@iLj*Lj_Om*xx{AnujV2$4h>gLC9r$_B5n=2qOFBx#v!N5}3)a5L3dqieWE zm;6iq1Q+9{QQ72g3Kn{I+z}IY_TAkCP4w>8_9Xn+J4hbyOR(@kTpzIQy;&Z!p~N}S z7@$3s9TGUVrs#%&QGCg+NR;4kfxnh6EdsByRAk&yK#S3CG zMP(A{M-N`0nWRil{*fsfLxCT3O3buCKte@ofZ?FsmHZ4GcP5994{n@Y^v9vD*_=i( zKqG8R&ATtq7M}nHvUQEeCG>CehUA@%HyJfn*fmhY(`{|+70u8{)B z?#|f0yXSbvv#K+d?{EBNE$}|FNK(Ehg^;W|bv-{hl&3GWucd?Aql1zs)n%R1DimZpp#=%YWzz0#Xh4tS*#H1gm`e_*c`W8x1A-3Oxja}PN zaJT%;G~QrMeAEl&NfuoK-YLpNxi_i>gInmPj<4DZ2WRiTr|y*!YiRW~^?#wxfot}c z5lo{=m3!1e!Qy)}#^tRfB3gwKNJ+3yg;zfwRqaF@=wY7cW`hotW;A9SB4zn4QdbpM zo;VDim)RKcKUC%|)V=$BdWG#3{Bj+D*pjO-z537!{0!X08+2(k6?F!$NtPJb@#LZr zHW$V)hqg?(*i;*!=JPVFK^zonFVktPffT|We{(Mg3225xyHlReRkrlcK1|l=GY?4u z_PyQGv;NqbxdG8+ld2OCNgC6C76EigWj9(S=IP$_@G1apwoO(O)trT6BQN#a8GBx$ zfNwG;xiG5Ik{`lxsHzYee^x-U)zJu4>AP#OJs;%SKv3nvpjMWnSy>7`Hga(O{ckQp z`~I(DVb))XB-P)doriQT^|V&q3$vAf@%bD5gOYQO1+cSMZU@Xe`?o5DEQ-r^pU1a- zuQB!qf%y4qzG^BtSx?U@&s~D)K(@vgwBTF}Nj^IYUt-kB4r>trx`z>6HDE-ZYC-^z zUaTnZY_k^Lrr#f3I}ZI=QDB~zqTMOVD@(%mzHDH{$nz&vPe7Zh%xfr2 z1zw={=%X7Ejcw=Mr@v-D-)Zqke)D6PU2c$NDAPZ ziG{#uF?+$2`?>JG(tIKo^EI}b_+Ds{Hsa^$x0G!MdW{I3ko;A-BkxtUo^HdzdbD?R zK#()q`-oJy`9WZB|NGz{k7ApYp+1UR1iv%i)*<0vn*{J6F{k6D;mm(y>u62yg?W^J zjS!6UL_)WfA@&>g75o(F%FvT!dY{gFj)vnOvf$U;N~zuDFF=2C?ez$lcNNbFnW|ea z?H9f(hPk;9GM@-=wVxisg*y)10ObP%6+?=F>@`RuDOppn7g%%8GqN5MR~~QazbptA zSCsT{E7LyUxuPF|kYxl|OFjBm(=SNj;c+=3!WBU?7Fs7X`}f>Gga7*weiv9prQ%*- z9j|c~smD`bH#$he+L;9oApmXHEE1UaBAT~de(^UWV7b4qVmE^y*@yjDxqn64Xtk}F z^@Ic8Nn-3&Z6VwpB6|5LQS2JQxt<5;q5x6qt$$f9nPL5}Cu`v8|H4haHv^!SzC30L z_?(tXK5$HQYra{sSzmio(7!p%&4pVYM_oCO6Qzu@Iwx!j-~46PpRJDcg-FlFo`#P~ zC~%y_`mEVVD$5uR?S>ay-GPQ}A4I-px#9ns`ur(Ysi0}Q8`2D0mMyNT_%C{CJOo zcmot~A>pxD;Aj#6y0Az-i#0Bf;&x_X!A}P9GLd1*tZy=@H>b(*8vgPv)8|!)^_!2< zxYZR1!EWjDTx`mif9VaoH>;>MKlSDL+@O^l@s^e`H|;jG&b5QZ4DK#Ml6iIN^ARnq zk5{>7e6q|l4dhL{M0Q=V{mv9deV)yWZ7S*h3Eh|!<_eUiGH{&xzjM9H>IC20?<2QV zu5GNz`m|?+)v}xa&61D><1Y{|&*(7G{Ub0t_L)&6vjUX-~{bmn*Qv&+X_VwWr667F~qsEszQVMzlJ6f^r& zL?253 zxzrkZw4_3dYqUQqBK+_N3gp!|%qDNB1Xe8S?e|?o&pHiYw+TN=$|~qd_xngA>`oya zqc^Xh^4PpaZ+&S7&7pD-06v6K8_H;%Hf`wYY0(k|nF^(!6mI>7_mAMsHx&{TU+Y#y ze5vLw7P{nM6`;*0a+sm}T-I6VzOT|&>$`?&*NxICeL2hQuxldZ?Sn$79MErxm)vyo zDX^>*ClvtHCIF;0%uvWU+Fg5~zc-L_rX1WpH|5gdOu+z*bs+G3hg^?;;;IC=rLOJz zb_ z!r_d&b~1SF_;d`M5}{%6Bqk`>T3k{}J-4I+K%H41r}!*WIbxJNPn2H=0jc~NbbYNX zjGebn5?!S|-01DWMG8LZ{mtq6VD$35rq~Txah}5XC;T7>DkW1+7MVgRi9y?w!sc(B z_AVfviGiEYuM81DSV`DlmHG3!hz@*E@+f((&rSIgE%}XjZS7W0wwJP%)$45Qv-% zEdI;bH-JB;PodxGGf*a*j|7k`Y(B4m*;H39ga80X&wf!6AJE{yYdZ3J*0>n7p`l9} zJ8#cg>RPesK-8Q085oeC2OJQSJ}N`;M0OcRB7XtE)bC$omg{Ef3I>gH=f}Hx!gKc; z9wI(}+tlNWRsM4lJUs3k0IbT)aRp{duxF zgo7Y8gZj#oKgx8eL1gi12fBDa^}05N1!SqlQ5fX7^2qV!?O%FQFy3;G-ZJtM;&S%a z9<_lMp7AI%KzJyzAar4s6`Yo0jr#ya3ZBV#hPv~Lx@Z|(zad{m=_(3l=L8IJv+E_@ z1Dp>83EUL4Kchj$p6t*1EG++Iq=-k3kXZ+dG&FfsHy*G(-}vOGOY&+QG(CmmkSrUb zD&t8RxV-<55fMdxul*D)R(+TPVHegvQ~x!#EpYr7db8TP@)tGOy;9+?}@`10h0_i3w* z+}^zsHWriCmJa*Rp<#e$a?%6n_#&;16Z~E_@-7o_z-C+&Nsk+=giT)Ix}|Z9P|scf z&@XD&#rW#XZl$D!N#>kVNuO3mUN|CcPdtR@cf)L;e}i@LSdB}Ml%4lJe07%lSVKKV z%tJl-9)cxALVnPyM>vf{*8E>);?SokofW^j8pc#hfUk@|QZ!cdWBc1xxp!jw{^wsi z-yz#PH5CX;?Hnz6_6$qbUt=wVsx(t;Dr)g~@d~Nfv3XstZ@y(V_@Jk3A3k^&(G{yCHLKyspl%g~G-}O@(fG{XQMX|89-qiAGiur2O8iGEi zH{@oX**~X9h;3^Kp-LEiffqSIt-DIwt8TCLQFwBOHL>>uRk)omBVMg$1o zbhRHG?`@?wdimGX5yCJ7C46m?`5R<-Ejy=T3jV~IDbKu-#IS(ooY;XfGo3G+x&|4}f}-hc=sVnPHkJ+T=GZv<`Q(VvJ0{_t!2M zlEI7j?8BLEemwhpfK66X%EFMQ@JqFyv5I0CU^4zq*V0p|?ok!oa&aMYzzr;<*h#ma zlJ}9M^m8gttMn2g7CX&=1Geaeswo2(OtK*HI)}MOtGTosvu<_IZqyW0GI(I39!KgB zN1f}mtPZp!p>3IG+NdQ089cYjZiR^d*E>9aw}Z+lo@SLN4o^y|vscyT8yp-Z%541U z!(S6|O$&E7-f2Y$a1esfy`%z*nG2eq6H7i#j!&P1^yq#ANbyp#n)5G{R$K7ywr)?u zHpu844;$KGhDo&~0ev;r*%X}cgZFIatBv{4pVM@Yt&+c)qCuzcm8bq`M$0t;87k$k z;A;274Ssb|0TMdF1@M%Ff z;Xyb6^*0s>9bkf?pP1fAuJZFnndJTWpmvs_JEUxk0X018BmB?v1_0^{TEcxt31iuV zF0Y%(f+BibFw!;{zF*7cYe-31Ye~Ck3LDMif+K7^UBqegouK-M8)1<$4wcgfjJ(jB^?V~I!X38wpJF?(- z56`tkS#8Ak&u@Ts%-`f-OJ;Ji_co6IQ9) zBZc45#%?vFfdZPNimQ83QT=c|zQq29sVi~?8{dr&jjRaineg&H3N=QT3g zU7KmF+F4Y7d1dHcqP&v61D44**8Db6*Hw-P?%s=wglDq$CLIg^B~mTU$`Ze=tu6Sh zyu7;ba4$#E*|`v(afGK8iN zor!!7?~O2R>OnN4-kElphLLrdKT&C7@T*aA|8#vcBV&m6@KxOfVTV?_7+c?4r1RFz za*)S%S&Nvvw)J6cZt{!?#?NS}&pDwvvNi`+W*q*u(U*ZlRs6QqQ*>If5vHPu0)pv% zgS2?R>+5Um&))_XwwfWT`~P`t7WxyNxs&Eg^+yr!Xt6*&l(h>dHdSu?5H3~`##Cl_ zR(@`oEE)|kq=22GtcA_r-5d6Q?msooO=@ za}v}E)Hs0apwAkU3}Ta<2|K$1be~gT31Fv<>6Z<0qQwA&3%%wiDc}qqAWkH+nM~iqbBQ!WndPFWsNjc$ z5ly(jZ20x9q|k+)VDH7`LI<{k{I^k}MHyW!b3$OU1ad-;3B;53z@Z4eFmgS#IwWO2 zeVxpl;50^sP<8opv=34^bg~}=H8qB{E8bEWrgLSU|1Egv>xePX7AsJSH(Kxe^YPsn zLj%_8t5t;F?Ytk`^tC1YARnBvDL@x!_&V9J$V5xWoMpelP2Tg*EPf^lKuIG+c`Vl@lLL@^FNfxo3Nn)btaSA3 zU7JR1THr9N1JIzXD4>?Kp4=dsY7F+eOtO3G&+9LWj|Xa~3VD4j0vb!S2Gyv6!**m~ z0s|Ny#sTnekATVB*1Bc}KthzC`*JOm{0uU@wBTH0H(?JEWa1)X+k#2?Fu#)53 zXL}p7fVyCA9d}c{`dk&dQ3iT6VQgI>LS56)z7Y%1d2usbnCKd;O(OhT7$GiNZtyr> z2?z+x{Znd7>LHb_&J&-PGvu@e6dX#B=BeVoT^Eg!q8hs*EoZ02e|58CseWy<8>Gkh zm=ACo#!qh$H|{>q8>9f(B?+fzmD(B*a~blC+s3YWW=?JGYoB~vh(i_zaL2#x&^<4< z#g0>vANCAw-(}H|&T0UTwu}Hq0(X}5YkbC4cGIduYPl7_41O{IT zKpf-EhGXCBBqksdFog<)<|lK(#|{vOj|erlmU;VVjvXOrZ(t&3cigbJfD6rA3X9C| zcN??ZmxYI}RYnh;t3`U@M)(wG*6iR^xU)W^B5|aOYS6qBri76GQEsDa3Ka`|O1)nf zn)u_Jt^AuNrt;47`w7`cT*sFUz>L`OvbNNLnUv)3k$7OxnyTcYuIn#d6F1??B!jpvB_a|yV z4z>js{IisIdfLW_r_hri9dkL~SPacEGe9qAL;M8vA5_;G8F@TG?C5L48 zod{tR?}xzHJw%Uvv%I0e0P4AWzY|sbvy3& zBTIXu9Q&w9W|AM2|5gn=kD5QI)~J^o*Ub(5B3iiV9qb=`zXIQ z74AfN{Q^{lBSM~}3e|7>9=Hy0_T=j=RF(T1!#E+lBDCeR@v+s$K4J+tv4}LNm`!_u zy%Xh43Ux3_T7N+*8S1w`S-n@DHF%}>XQ_G5Q+5n23CZ*21cv(u`|`wD64dJzLWc(6 zas_y};69K#k#K5`RiTCT*#rf6Op%V|dMuo2oJb#?QiR8C$zBHET{STD}ZHnX>&@ zsFXs#yR^?wve#7yH+jw!jiFwZNKa9oh7tGkTL^4QMoyr42;<6e&yGJ8pCOf8HYlJ!7VQ^&O*(tFA8AXZbPgFi6@&MKJ{&VjR4 z+~5nky#oKemgL>ef`cbA`RN?7osqw^3_N6pG~2-?5m zfPVY$2y#Q{oEZwi!Bf{8{C~efHfuEHvA0fpf-;&m7@)LAn$edF#hkfga85-`ox{#f zW=y<58SiHf>@13t+{Mu>Rsafn<$cwE zDO}r)t$pspICN)B^w8Y{jAbMz9;(m*NB2w%S9yGN5$UX|;(myf8?KM*Ta{0@F!2e& z2As=wxG9bSb_Tp*Wn4l#I}y5I+h6$^>!N!O1Ss0;iK2CWfzcK0d;|(n;B{F_k(8>K zHk94Ncu@9K`R1?rs!C;D#gHj2gFg%`^hQ86rgly~bJf zygch1TgihXe6;m1;z(2;%LNOE-jK%6L*1d+i6>gMqsQlt3-*o^)GT**1zR+3=u=2$ zm_kedZMyIIIaN;Oi30%+s4O2->ezq+{8wlk^H*7nR|=U2XgKBoTZ~)s8NqBrvV!=Z z^n4GCNM_vMnO7d2Z8F}0*uxZ6g&hshYG2YTA(? z58Lqn166cIc0MzLfL?=>lHppGOnSy6;)Nc^&?nu02s)!!xI#G{^qOPnR@uKH;HHMmgZb*r;V2fp>54ixoNk@ z?ZW&R?11j&KSvNfyz4*!4gSg_z(8EtEMYOKBKtG}L^Z?DLFlpun#;Dqn{w62ETd(2tY_#3@%S0MEDicnUl)&8NYilzzm-0S4{;kuNTz<%l^te{p_h z3R3HR-xk(bwt3T^Kbll9h!PpOr7#X3aD+GDt|dQa{Q1(mYhm^CbeM%2SgD5*EuieA z3TRD4p9~S-NP<@-^qYAhJ_k$QqTBm!_VM~qH^Ht!gwYq<}2(66w zIZv2XKk=O;w$(;o#L)n$c2R8GNVoN_d77jke3hR51ay&>;g2(z5N< z;ivN_k9i|wlW$X4WOyr3MCc~Dji>}17ytbO6-1_j`qJ~%xlAAes11BINkXuuqZ^S% zW(~d&<m6A02yCs;Xy#>q+9+R86qXW%bVV99)dOYMN;O8~3aLG(> zj6_i3)h8;4df{w>5^wc?4z11>0>5fQjJZKtKs)}@xwdOPBhvbq(;hX(0VKk%PtP-f zE1H4XBydW$fJdCEUAw9P7W%IMdDQ|d%|o&|hdr`mA&iA(9V_lkcw+V{(^Lh5V=3498GU#sr6Z4uOkJ9pqJUPjh|SibrWG^3>T|+C5gT#hGSIU#jko@;J$QAyKBsg~(()P+jasbpcR z(P+wTx!kk3YO!JnxN!@famtV(`*iOx#s(tt2pU`_B0tr} z(l7RJda5C-IxGfI0SkXMs@$`4uz<#?WA2LFN+CA~o7tE(#PlPddj-=eKvAC)Mt{+j zSEyWLu_pBrDri+1e*HaIqHguZN4cqWLWeDcuZw|(6g8`h_zf;1gTh`DT6$_z!14f6 z0JPpX0<|GP>#y5@fUO=gq{?OFhsxq0LE#&@-NhKBB1DqU?+B09MHQ3<1mm` z51nfByoLQ8w9mPL0jG9_QpE|hX&%COf1bDdBm1(1VRoR z^Vf^hnAJtB`EA_!Z6Y?+8N}vON1?_A&DNDajac*1GN4ebrC|eS{z;uNN1Ech3a(1H zM1)3I#+L1Ch`#|(N}kAxZ-Os%(IfbV5;pDW{GtAjB07iBScTSc-_~-Hn}rZ;b6S{T zSnFfQVnxdBQt6|#DuQL~Qb{pVEAf~t?xv&PRj7q3WSD&GnPIG3xHV%x4-P3$Mzbr= zRyx-KzBobayI{EN2ZNYQP%r!mOm^@uC~^)lMV?u267(6+a%zPl1FbuYg57 zOEw5gGc#c6D0MDxQGCSILI-_)N1x1-6y) z)ny{KmEy8u#CY>COmV9{^D>ci@t@S9+QSBz{!}wCq#=tlfP z4uLpHXg4E~n}TpUMj4l7luMszQ;oq^q>(r+r-V2R@~YStW~-q}l}8^N+@_QetyNQ< zP-?mnkBQlv=yLAYn3> z4_#YA;=s?=n1gW`1k@thlZgO|_mM*R^EJFI4N!3~i1 z(@B?u4U$96hWew)RORK->l!BS&HF~&KYlc`*InYRSDA974azjFL{dXl%cRg_l9nny zgVZ!ev8b1*70B`v=jxez3%4!b1i>!=>r*LWcQTWD;%~+;6z1rl)EUMO%2V`)(RN!~ zd(GuN9G#D%j-+$P%+~b{Mvvh^l!@mgk^MRjL6&m*Z|jnB9Ua2cTCF^Ji5;N8En%(M zJvwRU5P#v7Kbjn%$#@FoK+fqnoOI;v+$a&l3zjY5-T)0e>4o2Z>KW3Yiafz^+OM!A zh(npzA}Co}{xad9l00TQ+9+xIgujI~>_B2GTKY_Kls~w(5>9`Vr`PG61(1r~f~yJ= z0)9=wbJUX6CIr;=2e)p;7N+yeagwsfhJXOJN_1tRYwC#=g}?7UT!Ue>weUq&+YDcYN-?K@vXI(NZJRcHB|1pc21ucGzh}=56@>Y}Z%^!Lu}2CutoNgI-5~-^jTii!0%5++wh z;K&M3zR(o0Dzn`&HjQEk2^?$tLo)EKHOeiq#`_rz zIf^M=aK+Hl%??{QD_|^9VXMlLBw988rBIbEY!r$dK71uk#*l*6QYYIy`9YNa z0!l%s&c)y&${Y`(D$ zX%>Bn$l*# z87&_R$0M}LAHnYNFKH_jB2qRbWtMsUTwYDu^86oWbM!-6aZSZIaki4KjrweiP!z`cJc$*b6Sg- zq8HLwJNvs|4EcN;1hv9qzH=njrHRjQ%y{NQSlO@WAFRFN_UIFnB%myHsUcmI+VSqe zfw(7F1I5-&f(2L11vDQ29ccACW;}eQhNHvY#~_q2nq?WoLNFwe7ZVtA-!QBjQl3(D z--T^Avcjb=j;3bL)~!wn8EuhaBENim2cED;HCw7@s>g?rK0@8Mz%jOcufO9F!4wu? z##le{*Zo9oB)lUE9bhs4PcSO7#Kdu#L!aPlooUPQ**Ezn$prz0$Uqc5q|d2{U5r3W zC6x19tHfU$F&R8X4;oKITSQiSmZ3JEk&^Uy)%8@6mnWbuP&p!8wuKtHE&v#i-dH_W z!3E=tsr1&p?PJy{YpD}qycjMs`1n;;0wB^3qvvurQ7IM|mOaX)b_7&nFfT@}fCU`f zN<8&U0-gNluwJh-VJ`+?^++u;wd8%D4|aoUKhDV4RFMVS(yY+;52(3*ok{c6YUo)1 z;65>2_+|EKf(A)5^YIac(x5D-5OzEhx~urA2e4i4G7l(DVIAdOwULdA)d7Y<0MuMP z5Ete^RxslAlcDQ2fsyi8Ef55#+D~G%#p;?dgoOCoQppdT8{nMQY~=~r?)8h&xKV+ zSxJ>&TTF&p@Mutu)Hq{{1Zq^KUlCs?S&{w~Gn*L-eJzP7XWMlqe9ENHZ6;iKfG?fD zCtLk7`bkIzzWmX8T6CaWBfOA5>gOzapz;i-iT*TcNCWWmdZ#1ic?%HCt(=u^siG3S z%(-S&Y7#?{iK0~iaY^WT(=VJ9XjO2Ywffl&-U{TP_^9uJMJ$8pk5gRg^JZj+6dv;< z5}pO^l?h34!`Be~2A^|I-=KMa_pX(4DshufxEm9GDHI;+uU<}%8dHaQVI5o5Wc4)^ zz!ohFe^QdZ5r$c+VF(5ak&fe)7I7$ba^x?d-Th<2Rn-s?@VPN_;U=I)`43O|5S3Ys z`1hJrCKn{-pMM$hn;N|xLuMEJmZlQ!wqw91wt*=UN{+L8v!4*Te*i`rum{cnybUCH zMIDVUXQ&2G2Vq#|j*v>|9+!0G5SjFBR@#SWT6Sn8oHl1zNK|eEHm_oq9v!^Brf0jV zq_pVJQU)&9w9%2t(^1Mbi6?83_Ae_?=+yCtD_UT;O7Lu#P@Hh3W!GhIdL_JVt9YaN z@UFiByk02^SA=MEfIQjI-_U2}=VH9x22B%cUL4kUdOPOg$%Jq39t2nGSZiKVME>pN zS_p$>u{$um+ix_f2MFH0=2-w*f7kYA)4;sdX}!JI$$w-ZAh%V8WRzld1cuz`)Uh;kiQmF`H&M`nB-;lttF*?kVs?qEY#3k9=;j zSsxCXgNXTXX-$n-c-|z@V8i;w;^CoJSwnSQe;qn&|5h&}^!uQ-!G{$zE4Srw{8Z6= zK%x9oV&JVte3HT=i%24BK`W!@ZJYj*L7(|hn7i=n8KVKp%?7M+pg#41X$1saQnWC> zG+a>n!EKf`QzN?a+*?mQwzc^{3d^R2&74dJD+7|z+?>4iTsU*{Sg3yJrrb{3xbad> z4J{6$FVfurhU-_paEE+Mnx_hN?VQH`VUb8ky5DLMM?p5&u!6^hrm;tp8P!kA=4AW- zD0b7_!pjD)Z2Xj=M^PrszkjjYmD>AyYUG~Qw9FByh-4{@Py0fW&791vO-Vb zQvu1DP3$<^h1yK~NXh}u8{FyWU=<+-qxXyHx0{f@9LQO#Tyq9&ePl~JondwHVa+id zXcht4^>CBsLT5Y5n zW{Y_A#G6Kmql4?-c9KOj#It@Du}dR;nR{dhB0mkdP(XyY)LUOw0#Tr6({qc)%M zV{qD$ljsI^nR{NGSJk;EQXnF?<@#mOI=`e&zv&A{NAe!AiK@R$Y##c^o*jX*L;Fn%;;AWx(O>U^G0tCtMf$<_jP zDS!9>?}(+iL5Sfb0OBIJ?>A~A$G~KP_D7eYXGYotCd|2pA{;k4*8HJml;IkbQ@c^Y z)RMl5`^j*cKqUK1y3+SF$)bxK9_kb&q0TRK1sqrJ8{75f`v?boUTJUP6E4mei*)?A zn@n>Zdju)^zZe(maN9*GNS0WX)U)?^*@y$&N}v05+3GyOK(Gf+1`ZQn*fd@g5_mOJ zo1P_Y6p{M~@V&@p^Vku56iCAp`HaNc$>VLJHh@vCz2wUy{P%QX2bODpXjNAkb_Rd3 z5;7=v@zP|8H)riACQJ?NZ+AylDGA6oR|N$L{vO^bsZRpEdR$HEXn9|?0iexb z$|qGttGI`YXTJjr@9a?z%kGD}e9C(Mf8S``0LJXTyyM-I zOe~EZu`$pBY(}%ng6eLFwKesrg!!=uL*BB*zjlmB!Kr~jAreesM;IJCXPpz*1#ygT zqw{w~7Y_p4X44AQaF1SDpo`$5(>T#GzKK#I2zeA7ja6{0HF%7}1msMT4F0Vecf1Iu zEj90}5iuK72C_Tb$DFQ|(f+lbGrh3_C)}xuSQZs> zqV&54Aot?S4Bi_G!usMh3$+AvE1b);G!i``%F0TpSFp4iV{FQK0nB?<7z9d@P*{In znG474DEMSqe9_{1w|3(unE#J|k06rQVuzI1ffwL270P?0WF-mWL{h4KmRE^vVQ-); zP|=+Nq+RP=*HE{aac1}8gHn#!%LK*N!FhgU!4ulp98Qu+ zJ*o=Jg19pw+KCU9wATW7xh|t#6aS}$;I=-91*Sl0h22>?3HC7HD@gVgXhq1kVD5*& z%xxUx08Z1v{|O0+^I8Y+<}3hfD->MQDqUaHL7%M+aXLt3|_2eeR617eC(_sZEPc@+%5{u8*nCL z&Mh)%6f*#k*kFi58)hT`rLWl!I4#<*moUG}!PF!m>N19dM`jK@&Sp4s;w>857%=@o zh%uzjZ0nNpP$oK~u1rC_4CR05vLA-oao|?`Puh*4l7t}jwviu?wN7{1(@z>acky5m z$S#)necKpyO2!3GPI$9}Z}VLUYkeIL+9se^$<#Jvw(RIfA0P}92rZW#`{O+^ZfIJ{ zWY`9)Egb_m#B!>njYH}QE!%t zvm)!HUPJ71Ri8BXFWdYJX;oMaGKvbP1_)PRA^&M=^a}yQlPF|xc{4zzRdtE%)gd&omGLy`?J~NjPXkzOa>HP@l0``w5 zUWpWR{#<5CnVnzOj+sP>Lk>kp(8_*hR}WR#=v-P#dMM-0s)Jy|efrX96*$;h0sI30 z7t$gBMFK`XlsJeBN#ZVYk|M3j{KpQQSVzg}9lPzHT;};sSFHBK5koQ6z|MpzR`eUB(8p?;*LHb0#JS~`pTW}ZWr-@_ zaE{e1y&X0gGqVY6%Y!MigD4QS+8ZyhaVNkH)|GYp)(jpmWBsQL!a`affr5C{*DO#e z7Vq_Z<}DLiK7=n0q7DB3DzP61Q?lUS{g7S@1o8x4q=?4cz-lKo+7Y^K1q+gA-_y{72L1uOhX&jsn zqL4q}5PT-j)Ccd>jO9*h_~sSbQ2j&lEJCDv|JF$HTB)rSC~j>@ew zj937DP~k9;cvJkE=L5CJFo-)E)o1MokI(ere#n~Rd<&&nD4dM+kyb@P{EaNI^otmd zTp)5T%#-gUhK=`M!9e*(W+r(xf)nGzL$2DpyK%S*YUalQ5=!+E5N!<7++NcRIbX5% zMcwZo9Rr557Hg*2NVl$nsxLinKJVMdp3>BWQ`uk>0USDWtql!!i)OS%&LxA{fcRjR zWE?sOnW^0 z2!tB6ETwPV{i<~j5f{2*?j6eVwQ>z$o!SR^4bW;8q|)FFE;H88ib`nZjxF#~3$b-4 zqX%tX-vQq|LKtwb-j9`PZ{s^g-JHpT#YfOosz87FgBu$#qL-3FVShM0hWxzW{^-DJ z#)|RW+nFVU8gv0}bxn3lCRMRtPh;=wp6WIX7_tB%ynnF{ExDug{QStdVD{4b_I=`E zMv?bt5m;}4K=1ROGGOr4<}f;C!CZ~W0A1$WQBhsL2&dNk$d1s;iqVRXICp_q zSUOx3-9cG)^)F9l^} z4_1TR(@d3_E4Y4G@kmZij06$al7>c1)56=3nv4ob!_0wQllgc!SKa@0tJ3321Fy&I z5*Vu8!~%0l`=utqN`1sknwd?-l4zq1njGmz ze4bb{Ve7T8o7vJ8cNU9q=!CIw4xw%WyPSo5h); z>Z)X}TH{gPpfZ))N``9b-8w9+Zyo0NQ)G0!=j^tMOU};y%ajkYI^Lcnwi6zsH!>$f zvnAg3zjHdhNz|ek)o6HSnUUTB?B3u9=GOs`02l3Jw|@N6%}kG9_y~B|4r>T!(sAB? z+T6_-Yds&f<<8F_X*gXuoVgAo(l3rC4T%qEYmPZIqQaOu*Ntd#=mCsz^SAEN*`zyH zzwrb1od*nVZbu{8^((gjwDhlgF!-h{TJiW}Oi=rST{#5cDR5)l*4)@a*)n|ucpcS5 zN)5b(bqrxA55{W(3bJd8zIkZ-{hq}xrD#hX>4ZV4)63qkkSrakc-AA_{fnZ;?0=qA zvag};`algg$cWKRm;D zcc76zz1TA(MejGYf7`%-e$PB6G;+I72QC5$NWd>nB7lrv-XjcmM z?j?d*&uPcOgFOuF;ADA3ZNFdvw_4!flrA~=GwxT`r&(AnAv_Z><-;qu5;tFy#g`1D zX{Fk$;**wQ{n+u^3-b`-=PPO{-r(00%*KZS)AOD93R50*Jg5ueZi zY!+%Z$s&{jFE_MBYm2XzXr->J>G0Iz_f-u-bR%W5p%eE%|FY_r`Q}^)yVVLm#!-Qv zx0(^aFZam8C)z?b{zzDvXyStFutFI9kzzKHck? zjeE}M8MOl@;yXA*Fs6BIRRWI03si=uX5gU@)<{Pk&LlQ00Xn1&Lk`12A*1!AHhjV+ zc=#+O^MRE55j^*5EU}frI`)mW4H`&MjcsG!1>w3lp2s@85g|TlIxZ}yoBJOnqpLWT zL@fX?NaQ#&t{(|f)%bdEU`qGC+9L^&iJLM&ObY#Hsb3ql{C;(vsJkUP(j&?6EGeJ) zySd6mo(2WvYFnU3o1c`g+en9UNR97?;tIBNIc`|6?i zd_P#hamotSME;tJFI{vKv_Hzir&zAF+Zia3N!~nfH|+k=J%YO?APj!SSEC*21ks&R z>uxn{f>A6JM@`2R@ub&`Z2Hx4qRkKYPBn5j!yY7ytiGxlCP7&3h3T5LU-uy!o9pe2 zFGuxZG=C$b)K457k3ga0w@JN;uztPW3#tD`!3!P)mu5YL2CsYH`my{$ZCkNs`I2A! z1dA4u3Z@i%kE@cjV3&`AR>h7??9eX}?lSV7SpSbz;^ckxUeJa#uXun;#GCmgpLgfo z_oT8~QO4iryIBeU13z?4=EzuZom=4|?%GZ_5h&?`dpB3hOXw(xn#Vl9?tQ?`3{luj z_~Dvu_*p|+Z)x)RDzZ_s2D)#MxVdSEZ*`B<{HwPcI-l0BVPV_154^93u5ZVczp1u3zX^W zzjQeDd>-TT26;jE8KSH7Y9^fHiZGyr;ju3zuy}_X%-jEamNQuQVY(^k`4n1^D=^Vn z|5}+R2cEq*o&UXt%qP-p7Kgl_Q-;~V!bcSYOVQnl5MwUrPujzGgd$}cpXQ&d zHK<7Tr+!mcVFV@ccw+E5fupqw*Sl`ze#7<}pTT4j?Gmtc6^zq>|LAUmKYH%2erVHk z2LRd5)&YXOd=%j=jcpzcEZ$IMy&d5(HToX9;NW(@_oewDAhqq~-KUleS`;SH_#KT0 z!{``hPm_GV2i&iUC1bunu+tx#KF_@BjT})EAKYGhCz1#_v6wc10%*(&4%@H8!V&gP z+!VhWW{|YtPQA{@{ezio*#fMm29`n)b)NkI{7T5_rVN2cI%95@Ez3*C8C5Z^*cfYm z2+iyKS$p{1Cy*`o^K^6LmdQ`ivNgv!52*m@K^Au!rS(dT*t`$PTKTDe?-L-hM#qb0 z!eyy`xWbE+P2&p>a=SKmzE*rwhY3RK%BRmDaM$l`o^s`mfeRp^S2Z#1-Ch=)&X6PC z3qRqRN}<2aA~co+_osH#M1tRClbfDh!4%ZG_*$$4+^(WWs+dEQgN*Jsqn~ba>IGPX z*}~0=HKLHWy*vj(Tl~H|Ba~iT_AOmQuV$JT?%}U&id@Cth%f;xAV93X_fylxTl;w1 zv2~8|vK*hxp`uZSq|vzaWdQVcZQ`7B!TdH0YO@Hl3HRr;Xy*vWb|b-V6vlHm>&=+gtayn{^Qkiuacx;GVYA+WYy_;2U?j3Hr8}SG zK3}c5g-U1lzJUvUq%2T44(G?*^P9qh)0^&PgS+S)89XDdG4_9IXc{RLNuIHMW;7NPd|IK!Q*7V9fdFB^M$rwNbNVPK)UyRX$S^|pj? zN*aPk3<0IpMNM^i6Do7(r|xpX5|;1X!}Qms22a&|n>C5)SYy@gF16F+%;g{eCye8FndcVhI@J-(uN>At%Upk5gH4H2& zD%La1LO08|zJo!76jbzxARqNe@?hBpSqA#%dC4qp2)o~1@!X2gh%{4yA-lGcDK){11Dbzp#)|7zL*P5PP z^zN5|j@El%4{ovp*&9Pvxx<4TxF6a1bn z*46WZ{!EXlKwAuB1}DB0m|wM?96kNoh24tSf;E40k#?;p-f|SalOmgY{~DB5G##O= zOh2&ms6cbbCK;mf%d$wV`GCIImA=+e6K0S5lm$qU!1?0l;D&Bchi3wq@#}N3&twIedd6x0Fg#d*J!@ud@w;PMdFjVE;PYgLh*|=R0gfN%ekt^R z4`L^zTF>EODJ~$-Ozv}>S8%KxxPl0up5O;RONX(2kT8O|@SZsbKmWWt+C zGW@8V5y2RPwYiG*?fIA;QlOdgG5k${3&_9SqIZN_&06sVk(1C zH`~~=4k-Ii!OCo==MQ_c8>of)rTTphkrxs*O$!JMTfWl}j@I*ezwzRcYw~SNXf|y% zBBFyRgqpnwln+)iSb?0V6K`fJ{@Q+i4~zclirM1#G^zq3SXB}A8kRK!F10Pu^hyutNqsHTv2c`=IXnjrxB2A4aES(+dUa)LLk@7yFi$ zs%f?&`tHwb%*Jk$*5@Zty${Nv)UAAJoGRM@06Yf(UYUsHukF?#SZY=yScz1RkhiA3 zU#>KK?{ceu8G{{l`AbqL`o&o6oq^~0m)*Z-;yt&blV=n8r_J^$495@a2kvnLDq_dnO0r@w;{%b#qxZ20DjZqQ<}+LYMv+ zHGNdAeI3JDefSd@yv)E`K9WS|Qr+&rlls$vN~r5vajN~1YN`8?PBw^*Z|RhTPS~y> z@6aPiaXPo33$%2!L?kZ&UJa z&AGim3ZtuFIHYF?Y#5gNH=u~qDoby3PfW6H`1^BHdaj^uAg=Jvq$nese>my(s+gNS z3X}cXKz9JyX;Mz1sk}lF-rQ=+At9IUA2ueN!vLmtgszIIVkZ^8qFt(HOThYB`-4pM zc1=~5A$V`nam1MR{4GWyja( z(`WEFxkW=jO^+w0SL{K#HPy4!BOhuZL6&8aZTw#|Fa`t8qBY;_*=#5bdY&{5{}hPC zCt1NdIEhY~Y7lIzr8)-YJ7FHXa~SfY+&3@LA|6Dl9u2?T!$ePhb|!g5;@l73Gc{O_ z2u|@i?HWonpfdAo?haQ>?|qCg9e4?~#!B^k{Lp(k?+LmSk!oPR*%yA@K@k~e!^`^p zqmN-6wRs@s$!men7XL#1>p#xx-DagX7B8-D;qET{-|F$yLYlq4KYUfHWY+_SI*-JN zOU^6pCdffUpSXsFB!7M>kK57Lj4)lt-z#ua`Kh*5oaPam!Ef{==%AKxt<4hki_UR(nnaI zbintvr0c`jwc@+2;ly!>PNyL$OdXqhVF7i zjde_NXrhmQ5DZQ{HQK6dh+C}!){nS_;B}_hHy+v21N6k~ocBIXf5eLb0`AOil@jZ8 z-={kN!C-H=BD8FM0Bd^w*)Z~3qd^W(9+2)GgX2Tn@Ur~nZHcKTTj;sN{?})!kiv3( za%HRYw;|v3nn0Son|#SdQpM>FEA>@n?Qf?&dVA3;KI=gD1N_gSEd?g!lM{jB^54g> zQ5Tycj$cd+sBu$pq{&dq1p?3b!zX~!VjHxmf+kiVZ$lWz`(nTmRJ=1d!+eq)%q61AEELRs*{g7S{e+cC7i76&7aht_fS8p)H=awPd8m zmiH!)%{s@R(EICC+qs&bMEAS>iT0eBN8`)eWE&C;8eUqNj6Y0VVBR=|N(~FKGGpM9BB+W4R^$A; z??Dp?cFRJ?=vbG^&rMrt3FS?8Z3Z6Mz2`6JKIZ*9*E;(@h+@ z5FQK*5lcv~ycV2vx4`y)x`tYa705)w`9)z& zAdigoF-%dqaw{sLTU)o=Jv*+3Jy|Kf1!3R?z+k_!&akhWjjqVWVI*x%=!l?-$Kh zQcxm-buk1;0lQfX&U#}`(*30;E21_L40Y1diA;lGU~rQ3>7-pUj|iX?%kV)1$MN=j zdl+H5dcQ&654DJ*tXC+|0UL8%BPrp{@AI9CvE%Kh@2_#cx{r@g>0|RYD_=k(>{gga z3X)m7wuWLrCBD@rs=4h%22Srywr)}=3}9~LY8^{dxhBQ(Qdhd!0RPqbVs21yflZTy zcp~I{GzDW(4iz-3e#$k`g%c8j)3&c>IuEyXPyW;ZFB( zDj|3}GfC=Z+*-XOo<`O|(i0$~&&agX@EM2q(}>WaPK$tqHEFbJ=%*8HutBA|si6{m z&x>3Qd8)$w&hls0t}gkr0`thY`wj}QlWbnw5}T!z&fOUGFMi-xF|Y#4hOs)zTUjs= zx6gAhXqZKkW%}_OhXgXCqHCuJP~)3K?J&H?0)s(~=YKUyBV%wMOZJDDT>@ zx3$-548NzIEmOh2*%kXQo8LZql~2hHD~S_Dy&cS?_8qv3G5%{f(@Mt-EhCTIHP>U0 zEBy^Zr`G>J`3BcAz50g?IcWhiqRtY~?j<)mX*_nK64rSR5SPu>5{}XDnZbwMttF5F3cG0+-#)@vjc)$Ctx+(xV!l z98;X^kvPy+bUO68aehH#*RuA8MtGp0IPG8F1} zh4&D??HB8@z0OFDxGzyqbk+k$`eBGIc?e$rS1z=fUG6V%K=<+5l$Hg=GjR-7QAiPV z>g7vIqx9(*!(c3&GI)NMrlaf@%QM>1*oj=iePQrqM3+MMgH<5RAsY92yY*_@l>ooP zxZmxxetWFY=Zel~Atc=*?;i6RQv~}1^U+!4_uG9wBGY@eSjQSwtO3R5CGL{r$i%Tf2h%;0P?MDg0XZ1xub z>GG^td(omcd(2z|V=zgjrt~5F&%eb_WC#(=fr}_o2Oy-w=7Mz=4GW;&Rh@Yog$7Ui zrAwzYbaGvskB%N$49AO2dK3L|9!nIKb(Bg`M}x%MG|J}aD*aJL&*yZ9coX)A8Sf35 z@pIO1!YuHGGnN0UBdT};kUn4j(06OIUrP1HCA%7oGy~{D#S*yvX4aYzBqXIjX5Z$Q zEs4AfhJou3_RUZYEHGtBw!b%^PADFB%X2>MFWhh8u3FF0QkbsxT7(=R4d}x{=O#sk zo3zb+l@PKv2@x+=L@h1SVkEMhsM6zI1GBlTo*dCAb?@<_1&x9Lq&67pp1Dh;a5~V7 zcBQUzf9`ER9C;~e)blt%DRc+tGqWgF1v8up;%!)l?>}y2YnoIS=w})#Q?pI2-7Sx8 zp;ilMIuJy(Dpcul+Wz7ACSs*#kLQ9Um@GBjk@&ft3Y@^ElZgMU z2BN2qg?dUpm}G{H+v+rPeN*Z0HjMWd?NU)y zta7uMiASi)xFO!(1D5>`o>~v5eKVN6FB#!q*oi%#l7Y6R3;neCITpsF$8$E@9HTQ9 zAR{7R^<@D^Bc(7LGZmKHT4)6CAuqUXFcn55qW zoS{n%op7*7dTGw5Q*qOT055cy^UeLy0rz&EIDC5UnO2TT@^bi+O1no&Q{v_1VnE2$ zp5xTEzl8Qh1Y+xo16bRo@r-zM(2nXUq_|?==vO?m>#1ScUWkBz`dagW`~M2gKmy$? z=oE$%5=82#1yO+2Lz+?9um;Yz<8?QF3H?vts{BpEe_+eb@n5A$(Jf~v$ecf9ex9iX z<79HNj{^%fyui$RyGFsZsQ@nm__nbcb_v$ey&j?23@#{oe@vSTB8m!o0I_p=0+)TB zKlhjX{uzH93fW7+4>0wd(*e8>aXfn5pk|6{(2FN3N*!J*-=Go#nBMVoX+_#w`ic_$01W-&V5a%0I3Rn<=Oucqi z5B>eEa8okfsKCQ2>>Zv;J|pIK1X;gb!a{3FEy9CuzK3ML{QS5=akx6ylhO)`XXL)` z4l7cUjCvr*GJuiBL7Lv)neS1bYR&oaPno{2`x}#SW0!UVIJWA4`)m7ru7-*VR}sZe zLN&ISthSj0cla-Ike4U>cP&)GM=Ap4VQ`g9()f|8pK@s&|!Q=_SmbI=FKV0@I{TvQ-FbyF6nH(?#O;bW3W z%s>A|p@_K{>;<0yNME{1!kiDkxBFwi36Slp`?e0F@#LMy#JL?Qys_&;>|GI)(4X)2 zK8R?`G|tX-N9|l>Ne?p9lwe~`2X3_wcN=LL9=R<}7e-7T2B#tU+G6n zoEzI|Y&3S7#zte?jnUY)Z8nXaG`4M{v2A|OyVmyu?mFk5=bV{6Gkf+db^o9|2xvoO z(mf}|a^v_TZa*ky&StleJKgn*4FDyIL_{QWv+}P2lnoP^3Ni`^tAhGStwSU>-CK~l z-{IXKd|_4K6X?I|Q>q4NU7)I(L;7IpwXPap!b_Q9Q#D9Ki?ngFwc2r!&Gkl5Ze%q& z5*a$%|I+|TLKB^GUYH(k8n&+9f)O~VnuQjY{?{?Hnm{Px`->sv)6omA4kPj13tZ+s zjA+Y1)(PIsPj)6E<39q!okuit9PPw;8ov5_aomK41(AYZ9QvgDhShLGlhaViC-GL- zJvfo?3076x385OpMS)7`?NPn9o7p=u1e);)+9yx%r!eF zw<7)@;Vt36r%G3x674Va9K0{=&-s{B?W825fn}OwkvQFN9Ajx+9xI}7+QJ~j(59mf zBQBjss3NbYlQpbhbEC<3jqJnE;gTC|%c_@H{1tGKMteVe?Ck}lWX>L^YNY7|yhk!~S$@56~p=w6|0KFDod|S@H!E46=m<_adNetIGY^ORkk);$xo{RoWj@ zuJyXYKIW$ye|7sCgqFu={E+Q4VfEXcPv>1DUszQ4E#%FLpC4-1^dRNsv+7s(HNMi+ zLytS`?*Sj!G^Q1dyFpQ}NI_V=U*MxOoQ;z7`sa)?_O3DR8_Y=7XkwnxPKYAk4VyEq5S??KKb#Dm>AbQl`35TdVBivCD z7Gs4xc}zp=C|wQ|R~=}`{DTwU^4hcDG%dBfZ^Kb|M4u~|#Vp*1zQIZA-J6;GW%SVJ z-H;&=sU4%Uoc45HmjayBv^G`i|HbB zqiCDqqJqZ53@;r=*s32D?~6wH`aos%F@?=p7ZKYB5p55<}M86X$*pyq<|F=-^x_vzi@Q|qQ5)W%b0uj6s-*w)3x(^U-B1K zwJj_(PgJw*8P}pem?V4z6Yf!16K(n)AzBVe*4nUxX*kIVmo`=-UpWTb^{kxc2G8Gd zx*FW=s*_lg;rVrkOX!zRZuG$j%-oV0WKJR_wcE7U!sH!V?n{K{e*d~k(I{)2I1Bj!XH9e z-}>Q^j@a*PLmFia-?b^tKb=HXP#OM`Q*jtPjfBpsz;k?k{}~;+nPxTy9Wj1%c6RCm z1LK;!0+fNI2;AVV3imE5g~O(3C-;z6zV~bk_$cAu7OgjV- z7tPd8Sg{W-Ti=+C%sUg}{CAt&ttI_hY(>XD|KLu>?Ht`l^-vjuz_UBe@*_rQ>GLub znF$bSA?m2Mq3tkGKD|P|;b2O}4h~b*854$~&T-S*aH1Ko2f>G_wcho&7T49 zLAUg;1=wENgu8&&vjG@|&I7k~i%{(;-9!K^$GyDJ5L?DJlgMJ%konXQR$Hp)Q)A!I zj2v|-p|ywCm;d4vWecnIw`f{yMk;**b90lJm3~~2xUoc=(>zvw$wqEoqS7PoU);bW zMIO2?49bV;Vk3;?D+^)6M{AG}$tp6~OExq`ttAT^p;=q8Lw;2uM31JDNT~q*Eq3AS zD*g;mKZu>hHnRzgpu%z#2Dz3xrd%1}PISLe3cl00!WnvB7r-;+KyI}o*C~XyzhBbd zSubI(Rif4x#tZ_Cn|J!bp9<~wVUBzY zC5q)p$N&oP>Y}BGU9|f#e5?m{z-X;)`mPAw8kN`3ZLG0TbQ1iw;db&0o_}HbmGW^> zZ8XMc30>9f88;=GAGL9$t`BGdAylV>&v)n^Zk|wnnJigU^p3qWb^{^%*a6~&FvM!Nx^N^A&fkI zrk|?2XSw1*mO{ndf4O-1te1Uir{2G38h!YRI`fyqt(_B;M}*{$ValAu5d?7eIp8h- z!cM6S-LFPF^9nTDS2vPfVRlI|Ieg`3HRW@#Z>stOq!3>Rmmki^i*6Z_YVT|^o)m(O z57O#5+IN!*!ef6U57m-OzD(m^$Jc5Is4VVGL=$e48`h*CfREoAFPe~Hzpy}PJJ^nX z4~3Am$b&jw0C&xD|DH?u3SkMMC5GUD$#K8O3%R?oo#CEUf}Wm{jrcSUPa+T$Eu_I0 z!q9gSe3i`Ay)D_V{ZZAsnk$~94P_Vs*TZju%P-uj)3@1F3e9IFuFyr}=Y>x{)CM{v@<{0tIy7rN%XMS}L>vew6p2C{i_ zhX&xlGwje!#3;ki3icJNl7HkC3``6q#Gv7U36;#=y|7e{MnxW(4JIMc4C|x^EOj4= zh}{^bknAgSVU3EsSH1k>4kHODQR^wop5{b!5CNlRr+WS7L(AU;uePPPdqXV#XZXj@ z?7MW-I68cBZ1{`!V)m6a4g}j+ID#?UE9sCg)r#X|@U1QZJUvR$5BW6+dW~OvUTkB% zYYp!Rg_zxpraZ?br&+AsZ>U9qtWhSc8-$xfio}jRw;3E@GpWBdwOSvjMnCmM9Eflj z6R;9b)V9n-73HztdWnS2H?0V>rGA4>Ywb}%+C&#SXl4I^ha+ORImEEC84Df!!5F|^JdF=A5(NPTG6K$qFYW3t74 zF>zrOfMI2dzqP*@Q(3g-`!A0@AyQaIpc`YO34v zV1-IIG!>^O(Y!}&YBf<-F|=~*UyQoY=`EVwr(^UYxJaqo*(C-xstOV>(xW$t+`DPd z=qG%*78MlR$nANX%IplK#v5VUe0a2`f!KSeyZxis4+InJ*0RaBkNEpN`^YvECt^48_ly&=7cyS5pmP8wtH&(8ja{}I6$4)94`N0rIGjWQz6S{(6Y{{`&Mi#4ub&$>+nIFh`g=CH5SjI~U=Q&K4EQLB& zSA;aXkTTi4h&O~iq}IF5o<=T>SPZ0oKzuZ+|2qU5lr&?>>LZFGG< zMg~qh_nDU5(w!uW{`H^~xw*#=t@!E; zF$vB03Q^manJv2(4`tvN!6c4^3~{oXfJAFNiTLe_tg~TDd7-Y?;mk-$s`^55H#yvM zx+A;ao!H2L+oKKK9t-J&6Ngyr_ENKcSgR2F-aQ)k1|;c%J-5XI#11{#OjZz!gQqfU zX&ply#HV%aJhZ?EYw%27B;m_|MBJ3A#Z-e*?8%-o^hq*$pQlTW!9DZ@Z3Yr3eUF{% z_SF%7?hp5&%+>Z(G43h4&RYlX3fi9r3ck#m8QWu)zTNMsM(@(O9KKjPsYr@rJ&D|^ z(1R)P<60w{Q(t!dp#Jcp3KwJLXh17e2V}rLkM^e>LKu^*!4nXu?XfJ`yoN`2sLH>wb)go+&*G(iv?7C7@tKM)KkVEf#c*KFI+Qj~v;FSj2$Z@i>rx=dkimuv^O zb@eTGZkVj`5j?&zK1{^})dZyf{(?=I)K>ELOWnb&7K3dR^U@LuGY8ceAzR{Y3eGc2 zN9Q1pnqVk3_lISVUwHaafsx=Z$@vzdO|tN2m3*y)sz8>b+C7Ik(-uxYSR6*JG2K&Q zQINliz7E6NVE;Bsz;)gx<)3@d;H2q#LH^G;{HDYw6|k)? zL^|-KdXjH#kwdFKQpN+0okr!O!v3i$MbRNgeuVJGg6?X6IR)r>1MD5S1R;f22g#M> zvk2sKUVpOBmp`!mteL_Cvei)`S|dJNm$zvYW_LCxhsmKAy;COEr><^9e{FcV>ihm# z*#4KjMU~>fgS$1>ApaL=%BT*B6Kd9Loxe{ENh%hV@uS95^ix1LH)!9`nGI_Y5N@U4 z8<>|uj5!u@C%iLM(IaCB#wt*J-;P8Z6r@AY8--WOU#^Z1@AgPMWo(+un`W-?!@cpj z$zm~?MHNF0P3*V60j4#Fgc}FlTm=|(c?(Imb)HXEQ&%K03(7ott>Q3{#87>UWwrL& zV+naY>sQbW)+IbCIrjgcoFW^~fG}9jc1VPoP|?5y%K_uQh6z;D zby&K_!Cy;$1rtH=FVb_zmaEC)aA65l)b;X8LYyPAA{c?zXio_ICe{7g1wU@F$dG!Q z$1;D`y;-C7lvSBlT=~3FPt6Yz4c5*n^Eo)G34Y_WtF4N3p0bTauTSE z6}Su6Jt!Q50x;kX8ze=NR84q;FQGGvVLfrQ4e^)K`67Q5cw3YKfrGO`_IZU4odP{t z(*B@YX}Uk^r%5oc(+;Ao(}O2gdJ0V(0|>600}qEpSHiza0OOe{{$JEX7v<)0kw`0pqEB~GMe}Z#{>6p(cGc`(md=wRxxV1$@PVV1E z1X7HAg}mFfT3A}94073$8#-*2GXmI$uR$%AZVp4tG#G}^buegtAgD6AJZv{N1gtvc zonJDdU$1GXv&YAE+{90Q91S~u^m6dGyu062eoK-FS#JEW1cU}?8|yX|uEr@Lx^bge zBv~Y=h2&yb7F**+doA>nkx;%5R;A_^>*0$?2G3-~h>dADe(c|U)sGkzHjR2uU{vB+ zZg!_e@i|VE;!r0I5*%Uy*d06E5XM(Zc)Y0$hda&fsa3@tDj2Un;`~FqUMxAkc`yOV zU-ePga}i-s(IHysui0QVU>}T_O8n37Om&aRI8vrg?Kji94UGJOY}MScI|euFn#*tf zkidjmMWB1V(0JOT9sRr{pB26SV^cf4m$%f~hacGQgSM^PBl2irAQ0qACKGN3G;AOW z|G-}#s&C%ty^*OZa&pM{R?Qz9Lk{$#{P#!pR<)_NjidVbbJ+**@lR~}%U({npwiGQGv3pCUFvvU;CkiK`hR-@X zU4Y0aorq4tELuO4RdoHfN~N2|nV6IYP!&I~2;>6!a8 zk4wiBX7&5R=fuwKWC80>b!Da)w1rbltyRgxHSYOL>;B16pL&AEV?;n^JV@ zdF=C3A)%LhQMXef&rNhhYWZsTeG2A^ISQTisX7ul%p=q&v;T3N?riiFsv03lDMxQ- zc&TF8>Ed>K-QAWrd!^H5JEQ;TQC6tND^UuVNVQH&TiO#Bz6b8{VKe_Vrq_!jixK`$ zIo${U=Ro*Uf@SdeRA(>1F{Vz&s}{Bc6Zjr&2N-H@ssDUaOU63=KW|FL$=<8h;V{Yp z@dek}o81w`A)fdtgN|kcltJ`i84*28$KJTq3=++J&gjuwM0RQ^s$D!AD%N-`KS7fo z{hj<)iaKSoHRv*BQuqg!rbKv*%F4`WI-S}#GVEq1gP|)T#}2v z5;^=NvARlVB zq;$0T;wJQS6a$fzQZKGxIvJ2Ek6jbE4sHKe=-XT1q^4}C^PaZj;DCv~@RKu@CtHXH z1$=L{b-D2ZFh~y|oUU_Tm?qWIvdZXH0dc@Cgm3Rp3*11 zyvB7ZTxQe*3@T>54bDL=CB46=q)p#$l^xGFqR&4Vt`;mk6Te7=dvB@6iA(%)O*l_u z%d!xNM%~qi@qaR4!LANR{I1XTDzl4GNyhb&!{MUV9GG`Um@B%Dx9491jC-FMpbN!Atxq?p%!TB=l2@|6fa zcXsGou~wcZg*;q$`}!m_zi)2Ejh6iO@-b#F)$y+?Hiww*+Be-f!4;}9pdaw*j=>?? ztyt0tMg95qEut4+h-wI$>yuDdCWS;5#+Y54AV4;SB(uck!$`#l4(@aT&X+}v+s-+Co^^(LwLi*Il$-fL z*zJi&FOdVkY!wOQ6D~iv-j39ypSbMx`#?clsN^0p)%LW$cUM#o1aIiWK)OL+b`&J!oW4I+UxjN z4Uf$UKm`iWT#6fQE+~u>euP+)r9c|^;LRj%BL*X-sO-3QZ{`gAPdoEo2gZ6`Scye8G(5uJ0L-L?4<@bU)5W_U*xO!Slfl! z-R4x@c9`}^5cNDd8Fz2F4;2u?m>92K{ zb8w3|!TAA%e6K=Zcay+_jb7*tq-UXDjS|`LLCcFbvEjh}(sT{Z<>nRHuG}$FCSv=A;&x&0#v85n6byQyPOBpKHq<7wHZTHf#-v z6p@gD$&J6cfnX$1C4f7k6nkj6p@A}eOIAm72l;==L=&vk zDKdY?PtjeMH^p51e#M?i)J7cCJ+-IdaBPLUqHJO^h3t$uyV~aGUOrii0S0XXU*ojl zlJkDe1!Cnf*(rqaasBTL1pw4ElZ3VN4`J>DBI*nUMf@+1CmFG+WY;qh*te*!axZ)o z(eQOWzrS*2BtG@7(y@-lp+_^FDx}~#lf@ADt{OpJ*Z!&N7dIs1W0}I$MjC|t2PXQB!lIuXpOM@c5f{Fg{;Wvv9$z9 ziA3s1;20LmveB4h3_VEuJ0r<=d!z%%ppbhylz4f?Pkil9x0Ua;an|js3@x%C=9;VB z@w54D$kq#6=Oa#+oT)SDd$tfXI1pC7aJEY>&B_2lf}>4#l0@jxy&EOG%GG5gww zRsMCmoua;lZEbLPGuzttKylKuZw*Axww!ZCQ~RN6^(9V;X97`@7)bCdF~-c!Cc@_F z(bnGq0kO|Wv5GiVMjCD&JE()cjr(!X^=doyGo2(+Oj1mPuI{whocnN4CQeDq&S4h? zg40nRw3bCN2QlE^5p>@=AtSyEP5ahu?z}~GQcR}gPBTS~diZbfT_U4CUE6W3|YZxe}r41qTzy;FO{*?q#1ZFS!Wr45OTX+ za|f|~ZBHoieNx?F7Nz5}EaP4dT^Oa3qD^mrFTH~JlfurlehW4A_C%m2DkG*rJ6C&! zSXas1P%d9sT+9Ltx@nOTFs+dyRBJe}i99LGXXOpJqfqP+Uz$}N*X~S#?R<)r+}|yk z1A<8wRz{nrV?-cgbv)00@~?dAe4DmW5r<(JWcHnKXJ|8FBp`NA7$gQKEuOG`$oE|n z2WkpMmxfU`Uvlm2h7A6s${ca;ls)}Y|bE9KsLB=(KWZIYrR z_jJuC&y33dWj%0mf*^%M5>p_xU@1iy3^Y-P`(Yo^02!FX%QLb}=ZVNZUc<%=2IBZp zZ0_3(0u9&C%Cof_)^uTd-WWjkAu@M#*?NCcug-?Ko!V%P?K?CifCX=^NSfbfhGsFk5Kre*=)zeD2$BABSD6{2sKoJ&6Q>GqjVuFdrm|6y#suvxUj@9}df>NauPmf6FAb^L&@?hhhPLe9& z4!*EM1AN_GXuTcxlqe*PS9l2VhcgOfk)4{!_TFkQ$ zO2t43_pM1ZzIiNcAB)rfG__FZcNE7}npKN8CQnFN7^ymZj7LXUM(TJw_sN=t#wxt`?B{7wXoe_{?xmfvsc?`*WD+EuMeqoQLX z3t9w8&}V>IW*JUM-4S|F&7gG$~o1NoX(aXFx2f7`(Ul<5+!hV-F0(7Knu z4qw#$kmUZQYXGJR)h}2~h^XJ(?1FLh_5)L1an@EDG(jFMk{ab?MMbQ<|79(ACWt@3 z{518v=O6aVtwoNR&Ff%(+1X=y_4<*jhPC(v}=Lct?AB2RXvo;S>vmEmLj zc1w%Ww^%|%5o26*s7xP=wonGNl8Qj4586Wu(M?_8#~i7_>T zE^)i_Fqw!89dva-%Gjy6Ktl?3Em`D!|QT;Cg6$=zv<^am(v z(W3IP9xba%^w*I_Lza#L&{wG>|O?>Kf2Y$#+}W z0kZj6w3ULBt`E$0=6rf|(4YdX;2Jf#jKqFi$PM$Xk^RdLz$1E)E)-;wXwb%>s*TZ1 zNerJGm>A@dzlhCjh}I;COK@jz=5@#ni9wP`V;e-RVPi z)4V!^7dN5LHn>L@&51~rEhx*DERHoL*V@HE|IijA&eq;;+(Lx_9veR)+pKw;9z3bV zagKr|?r0yZH8F}fY{Z$~C*olL-fEkM{lW8m#8o$rz<|Y8)rkA-n%^fI#$}~3d{nl^ z1*OfZZt}`Z1rYuv7(vYk{k3Jl+^VExDT{m$d+xO1K*vi^n;+8q#{O%K0Sb<+M$z_X zerU6xW~NxCsEby-^@-F?uvF(#$*n5yZv>10>)__>N8XFAD;h(>#L4EG>)Kb1UklOW zd`^tXGx0n`#rK0duM&E9m?e54n^-cI$GZK?+ZelOjzGM1dl%a|dQbdf*A$VVk)g!% zD&>2fLyW36TBN=2YYI$Qt7&>Ke~JoNFc#-^I1gMR9_=gLo|X9!`*|5BuG56=zG zhXCB1dS9E;&z@`sa&~O4AE#WU$s*Dskp1`4vj!%79p#HRtDhf+Yc71X8*ZhTr8=ii z;ZK^?K5W(e&eVz;^}_sRi8hwhTWD8TU$*kK2*sqOPTL38?=pR5mlE8cESFnsskh$V zQP51R3&Oy~UtO4+>`-QJkF;7NgqI)+Xyq4!13o5B@m3q7Yt&3f-03y#)u>V44jBO+ z&Br@_4Hz**$nVeWU$W6X2&|G*-!1CO`etN-^S`NU{qt-qMvhoB9jm!*wHEW@mLnHf ziYsgV;~c$3Bj1B!6Wx?8o=pn5PV#MNf6wnk$xj{`>POJ2x_(bEFi<`{`_ys*lLiUp z>L##xu6~ChD9*{F8+{oH#+cQKGsH~DO46KSjHx3;_cTXZ3knWEV28G^*vDS}PI`}2 zTAq+m{mF-;ha@?fxY+e{!)_W>@^ZgXa{uA&d2Xtq+$o^};^c zf^1f}1iN&jk31b($&Wg-={hXt0omu|v^&&qG*J zU*A(CKHx_Svmc?qQWJ3ZcqtjOLopI{*&naDTb~jeMqvqR=Xk`iRky|i_*Ic{GQXLp z)}miA?C`auv3fk3e9$o9cT53HgAkryVpflqj z+tm1l)WCV`D{v^{R$7OQ6v$y-_Re3}1qgkob#%kq0CVzjlnvW>NY&`%v2v#Jg4&{hHeQBmjT=!Q#eLWAqP%o)& zULLMr^Ysi44njX}Qj8@m zRBjfZ^W8T&`S`A{ERI_pb!n>A41{>?7}hOr^89bXEU&Zw|yvF94%3MyVdS55yN zMvq9Bm$c&P~H#ee>=>1z@>o8j)yn$~n_yBkp~BKb$q!7=wo*&m{r1dF7#PV*3&?bT zNjx%0`BN<;t+-3ulIb}ye%(MvT|qRMc=S{uL0l-@lyGJ!4#qjSzCR&kIi&+J1L>_6 z(50;&5KI|H`LJ5p3~#U)l2H_vFc= zulxcB80yr#;SeDrpLkhSd}-t)mUm5IiKsGI@|s{71di$~t5hgXIQza9oey*={1-!BMo|z9=nCtna7xna(@K z$ZD%U7rHN0JNvSE0UnR{$EFK|KQp54Qwfi88fHPu0Pk(8w=DQK|7|}zAKVmUF8 ztJ00pwaPQD#I@=-?S|jdM$ZfEWgakF@lSE>cNVN{Vca0rC@;@1p0j*=bXYBd3>^pX zJIB8JfS_)6-&#R+b)uw^1}9CNp`ZFNscaY zT`NYzA0L@hGi%3nU=Q*;6MCaLJ_5-Z?I4VV#+sL^P)(;Tg@PT4`mWP06#r`VCesP~ zBb@PT(Uurt1ha|sz9Q5Kson8UrB&gX@Mpfp-#RQq;Z^t|sN);m-rb*IvC;qTUXEyE z@4KrW!N#L{>~ufA>aEwuFe6HuoGiCpK)djNLPhGo zdN_V5_R+2mCqaDsSYIEBN%%3|+a8%R$GyvD?S2COP@yf>^p09=%>|PDeVXnu32&C| z3Kv=J0a-eT8{BCmK$ef^VgEs}HIZPoDcPEj7u3xjoe00=Ka867SI%Q|Uh*x)&csC1 z8pkuwe!WE!SCKs480r}c7&vV8Z^3*K0Bs)_eAs;gtAe{gP8Nf&Z6pvC#)Y8@y8a-_ zL@DebfS`O1_r6y2D%gO4Z`i$S&565uz|7rU2TA*pg#OMh{2$jsWcG; zp0r(7jB^!2S^e*!5rw(&H=bYWSX3lBuSi*hLkDpf+NWp?3`k zk##S~)*&O?ZcLGX-fBW@QN~vRJwE5%m4Y7)1k+LQ(zLQ`;%UFXzRhLD%fioChqHZ_ zm1C+8AU6K3zP+P$BYMJ~Q8MPxhti{sB}T=<{R*=wj2W#5!!Ex(P6am$OAbTa@zTLx z`!41o<34+g-->)@xbgn|@McXQ#8Pv3cWp8nLz)g^tB++D^J9IDNxmB_{gxq(Y zNYI9vlPskl{;T#0Y0}Lk4~;K;BUOCK5HFlT43{F!SV;eVKQ@LI@1;i?GpFV2ilzkA~DRB8(s{OAKjQ{al#`=K~m16r%w zkKv91mj%64e&%4W{<#?YgnD3JP)|g>5Z`{%5Gx_UeeAWOK>oPV*(t?;u+izu(Esq$ zVD-0@)4^8XZlMW};j{{gQi?AOh5r|B_X*3V{!PBF)4{;-bfcSCVI7eJeIr~B?W3CW0F0_2ABW&$!Yx;v1wKNEw zqtV*qjL4<^i6MOTF6fC8fi%vL+wj3PgAJv);5RkM?a4~tY}eQ|(J})at3jNe>JhzC z&ypQ~qGqO`aD8z&cAr!muPCC~+f;v6Hy(9#xr*?z>I|^Eceh^fPl-FT-F|=l365Kv zZLwg>3QYhkMpGc>bkBzK#BR^gs=YA64dxX;>}^bWl_~lKGCo)wcP%8N120AH#S_J2Z&-}JKvbBJ>F6& zex9KHmTFo5MSi7r=Pn2=gvyvvPMkfhiRbB8jm{H!x3c_Bct!1~v=9Xkmde=mxVrY? zvN9j6@Q~sN>Z8zH>Rx^QjOB3s400BMH;l5QuI^kv=w^&wv-&xS7!-z|dPj78(CPc> z>C%3MdmKWGtLE!@_Dgh9WYt>&SS?LzW?hu+ctyy>`0e&gZwC$HUz84 zL*WA*ZUQlAimx`vekT*M448T}~5>p|FE}%YPeKy}e(b1ymOd z)2Q@nQQiN=un2>^nu9DgaevFtrK!+J&if@@^*?q_WwiOilTpN%ij?~B^TB`G*2UhITmA9eZB9q{`#FfbK_2=^KCMC{Vc~Bk+^o2E{?U zr1)+ssO-&)tGv1S%`~sQ;wxf)*d;0Tqtil6{ReEKC*M8)?lf(YZ)iy5x8Y#L{Ce%A zk?W(!4lh>Pe_LSj;+Y64R55AHDhr+T&gOrZV5)aoNaQYMPf5h5N&AF;%7n}M?{vmy zfYZSfAhQ3<&zZHuqUPQ|3Yiy7W8ON2R;+L_0e%t|WKS*8l?tQSZ;hkKC0YGu*Zm|h zE1>%E2y90~9+9=t+GhvI{lfm;%O*BlO(@3njD*VJ`>hDrX~U!4RB7(;pv7@>Huy7* z`395M+fz4yR*-MAgguKSha0kTxU&P^h4OaUFRxZOlXY$}Q!x{TXtd!Oy0>Ifo?IowJu6HbYTQ698+rPmo-d~D!a;6`LWcd*cw>`gx zSQ-vk&-b&_&qraw2Z3KBK7HkXoYTMBIo~1!@v}xN7leuixFaa0cHvOjH{nN{B{0*9 zI%P}Fl-A*{rf3!7(dtvueSM>orbG=ev4QMV-y6{P%6uo#-+AL|4_(30mEMN=8@#>@ zXWmVZg(|MKHk~a-1N|Fm1fRRTBih{Oj-#myC|#*!nAG_g@D6&5K99jt+y1u@D+{g4 zo=8tUJ1!n8S#WglEJ7>(gyhp#d&d2F%wmcZ3~J4}?teA}ZcnG5;}~1d3OCs{MffMo zHs;o5q%Sv_2$H33&^gzCXvDrLVicQHv>Xauyc~Wv8!8);ng{ScIwbV%cW^rZSw@Sq z#mGiT-crlt?mK>ZZC3rb^HDE>sqca z=2&=qnUyH*LTXGc(i6A+XaA%|;f$;}5J$oMWpWFU2sr#Z(i!5q%;gyTi!?u=osMh< zE*@VF`VPWZ(q!h5sT)11msw8fUT&|I*X@E@-+XHIP~)LhJI$$QpQhOUc16*qj}bAj z`<6MVTZ%%6OMs`4d9-EBR_MC-{PF6h+DF=M%?CZ*Lw1eGt>O*riK5joT)Z%y1lT~# zziG0JIGT$G;vMi$sjAwq{~#wBb$;eV`jeDLJO$w%ap*;xrLDv9Bfg2bbAw&0z!YP` za#rt8FCvZeUMi*N`yx~xRtSP<_8o_rag&GZ4RN2UU_n`;WYTVny)7P!B(h;8g&~w{ z`Wh2ue7?Q@a!iKQN<}A`g`r{r?l@QK-3nB;z4*Y_kP>wwh6%u)iHeFbXw5^mk166YrqL*i#F0^*KP9d&|h6{?@XNZ!QDyxUAXt2=syfK|+rqRx2z zK|^RwXb5Q^>ib;*n#r-)7me6?b8_IoQHguCOun!*N*@dbq6_>DPx18H$L?_YapmfN zynSP1TdBd{`bc-lP6lNbO;knQ!i4GX(=A2*8yfGRfthoGg*R#EOurRN`PfX%Lny(4AH0b9sLYnHpl) z=YoJ$K$RbKYIsNF)WrkXm@)zaI4F4^mlWSg8j@!8O~ywwS%XQ3{~PCxd@`Li;XIw{ z_TNo668OSBm6XmT0}T3OD$#D0^l}pEEqM~Iq4^bxcH<`-jtxY$cygF62M!# z-M{~RL8WNw^oG^u`8v)vrww`#qrC%?1L-qQ2OVWhrNeTc8#f_I7p_k3>y}fN+Z9r{ zdZU~sY;7{$uKcVFWmmR1uHDb7yYVs!IJR0km_Z-22SviA`&SKM_*Bb@lw@Rji_mcX z{&8~j9oqwbhHhJd=YF@?_r$01tF2y$m-FCYR^Vy%U}&)wfgw-DL#eZ>=`?{w^$59y zZUC$Y0OGqAcSs33*>Ytx5)&_gKca!O0N64T zkDbK^D5a>52^t+SH}0<1DHIgc@4SfCI>9e}uXX~7MEk@po$)uhv0t{~(0^0WLBpo% z``cC&Je}_HvsjBx=^lC}D15U}(@13tb(9TLN)rB2pH*nF5%t@5Sm??Vc`R4JP_(SM zQf#u7FXRa1-0KX}&}9zqmBY9C(9-C(DxP~>*G6A1-3;95#x1rakSSV5m?9!RkEq|Y zowq}FKE~BOL<$%xdw`7@UqXB(yky?w+2jq2`xL?UEg#Q&2P?2`=pL5@Fv_@cyx-Y8 zo)oML1K7Rh_f_YCbN_y={{7)0`p)1Kz1qI@Jn;qvJ}L6;dQnKL>7$!Qy!kgOR}5TF*e6?yj+;jhE2&QEC!QWxHFZFJkl<`QfPA1214N}bIpBBTqAW#xytwxLoMN;dKyL4B z#?Q_~8-)brULfnc_d{^$a@2@xMsFznNinD1`j^qBiyzoN6AjdSB$>i)5BSyELn{GVgF1MK>1MWmR>Qg4> zp!^UJo9)K21e2>M3H&f<5KVGm6^v$N$xd?00sie|)KTTtdgd|Rt-U|xxNmAOQ|rm$ zO@Da;4xSm5rjI06G1a}l6h@h-+k8`Z)BN|u<<0^#HKR~#iLqYMr0vssRP4=pMVgp= z@>FnAs+^676lG1C!Ppb(Bh3D6nvDa*MI&is)J|Qk?yeI8z|`;*qI}2q6Bd~cUa2{c zj;D&WL+N0+bFf6a-`un>LgJH*Jz=8g;lA4@cHZHe4wGg6_bc2{ws1NqfWO^}`GvQ> z*yF>w=`5O^ISt4cV^bNh^+xEk`M-xvOczbu=`dN(=Hp^8foU(L;=NcMne=@iIsAtfYorG%rk z1WBhuQZFjr6FerDJ>`vvs%GOcPR4gG!X7>?LR~eP)LFp<3^uX>{dI# ztwyVS?S9O}0d1I%pMEXYRy3M0JxJ>qv65xDJ~pHF71prmi`DCv=-!U)8%1nJ5aQEg zSJ3MUHDu80IMJpbtIwmsy8c}6rK2yU(Bc=GWl|e#)>^RT!i>V1!lp=RiKSW5!o8UJ zVBb&(8_3(=RI0JPye6%RXS%FLwcPZBF)S|)E7nio;e7Y<9+~KG zYtG-nmqU@3qJBmU#owmG+q#WA-i|G$-e~+Kj-HM;tHkS16^Z9W3iST|idKz*u^n)9 zI6>1!Lg65WsDo&o+^A)^mV_haU$$Ji2)|1Fpd;jRrJ$lU3Hu5@9C{00h2rY?1-Adi z?1U3LePJFk*F_;Cr~`UOmifSgD}^@RD|RcdhM-O#?bNl>z7v*ZTfm&#T;FDL+}NR*s&EkQx$ zCR@8EMehHc!}w74wjS3cu$d&++laBt$@Zq=QxaTBM2Znuj+|B98iKPQBudsd zlN!*)Q)9O{l;v^dfbKh-4YFnJkwy8{=pwjG89nONItzG|j_E?4-vw=~{o zXQ6nw5H+$^wEv(Z0L{6fBTH$Cp+Twf4(_^K3}n2*&(yv7N~1+-e}V?T=bv)STgEJx zWD+ow%%3`-=TclEV~_QQ(M(vu>7d5w8Hyl=yyb)ktBQyv4m5Rm6vMJnZBf>^gZnXZ zBkiMSq?C%f?vCG>t<<<%bbXa+r=F*LIoM^g8CJ=oZjd&_icNp(IoIpJsIIVG4ch&K zu7ajmQSDG5-&q}*TcJIdz&zx@!3RcCrjTaJ8IaHA%aK!!4(9J^W2)L(DoRrBX6ha+ zMRyw%@bg?FG9_Do@GyCA%!?xcrz5Z!7l#^5ZtuJA3a*ZN5f!(+kpb(Od~rU+xC=yU z&Ma~1pE8LDV~6E`a~IS<*5dlY_!d?T-&ubNNKV>&X>|&+|46CNJ@|9J3v?LQZ8Z~A zQll}&hvm-U;}8&ULAoaR7tWL0&I&0&M{vc#CRU+{s6KM`<~Euek9FKIUy`uM4Ib+nT|vxQ}IKdyd<61OiJWC4l( zA5%WiBLzjRO#hSgDqyk+Pp&y5sPu4G_&w!}+vx0H| zi*s)T_5rA}`Cws#8)jjV+V8caF7QlNB^kuW*NQD&gh`(-g#dvc6%nTL>qPzVyv*Z+ zMHPb@n**uQoIUkB@(|~DDh@9I7z5kbvpMByzF~n@e7l48i;WKHH?t7ljC&x%(#fCdc`VT&lF#`5Q%^Nlq3ty&TUZS@7}XfRQysro zKRhZ+Ka-IMvrUb@=-|Ntr@CR9;ZfP2d~W6rfcM4FRY?zS49+f^Apf)hFL@V@D$)by z?Y72e9~rnC5Kkb#T{J13)fCj{N}_-|I}|be=ieTYCTd|UoMmZK7UDo3(sr`Gp(wwl z3*?%~*M5HZi;`2$E$P<6^Ul=^G=7td<@1QoiBKNxHy&W-R`SI4e`+%cO6$@V9u;Ku zr*!Gsy#u+}g%OQnn1;?mdk#b;>MS<};F^S7k90SMaQ5kcz%^HZPLd3vZm|M7T=(6B zcXAEXptK$0dMB>&5!osrMAV|ekfTBZ+)^F_ER3D+E_V~C%hVUF zF&x+ZB0e7fQl=XgJ?HLPS8I}F!-I|jYRz&@3p=O4>KMF5<-g`5k%BDI(4syur1Ono zMcJ9_^8nQ}^(Lm0v=OF8I%>d0GL4*nd^cghcz#zCXDso=Xh=?iZi8$~hSL17P+I-T zHr0e(1U6d+Hgs?~S~fWI?3+s8QHfRP#t11i?=$9Ie64CvEnLpyZyN3QNRn0g74*uk-)3$*1XC)t}e7D{)d9E8^6aDH6%`;Jr z-5KK!CZ(}UKl-eh_-T@wfek<%3mpw4@UmOO?F4CGl`8FuK!Jf-pmjil zyLL_y?YrTu{o7TzTHl^SD&m2w;$oCg8CdbV1#LXplL@RI8$nEKHliYOu`{5g;ZSi| zs^y~=xB>%p?HqPv&1ANG8cD|+t7^jLf#2sgRX2(uhmX;0zR+5hXf$)ie2{p|{dX)B zYR#SiR;R%*#*RQuBO#3}f-Eie>P@idpjxY8ZY>%1kzICp`~12+sK2%HQ=OFBVR^p< zg}5-P90a|x`#IM$#R5&J@HQ_$h)T`Om=%CA)}@A19l|7~(03{0)5x?GfX-xEQ9EnbrzEQIzv650Di-D_1#wIixjmnw#1?G7&2rn$RY0-(+!m2){0_$m@K z-A7YccOLg)73Q+PCRxIn63`GoIiDN7;o+f;CjSmt^jLiUEG{wjU^~5VbLAisVMP$3 zPF}uSantbAmQ3M_EmY#kMva8SUFcUnw&7Xlk5fGj!ffvE?=6|uZX@Q4?xdG9(=&zT`o1VZtBcOAYwzKOI1;1_e~Ui>~~1vun(OJAwW|t zl6PGUXKlVv<*l}?jjOs;1rU_4D9pJd$(Vp`oN>1>8}|0ZhzwU+iJ4{TdRpJ!xVF7y z@<_7$Ihd<%G@`~1aVu=G*?7k|Nru#?GaTj9< zB_jNupQX)}G!>A2Xs1}2s3X#l{xw5R!S0wziVOLfpCK1jo9_Z_USpRNlCC_|``jZ~ zRNBik?BrrBPeGE(*v{7~FXbXD31X^~*qeyHbxUd~4IOZb(E0b+;cKB{B zT3{K zF8@nj<|L@Dk$0`CdniLypds?UxY#}7UUg&Qyk^sWwItg2vFx7-hd*s5C|_8_aC_mX zUWo2}?U7yfsft^5HkMbkfSp0@cxb!}eEOU;_uJqLO~Ik2LQrtY0TAhORZ7I|yM38S zJpXpQ86GLR(^WmwypXTbHp!l@S}B1}DWkshTJz%dKKRC?A%)o-ZxZ$z}{0{_)r%p=(Jv77%)w3==UBO1K}!u zU+xuuR7UCYH`r}8OU7O3zbZI&6gLHU-@{=WU+V+K1?ogEbu@Ti*C~zeZvo8T!5}VV zdimeHP_Ys!v{xYE;A*j;uZf*fu-wYL7K3E?5$?teTdF2$RB$T7eISPEHx)De;qCdqY&qi*NwMxJTqd9L$7wQ`<9o*~ckl6gC;*RwChf7fw8AuF z+ld7$a2Uno3GC&QDGGCje{75Ndd@r?qI9+goDCXw?h6IKT>CVdpHsvmjiShGJSw1< z$LLBSUK)LK8}UwU#8Q`EkY~V8z*_4&mOl^PBPUS53-68iW;Xx#?DTw1WdKb4a!t-< zeXPr6#UkFZ6P223*@UA?1t~407w59V2c{|<$Ao?VGDZJ0N1NVCk>WgA`De-R$TU*} znq@<?56i7sV{Cr$X^o1Pf)DLp$C@rtd#| zRY3Ikzq2)GuId2mfd@PzDPjLx3#twIps?ZneDb=kkk(t|_tiI%`2=kyCgyBeF*?a@ z?f8`_nu-_!!CbLH1n&9MS)fanOdF1YYbI9l#E z%~FfQ=Z)ZJo5|b`w6^5Z?6V)=ltDpP;Sj91OS9||Wcd-ELSy{QH_AC_MESo;&Z#t5 zyVQV^QaM(b!Lds>`wuQU>2Ny&zSiODULp1o^O+yY#)fS*M8nXVf8Fvc_jR!@mCGOF zEZ3e&E!U2kZv%|!?_f3$c0|bW%>~%gHR;xk61pOPew{d)!cYD-Fmk}bci(*!J9Gm%tL&nVm9 zMY$u)=_^oFN$LpCMz$E!{1;k-vKm^I$wsxWzK&m1!|Vuzdi({Q3i$2k+(J<{i@`aK z74e9#l$SviFCs8P!_e(PqijR&L_mQ+(Hw! zhDrT#gH0$Qfs#brXP06aJB_ll>|yFNd}BLXH+uD6?ed*(a$qM2b50IF4VFYJk6ajt z(lOc7aVXrqpGv|Y8}s&2zbMnwosVGnIKaNflOW>!ihzwT!Z*fM?x?c6%KO8EODUWT zZn^UW&J1sRiRL|&3)w96BD(vVGw$`_=X;8jkVfn6Wi1lS{}3dZXl1%9P$Kv$hCBXQ zW57?*#v~`F%Ozuge~=o=AnrHPrelmW=`C<%2^V~RoO1b~US#S__c3XNU3l{w=Vs=2JOV~QM<=^i{3?hAOG~3Ek`15veA)7z({#{I<7S*6p8wX`t-b_ z$@&Z0Dlc+2xY1PL)$wo=l-OQbuktjUPGvr3HLQ<>QLY;XzYE#V!DF~Z*Z+lV+xWmZ zGvc3v|4bnpRiu2{!VMhfLY{dhg}yKHBM^4I8>p0nW#g<9_PHX|IhyOSS&^3fO>s#- z`a(AM&lay!GTKt?l+ipH-wz5&)m#-{FC)7~JN)LZus8`TO3J9x$#)Lyh3y`z(~rkN z0?IC}LkAxZ;`<;M%jsJgb@}M^&jQPxJ8abv;bsWw+ni$FCA4)pe42V}wD!lP=}7A& znn0!%iZewpMJ8AN4Ji%(uI^vDG|!$f4J z?%2}*K-KOeeAv_!Aa@m$@{)T60IAKUQKpb=tW1+|p^Y+2e0#_Ld7q*F=Cld8G3yrK zcyJ)GfXdF4?CgafY(kF`XEFk~bx~#%AWZ6V9CHQf7jcC$B)Nq@X|+zj))jyyC=&y2 zE*Z{hH3c(W9AK1DPLxuf`dpw=rb5pDr9*fXdP>a0v^eF-98^H*aBnEZjBl264gmhx zrT<-88um_SUlg|4U)7YVrtHL&^JjKH?Dm2ac!&Sxf9q=-6{?PbWHEQZ0~CX%EdTE+ zdf00NU4zOpypn<5BD_8s`aHe)LPl`!ZUDOOV6Mwj;BRe`qPl#SlaW3FpdLKH(+PEl8<+ zhM=YnJJ`m)#yt>RwZ>{%_ZnM?s;+R#t7^k8eP$j0TMvD>~L!(Ci>At~8t!DOAQ5Adt!?a4(Jloo8CIf?7_OejRua9193syNP zoty&>O(yc7+hU)W{gzb6A_zo}7Nz#oO8{euC$llj@bXRv>|1=|1G@;0C7u-SiNb^U zQ%4lP9o1$PyWag$9;o&~Hzsy3l}un7%N_HQwUqa}nni5b6)KIjKb6ViVGsk>aZxBU zw&ON0bM46x-2I&`WhfeaOg@z(tD0|lR{eqFb^tVF+W3%IIkYpl->0D|f5~Nm>pN3X zqxoJr^1QVLZ7P5~WVdow4AfnK2-{&0goWE9na;XeNq}m>dUJ5&r91t`jn;f3G07cW z3)+XJ!1U?t`r#;WM`l-ODp(EnZy1c*6d|w8+0Qp!m%j3Y(4(FnqU@|>JW6-MI9{Z0 zJ|I+3cB(xh?1IO?)h@{yn<#*hUcKnhG<+%&wJ;N=*uAh%O&QSOJ12 zY0kONJ{~OH+s98?-9Mdkg-L01$WuPef5PwQv$8SG4*e92zSfkW&M62 zEyUGw_2&hw@sZ*c=>}^hvaKQ!Y7KCD3_pVcrdvCqPPeB1f<1Rhzs8rWgg zQ$8IF!^UNp7SvT=Zp= z-L9F%S(js(Z5p**rk;p4US~d_`O>~%$s}1K*9KgwX|F%6AM7;VhDg(-9biSZaJUFuutv@^!e$*Lyr?<7JD2DVvoC4OaID`K@F zkXT007Kn>$oSXG;X7Y4zW>{-%K4i)JY%y!7I)n8i&;an3KI?7Zzlr*ndBnfIh;?x| zpU_}aR9Ws5-CUnMZ#er~knM9%szTmQbOWbO2-<{SCW~r2PhKw0MA{F0PNlBTQ)C{> z((x*K+MM+z(^9|4WJ+_K5UuOn*Oj_Y&`3b-6%Zado}S6%*H4QJcT1? zh~qLDMt`9Dj#yk6B zFh43H`2{*=B+%MfjM+a1Guna=dvMoYd6+&Utj9CaI$^0{NWd4PenpeM187Dt8n_L% zLDyX-PkZl5HSZj18XwCk-7=mj>AsPNcVFq}0wMQi%DuJ>t(giY{+npX?K+x$dAArW zMeY8+wEEQ5|3`s`F+vPh{6i#J%Xi0BK;lDl<6u5eWt=zOIE)TKf9v2JyV%bdQ?b6o z@9C>x@0(4OT@X3aYZ^`yK~$K|q{Yb2k}?s$oSf*TLVM&PHv@2t#3hwN6gKmq>=8D( zw-Ep9p~L1XI5(>1MBh5$P#6ij5BfXvUD+{VmglM8_c6Aq`z;|8c`$ZdxRaRfGHyRB z_7#F=HwRmxCBX^*htgv6W$Yp!a0Jrxj>E;ru;9vr<4gA0PzXJ!xkL`EuHZWiX-uwh zC4vU|s&2MT!EM8~;;zhTcXfFNIF&_|XT0P;@Cv|6MAocPk4)wC}Nw z)c>OV!k3UCB2eckNsBByNj8QKGWRSrHxr5XeTz0HVC#3$m>0>DD)&BmBK%&P-f^TM z?gGeeH};{YXz}B(iD8y=_H~2_gJIcp*;;IKM1SOsb7xLwD?QL#uyjevpXhaFpYeLqEusTiOsTtdkl0?_%*ew2H4zS_iSCmt7@5JatXci2P z8;EG`3}Jqdv{NhJ5pyF!wIx&Ds*ohq6GT9immJzPvej*@psUDM8}Edf z^-u0G!oO`|00gs3!&mYojNXHLY~{q6h#H7K=nmzoJb}o(_s0fZ&pqUg%h(PB+IbN^ zgMZ;3dFL(8C0c*ia5R6?#D@lkp?fD6wpp%jWh|r~Pp^TY$jw^DhyUzU+a~tUixM7v zxKHIwLqMa8-iw_^OQ*psiee6UbhXB zzj9u@%z4Wdb|#y{!Ng(oDE4BUAj~i{)ye;e!)rtz1zRQ!uHSw=94OWIxbBw%L>dhl z2!6wD-R|K>6og*@(TLFai2gcu-U6@k?iA@q(;G^3J`jSiv5b4fwcC> zXg@LscQaGb@yha__py;(3J>haY-Yf%&7D>se#1u1clAff&`eY2Bd%*Q=H#hI#$@vPi z(!VM__16vB;CE?48!QCD6spW|pzs^bb?Tc6(wJB^z-4JbpOyLP(u)xRuf&O)>}(qx z#FRr*SdD)TXq(uW1J(qJw24c)&E4PK_ZtGI@|0G4=Mrh%5(%*d<86Op{mTn6V}#UM zFcwu62VXGDTnaD-P=c zNf+LJ;~A0Wye`=qh#c4!o>CBMt{5&?uSKjTfp?# zeTP|ggjuKwgSOKyivs0UBA5)-D!plaRMlAYqh(^%FlQ)r|uZm17Dvp?QCqkfhfm5@FD2gtdVI ztKuv@%V@@UYw3dQ+o8~QPA6~JbBEpP*O{;Nf%9Cm^FjgivUzD>V1&qI@20}ZW~NsgLcG=<&xzz01*Buz>@QeAWHMvK6*Lm3GO5U`Y$te+ zE-+`9@Q+`T4;@JXtv?Jp*19Q2@XF%eJSm9)!(sOt2o*!rr=K{>|2F!@rj{pE+S!XN zvnlR00Xo*VG1fgi8b};Tdg?-h6|a^mpRLl04QO@)a9+w6qkdjo@X=<4o{TZNKCkO?I?LE1Oe2e^|q%NhDL}o&4O@ z4bwezq%Ewc*89AyX0N`oi0-TF<-Ki-zF~Ws$rfrE#60(4(0mphQ^`TwU5FHZsK5rV ziZG|dtgGx;oxb(w{Xb3^sR3(=173XB=3i{3i5@Qgi}^Oek0v41pc@z1`cNt6)1Fd( zZY?T_balLn$O1WYq#Z$x@rM?UXpK%{n?jrn(0z>zAoBx*>0bZ7%Gvw2ty~w_`yE%;w zP9%?sMqVb!wrtvz`hqIELM(CsYr4GVk1AY&7(So&`<^w)S6RU=Ufk8R$OCe{ksjy= zK3RRJNev~pfT)kd(xCU!f2LD;OxT8UW>BrlU|&hB@~4D`fzwEz;O7&8mHR9*w zTBm;bvi+_nqBmUR-?+rHHCn#`K3neB!GWP+E8!Zt>H+vj?@9@ZYIHA<6_18(i7w7` zMxieix%@UXMb(8mv3JZZ?7I=UN(_f0b)&@?J&=dSXmCD5dt9VAw+cVt5x;m7U0pA; z>_C6_zpk8M!>WF+z-LCx9NIT==gzdyBGUTLJ?`w#oSf1vaP5FY`M^hfA;Ynq4qo}V z>ftt~K^}vNR$0lz0l`eFqdC;f0PvQF(--1MN2LTbdsaqf9M0kbYSTREQD%fuZj<)^ zsZ~GYQ3HG8<$A7k!H(h_w5LdS7qvr*>Fd0pN?A+6NLbG1L`a)M;LfEM^(kln4=Tv0 zg@OU1_VN}-abWs4Yt1xNm+sS_RVh4 zGSm;D3Sm~^1u?IgdvFuHWmNW$sdCE|m?P&&TzR*w*vDKAUnSzKm42I9qz>+&JWbvC z`S+z3Yr{Zqd+L0~)W8}2DX_5RiOBi)PGkplMzkm+9d3NU?@>;|-j%HpDGTG%U$-PQ z+9XRvbiC4UT%;l!=3G390#jCnwNvYvV?!Fs%ea3?gR`6hpqi>%@cFFJg8$M;sT$gLr4 zW_Y?i(|bQe-RqS+7k!@(l?|JbZPC-bQncCES9NqooQ7B$A)twLdb+zF5c-c+3k6rp zb-Il^RI>JvF>utoX05{WwOiHwYYSxPKH(Jet?7le4MM58lGExhf7`j<%PT1mW_yns zjz22%x~T+9f9EuY%LOUqIfqPVASrp>M#oR3Y0Yp^6k5vap-Vj~L`O{Eo# z;h^xJ1*Q!n0n1%2@I1%qm`_adchQk(yDT|he+w@gPfV;I9p!ZqbuWvw$m;a~#%p1# zkjy(;`RV#AQv9g3bIgTl84OX-Vww}HkZf5Gb3ld=7)>eVQ_2a{)>t#AzR;H zk4_GZ0@0mQVoSesM1V99IpFjao{XPw&?Ck1d@VBP9f!Xhj0XP^y^ZTrTHtz}Y#~P1 z8ctZJ1`35MjqRSPV^Fh;^ec7Wp~4w)N!<5G{uauw2@SQdqj9$;dkFxlqw zGb?-$(3n9S!HO$Q#J3!XcxPxat7uEmf@mr${)n((h(=v!s z^6edtJY8qJ63}BT2E_IVhj?8vU+^TLLsJYu%qiI=H_B?8Q!m8Nv(fnd7Xpv_spF;+dgfty;kPA?Z`oIk?Sq*Q8i&lfu9r8=E&)$|Y zX-Rd3PrBodWz-2PG}8;okp|P%?_A{Wcsub4)1fC4F;y1Nzc~iz0Hv)kysUC(@_37u z$bU9hjnb%+u7jQ};d#=JKe!^y;hRYb?*1T4VH@p)NSz`YgrFo<faZ-zHYRc_U#_K+aZ>3FqK4ek!&N*bEemrDj5%q-Pw(*jL$YdcplvE}8ihwp32_dE%k_nw@5JWSiyYI-*Y*5h&AI9 z;fWY%s^LP6oPb}>Ko&`7kO!ys9{)2~7SYTSfT;g2DJX+7deESq?Q}&3E%>n4gqV7d zzfX2t#%`o>7@FZ(hrHM7Fl}~~e|4v1V{#aUA~V+T@w>^VR)c7QETEV2oc|qUN^8vi zP56z>&xXD8PXsuzArE z@_@WWeU$@>Hf1H{gipx4`OBeDSvr~;y4S|9|2hP!3!9^5JP?qOARz_p2FpDqNE*d9 zw+JN@mY$f%#)INnUfo+tdlWL_s8xEE$dN43wgXs76cX$DliYh*{U@Rw1q)wO4JIEp zMk9I`51ct?=b2Wga`+mdm4)!%0y@!EzLYr@Hr@^x*jKi0YT0rFuoK)1PrbKAb?*0^ zpY&TP#0JLaD;wcyc&|saL97`05vI>`h?z^u+pvr{BP5nU&k6vu+4{RYKqr`ub-kC{ zl}37^AWiS1&6Kz|)QCy%NK3xAY&q0`kAWF-|I0S2UoEapqsUZtzO=(70G13*f}%8k zVCTJtMw5Ra-`=*udz{M>4`l20++K>M5T#as$S%2seKV{6?T{5kkP%R~m9hv)wHOjZ zlQ5iO!j4G)fPOrO{$47G{N$Y7>MJl&-}NMb|JX-4k%&LQss66;(JV|~}12oJk z5qdd_W9^@^VZDou6sMdDu8z@}EZv31NzOd#yJC{z{XJ47`aHLNs*5r2t;%sK*hcWX z#l9Gy)Kj^+;y6VP33O~X@ROgsL9f_#yylMFj6cj`*M7FYpPGtF6^G|1d^P!R>U^us zv|5+4iVkf22uy+>_%7+OnSRW)ZlK^YHV}evK}7HBg|iz^arzLOlR216BEBgy3k{As zB@7bXJR3*-e%UlEJ@rfKabu&5j1r~xnk!?MN$~xJ;KSK7*p50NgTY`1o_%X0!CejL zT?0g1v%el}v)LcQfzSst-ZU$Zr{!V=@-oor#Pe1C6a8S8;JvfOpNOnwb4s z3aM?=Ut*j%_wa>|Ei&L*8P z7dVtfC*pKg0rAywGd;d5saDuNpQNPUCtvYt-u(_gG5-blaa2q>dvG^L&^Ka%LY=mpCpqqVaoHji%Z{JcJ(Fp>#s;*ZJjzOo zYIb(%%c-;$rGOxPbj)-P-deh;^^;&>{E9CsS$e9ak+6i=OiFlZBLw>v92De6dHRW+ zlI3w_dXun3LepM8P&sbeQ5JI3rPpfZ6JkilPN#GsFMV4njm(M$6ed3se`kewzT6}Q z(H2e%(T0cidw|P1N8z13DO@q+L8}BUY-&K!@2QjCVo~_Xh0f4h9n6Ht)8!OW^^4g`olpMh(K4Ool0ifcU%d)eOm|Z3FYJyAx$6O)t{(& zi8q6@>(7syUCA*&hFxCJqFd`f%mEY>L9h@g<4MdEu;C`qjh_OgE}7Y9@uBk6)L%X> z*SBfW6RITi&h@lwHJeWzGW_pY-e60b?s*R0D)Rvg6W|#pjD+PSd1k@m$ z=da5e-;u3;1QH0V~{#AU^uk217eE~==$%BgeA5;}mFC6<$F7K60 zuznI&ah((Ts*3i2rHpn`Ta6l&C1ao@my^?&9$HBcZgfl{I=sg{Q@xOBrLtA7p^@f? z7=3rU1ix8aNtsAePVI{S%VW^d%q=`Re9yiWouGMLO>7sd(zqAmB8!hCY|7*PQwRFa~K4QkTRJZ(7B2EUvJ{QUv z!wBnd9}khgCO_Gtg;A%L$OqA|$E_-?-l7afS0()t+2Yygu+xI8+X1J3Bl@oi(;l2m z<~9=&oppd}@^?&mCc*1dj&WQ8lWKNB$MgtSB%LV9BKOXToRGBuX*u3u{s-iXdeQ5Q zkVjtpN77paex!-Q_MZf_udeRt>Ok2-Z+!s}3M4z#oZcZJA_%htnE07}*BPzL3PZKp zFf+r`ZOjfao#-s`I$gg)P2ila0|A`oemg~$&B)b0Kda476H>0bveP^g?8`)xGCg^= zh*{eaOj4jH99smG5nOQ@QltsfWVKU)+ldzG>);bO-pDPHU#duv{e%*UvZ$(#Hgi1v z1MNxnWq3Qn;My(`V2ddI=J<0KqY~I7$M!-OJgT!aalhdm)2Dw{jh_aOF9vjez~=3> zC`WpALH%AGMTW7;tx+)tbcqAEB=8R8k_?8LyYPB5{l!tKcp(hL%apEei#AtTjOmKB z8?U0%|Eg(K^EgbR>$|Mr-Qf53nMc@r<^!+wP1Epq(z{T!m`PfEJ3%dBVL$7hol*Pg zdL5$nruGsKVF_V(D{&s2kdG3RQJkKLwv}I`l$4T;wh!@=(q@rC56pzg zVn>KgoE?9($^(j4$JMX)icI=sa;Bd1{mek0170Q@+bQXnX>xF`K<+`IIOnE7li)}l-*?_T+c$Yu zBdxt*q2-iMLvwaOOd)CI6p?T^Afoa0F4k8ymn$CX-cPU` zJO*D+2hkiq;dVdu5G^&`haeac+N{Cg@g2c5q zFb5g9|7{^=6>&4JsNP$wEYJ@r;}@<^$hL$7tUY%ImFq*fNx<-R!Z2JC*&s%hYV0o$ z_=y8FGpPbYukMQH|IM2nolfXaQ`qWW8}F(0L}dm0$uxus;=aA46z}y@iK- zgzGZAxd5SYJqtr@Q$djvXLgs=Lir~%oqV4=GonpjS`(Q57ZD=s=$J}FWOJxOrS$1lgm7?j#MUoMqd2rkU6 z&{s1Z0VX8^gqDPq(I}z>VMz)=r5lMvwLq# zLM|1DBQ9{desbDq!iA+Gv?Yr=tvUi6kEQtp31dNrCk2^Q<8!KFrvqjGB%(key^X3< zDWLe$52kfXr8fs_-nuY^f2%z}aoN!H(@%+6Gt%ELl3ZWNxft~(`oV|;lqWReA)Q5J z4+GMg4yWA7HkM_ID=m5usEaS82X7AhI%YMo(=O@v^7Ch{4eO%yHIN$yAT6x_qxhN^G&5@Du!Xp%OEDLwAJSOrvpGT&k6?k2x*XO zkW}_W(;+)f)ohpVe_62yuW%dyMbwD7?sRpu-3XggO|RXb{}4GfDzs03k;OQlCpvD7 zrkv$nxO(Wt3Ksz2AKk6zT_wbAxeOozblzwS&Tv@KG*rfTOm>b>v9m9TQ^y6cW3vMP z>`da{P#}tlNs(GSK!Ps4n#jzG)wwd(N=maDoc*^I3M(LhW-meNd#NaT0xUR5mUF6G zx;tTm7ibEF!P4C&^^OXq?Cjl;v$n*3D3V^fG~dw}ymA^|-3hDil>kJ{KtrT-4;k7b zI6Orle>{^q_8=sAANDxw>WV3k>O&^~k{$V!W!S%6^Z%+l%de>Z_v-^9IY^(!;JSBQe-I?>@8yJw+4{EHc*~$aU zlhhzazlx7DquM7yK(;jLeNGME)EI59>~_|F46Y}e6cy#NfZY!VCjAjvM3|pBw1$q? zJfd+s2_|QU%JC*SBp?%H(J*t`nb!S`f(?q;*=JV@?9)&2G3cD1IrAHEwSNW9>4{Y> z2i_sE6L_g{*n^iYP@i7#SJe-%%;U1vzw7w^y!lL=!r$X=l_5NA5xu4NKK`xfN5=!3 z(H|T1@y~TkK?pX=jx=Y{i0GRpq6Y}U7&yP@uK(G{gKSGiq0l8>2%hd=F3hIZu|;L} z>3{+4-94svTd$heqH{y?WMA!?cKGXaWd^-GjupGgFA*D$2%#CqAdltZdD+vXej~I; zd(r!>-dUgfj8`?mq8S8IA!pa=97E@&5Fp~R3U@6|oEU6fzZ^W#eA_QEi{05&Fj?vQ z6_yPn)Ro}+r0Unhb}+j!FX{h%*{YfAIPi9sQAs1KNFsI zY~(S!Tk4(lP&7N83-qP`>4Z)x-E1O{^cy;250_?-FzhQJUu&5=*q`e-Ns0Zy@qUu^ zfzq$3f532|)m*qxwC)jd~P(Krr`OT6Xp5URv$ASo% zOQ$}_uiljjB~91sBUvc})sD2C(p#6sVR&81k;^k6NW}BNfsIO`1uySJ`n|On1&55J z7we2&@Lr*>OKd&FcADFx(X$C)h9p=$dI<>|u7ZxZ=XeV*2P7jiO~8hXfVsT<$y400 zKNN0gzbRF6X6_YTIeco)pN_MY7I*581N1F9B4IE^d_%=-R$Pt&;&}L%a)4cZkFc02#D`Ui|oysNTn_UKT^=br3 zXr~AJdhK}bH2aI441&pqp(dxf6+%UFOhb-$Q9+l^9dwj9gHdN@)O*=Ut?i~Ey_vcW zfa35gmsip_ztVA2Y|$pyh6VvHKmYWUC>*oQf2R3L|JM>4MY(HqvwW4srxw&_@rgJxpNo5Ha-w`%4=>O@X8wz~Pt5%=FLjapta-;d zVLC^ti%e-c7ZEovYe!lnY>{1b3vaEp^lS#fcX)?{;J{h=)~j9F10o6Zvq4EemHNU3 z3N0FY^P_AMlF<-I=apjKdM16~UYgT9tP%K5|2ppV%&31`Jm%Q>NG8QmLQ(&vCkVP< zwH~Kq6+d`p%7pIG2Qe*?|BO2tDbsoso#;D>)2p8bf6gpAE z6()q#!oUe7uRa-&7kCi&&`&4uC@ax)sofCkvM>jk#GJMU1EFhUYYI_ z0eLg0adxFn2-_0zg|Fm)ZQf9H0XVc1bG~9iVtYwQJX8%hm#UXN79%aSN5E@ZaKt29 zgzzfxLQ)WTZ{#YOj|HqrcPp1@UTv{a)aUw;QG9YSB$bidAVI`34XVg%h+hjk{Y}F? zfS~6#?hLP%@`1EN%jgBMPjVq}w^c}IMBJig_}EEhySlM@vTk>8P8I5}mTaw_H52Hv zk(1$mz-HGj{8)`6@|FsZJUND<#?S_uOMs90Pn5} zJAiCuR`h;<7v)8KbNnG=`CLP+$ovn7Gpc|u1gM66d*!6vGaDTl^xnnNBRYmhV z>Hbn*Z$R#)w4Z-uvBRQ^&bxud?Kr5iD+$YWd)MXchezw^s2H=IlCzzAjx_{`w^;iB z0H%EI(G2%j`7!W`#2sjyz*9i|vL_;lVCi90$ic=8GEI{3>+E4Eu0iQ9UoJ2vc*MOG z8c;ob%*q8qFq{Vdc(h*-H0K0D@epp*J|2ve(d6Y_zGi4QWhw8YCnAUKtUU2wOlT7q zu0L2hFSQk)@9wmjrEf=y(`lHl+kYU|uxmmq^KNBlUe+Mxrj2C;2`%1VUj z^dW4zbh4>TSF9-wdd{m7L}<#&^8r;9tN6Odqy|_Ot2YFEt~E1BF-#H zi?`oCT*QiWNYk|xoQh3ROFDRWkDBVZ7!eSL-tbmikJtFte@^YGqn$WY|8ipy*{)jC ze)I~JVG%A&&^$C13SvMB#+MkMESv4_UFJZH;j2C{9W0nk+0oJS1}ERkrTl$>x?by| zIrTDOKnSiglOS8z-fUxh&PY9QE?4qQ3vYE-oKn*Oh??Z^VPA;!C?`w47U3j+BIHI^ zTC-@T#PHim!+@=byu^03MP7_}w*+$K1lrk+6XARq>7X+&X5F#gW6*y*x2?omr=kL6 zy13FX<@}cQk?KiyuBoX#sQS_U`KGI2%fP$KM6Q56xc>932rwR222^u{Jv$3fKC6Gp z4_3W3_Z&IQuGiyxPfBAyiQ*5Q9RQZio)+an1HCD^srpn_qI|n@?n5mPI35CWl^I~o z)sM-#(w-~nuH(wl!yylEkCKea3H+x``ZMha6K7NDetMlF^1#$YF%kChBh#fjiWDZT zRxXh4AR7KY1|Y_i<%>P#e8PO%R(o9cwO9>ExY&O3{R#D?kRW8<$toaS6l9lKzWfQ@ ztcJFuV&O;YnKj@6uy1`~y`!B)v|%((5V2RZiTe9lQL&LfC#aT~l~ejmh01;u z(fQq)MFpos{K)?9h?V7#cBPL0F=5MsoXz)?atv%ge>b;ffp}3PR~a$IsiIC#2K{9! zPTK%V_|vRkc-EWG9FvgW;51t?84S}NxK>tOLp@v8rAuPE7AV`Degfe+E0^U_rY1XiQmEM@{&EZqa8W*=-b_tHfP)ul`_ks z$&Z8C1AeKx5{-LpA9#Wnr_?>{NUoT(45kW;djNov99fkX1HXWzIBzQiBWBLuj;rG$ z1u)f)frrPB7sa1oCFr_O6%Z-5l)j$rR8WBqbjjw%KhenHET7bE?E+Flr$q^ z#=7M1matm|8e$ZE!^R@Sr(^S$MAxX#T@7T`$|zT=8PBkNM=9z~OYxh)k7HicUT^|? zfp${UaV0+Zn3vKCx|`S1a(-ZO@VE9kV>r#w<6;S3&c!h^;j^5RzdU|>@fh~D#m$NB zdPJQA&_Iltk_f)G)LfMD(w%W5C55-BL zma3yfI{VWHck8`$%x*0B4}cLI&@+GTh@+ics;!O?tN}SXDujS83WR+>#%yP&6!)&T zK7GJKjjeDX(rTtpO7>>;(8Nsu+3JE`l4Nv0W?{6Cocg?!Y-dfHvMF;!ci)_0TtxCk*--8 zylE)avVGeKF?#HQVgo(s(EI#pZ|iz^yrZBG?K!EL*>ReDwROgPY%c`DYYoXm?3HRu z?%Pr&mzFW7tLW!=&^2j^{{*%m8x8xuNBt)#qG95k&FRYTkCoL>zq*Ze)BdGx$e*p+ z-cdKp>8U=5KT;^TqT}NTlmsQq@L^-)JOfsCf4O!8A22)M;FPxavew*FPoU8c;S+r+ zJ_ETOZC1v+28Ra4*i~S$1Sg0DN%y5H(lL++kWFSxH?Oa7%YuoYbi zMC%XNjxsLJocbfc^dbchTVqFN=kOJEzy4={DgP7MB~7wYt?9fxraJANfr(SD0_k1p z86M&@Y>_iB`jd9tWDFh}Cl%(X!O7H8BlMsDK^i%pRPNF(`R%q6j15fio3UbDO!dnN z33?r_lJiU>S+7a3$ZKZiPojWh+^V4o<=snQ*AiT33>bnsd7m(iON4+Afyc1Io~t9; zHT;MQ5&6o|k_~Y5UIvz3^_t6kiW^Xtg&jPZIhznjG`mPgTV}skGBh(X9+257l%Leh z_SotAx^u^sR3^S(PYz*lB`YJ>DSflPIgsL>fBjP?Zq>aZRY&)qfmi}1n3gnCY6{48 zpNeMYn`<5ZwwiZ?@u7{oZ*@e=7hG8u1s|rGOgFnA>oZF{IF~FoWy_ZeAXmGhxWZMh zES1lW`Gjk)ILpi2%ZuL07L~~`A<1XH2{C~!`m|JI)$aSKys(=knn##{<At0g7 z+#Ks(j>sC>Yu}d80XS}Phvl}tYMq8`sNppq^YmgU3Pc^yD5qee26kYG_qUcjv;I}tvKkE+76N5AFNuOw$4(eN>uw)zqPiK`^Q z))x#4Ev25=q^&5iRs5M3aZ`nMHsV ykyico-p&Zpo!XG<*>MJcZTQV27=?BBwXOkp9eomwh@x@I!f?t?t?3bp4ddH9pdlYT+9 zuq4QtNmo(A++#?o*pW0++v_q~ac^^C{gDVFKc6HN3@YC*kru!X@6=$a&As-%@0z4XMjjBBhRA>6{ z@e0M_H*&HgY?-QP6y{%7N)|+d(q8;!seY`Sb1@G2msRyb@0+7#M(7_RW8ZZu%OLY) zcm21vTK0UQnwtSi%LnuY2Z|9^VOf9FLARnKWu@!q-y>>6fH&YaRbg2WaQbz8cMxL=AQ|8BI*m{~T zuF33IiX8E|N_n}KZG2i?V0r3})p7swwblS`PcO5VN=Pb@{$X;(1&zXI=G&U=22N+a zP&yaPn^(oyPhgy?&J4`p|z%QN>Q=*Mh&tBEvp9>KXzK!sMjCl$8;MjN85jPHWYtKe?4U~ z*l<7=NqVLrVMld(+n%*mTeLHpO*;`)I5I@6>46oK_2cWcaQltV(`T1nsq+%OQ58A_ z;!gm(2%smn2lwbw1J2&Nf1!_rCg+A^R~zJuUEdq{g`0zJQltCu_XJBgd9_WJp6ufo zHS>F=U%yhmxmZlK1rtX&vHar97Zg;>RRu-}axI4pPw4@yjtM=iv7TSgNz`I*!n*2%f{Q7q%KQu<#i?;e=D zgX{PDMjqv0TUXeob`RTYQeEzASd|S?0HHOhLbh5At?vQDwRG^MrFpk2=q6|V{U>6*aMs|&pVgrNrKPf&)YiV7OK3furWuWT%qBYo29?%;!?(46f=}y zBF(NsaeXqH51GHe9Mhwa!Q+}|_ugAR3#bUblvQ)weQy^*a_d}cT?ViuU%p`(an5S{ z-RdjG$E2!)ip*nvwf1AKfmsBQf~^%u7-aoU#l`R?{pj7W*wEhxYAXTWCJ=^AbZ z3g4=#?+V247Hf7#*U?J6rsK@T7esf=BOzGNJbKxiM;V-dt|Uq{!Hxe7UHo z$h2gmYARrdi$5ZA%d8ugq9)nlvPvVG9Pu15nS@af@-Qt5t_xM^Q8Ap$Vl~Q9`PxHm z3?eaMrXm$1*(tdK&RtDbv{oz_l=g*R_*tw%6hlj$Pk!4^_36$qiQ&#ubiBv<{+)BT zmr~xzxmSjxvA;r(?owjT5ZL{gU#mG4sc^g{W_Kt~ zgr$xa0e4sDU$2AK&94Uq-|8``71GuUESnc6-$IPu%qFF!LOQ=?{5o2plj5SAZQn`+ z4PND!wwSCN`snZXZLk!gO}4JDHsS=m_CB0$tcq(uL)Hn?gQ??2v299S&rbSLwLce5JaALF_>86R$Cd4`2q zmOD9?5JfsL6vAVyE&IXXJ)_INoLA;lkt~ioRoVP5%A&VrHL_}W-ye@v`{2%=BRWO| z8}yd8TNhS;@P1uQt-?=rf7K!R{c=6<5N2FGiC1|H=o2=QK&J1+pO{_=53%dgSf1Lm zw#Kxa@Y9Wq`ND+2btNwMmEENod-&_k^t}`XZ9zgtz*j}O_ki{FA&m=6%{>_QDG@NiA|A42*lCO=Rd#J&DH~^%_Hn(Z#j5|b zMMx@Wx#ir&?7Hldv&x9?zGgbb!HG$G=XVb--lkiP^Wzsr8mA@^7JXi4W9LiHJRnz_POWo>>cmUvx{~6k+weytt-Dr#i>gk!YG*#uCb6=1xrso zyw{t4ecRQO2g9iL08>Li+ne759BB%8FiQ@) z6oJar?mFj{eznVM&nw5M6t(rh#wNe}tKnK2d(En*kJ@-(=dfQ9gOoP&j~3st>PXQ7 zcARiz(~;b=s&>Y~{^v$+K;nmEh~oen2%myz^4C}1jo5t#Kj<*S`PBe3&;ymS(FE_$Jz#Y`HvHCc;TZ!JjauuN;Kb*s zVFHEUL*k4x1sijb4na>CpV406GJ=4ltIU1Rx+i>12C!6{aV3q!t+ld*GqzeuZc(@g zbAnd4R2n@bbW~J3g(rw~?Kt)1^OaM{cvD~p2a09OvRZ7T)Kx~&=Yt{E%8^~RF>_a= z$mGnCF*K*-Fjb^h`_9ypfR?+_IzV^utI^@pqT+-DT>KJ!3kaYn zp~Sku5>Ti=aI`8XSy5zF^Zwl)qXWO|OJH4km*s5{|7P|zUJ}o__Z~sueWL=9b7Kd1 zK%X>nKI=t8GZl{{blTIQJV|Bd?4Vl1vVm{aGI-C!7yyv&!u9E`)NOaEx+@vbQ*#1% zpgv&GixLd(t;R^dfe>rA;*L!6csqC)8lH@&q=e z&l#i{`Kpl`f?pi*%qXdGfcKUm*Bg^xp3B@kgFf}bFW%Ao?U~q`tsh32R2nTL@zbW{ zzNJbx9ynhMn18g(X&2xfmDlnG7=sY)rvA!CcH@G3#}RxS=}(EqL0E8>0;%IETp&5BK)}gl&%M(;e+7M${KskbEw#l=uq40MzlH zZh}(qLW=aq=O0L9B4Du=9yZADBv_~#MXsSjye;r~1%NLuny5s8hc_>%50AG$d)3gm3Td0F)m6 z4?HCB=->AIe+;5=(7z+t|KLOb0qg&>3pc@~kGkuft|kpIfRD1ghTJ!qH=+Lrka7^M literal 0 HcmV?d00001 diff --git a/vendor/github.com/pb33f/libopenapi/resolver/resolver.go b/vendor/github.com/pb33f/libopenapi/resolver/resolver.go new file mode 100644 index 0000000000..8f06462cac --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/resolver/resolver.go @@ -0,0 +1,457 @@ +// Copyright 2022 Dave Shanley / Quobix +// SPDX-License-Identifier: MIT + +package resolver + +import ( + "fmt" + + "github.com/pb33f/libopenapi/index" + "github.com/pb33f/libopenapi/utils" + "gopkg.in/yaml.v3" +) + +// ResolvingError represents an issue the resolver had trying to stitch the tree together. +type ResolvingError struct { + // ErrorRef is the error thrown by the resolver + ErrorRef error + + // Node is the *yaml.Node reference that contains the resolving error + Node *yaml.Node + + // Path is the shortened journey taken by the resolver + Path string + + // CircularReference is set if the error is a reference to the circular reference. + CircularReference *index.CircularReferenceResult +} + +func (r *ResolvingError) Error() string { + return fmt.Sprintf("%s: %s [%d:%d]", r.ErrorRef.Error(), + r.Path, r.Node.Line, r.Node.Column) +} + +// Resolver will use a *index.SpecIndex to stitch together a resolved root tree using all the discovered +// references in the doc. +type Resolver struct { + specIndex *index.SpecIndex + resolvedRoot *yaml.Node + resolvingErrors []*ResolvingError + circularReferences []*index.CircularReferenceResult + referencesVisited int + indexesVisited int + journeysTaken int + relativesSeen int +} + +// NewResolver will create a new resolver from a *index.SpecIndex +func NewResolver(index *index.SpecIndex) *Resolver { + if index == nil { + return nil + } + return &Resolver{ + specIndex: index, + resolvedRoot: index.GetRootNode(), + } +} + +// GetResolvingErrors returns all errors found during resolving +func (resolver *Resolver) GetResolvingErrors() []*ResolvingError { + return resolver.resolvingErrors +} + +// GetCircularErrors returns all circular reference errors found. +func (resolver *Resolver) GetCircularErrors() []*index.CircularReferenceResult { + return resolver.circularReferences +} + +// GetPolymorphicCircularErrors returns all circular errors that stem from polymorphism +func (resolver *Resolver) GetPolymorphicCircularErrors() []*index.CircularReferenceResult { + var res []*index.CircularReferenceResult + for i := range resolver.circularReferences { + if !resolver.circularReferences[i].IsInfiniteLoop { + continue + } + if !resolver.circularReferences[i].IsPolymorphicResult { + continue + } + res = append(res, resolver.circularReferences[i]) + } + return res +} + +// GetNonPolymorphicCircularErrors returns all circular errors that DO NOT stem from polymorphism +func (resolver *Resolver) GetNonPolymorphicCircularErrors() []*index.CircularReferenceResult { + var res []*index.CircularReferenceResult + for i := range resolver.circularReferences { + if !resolver.circularReferences[i].IsInfiniteLoop { + continue + } + + if !resolver.circularReferences[i].IsPolymorphicResult { + res = append(res, resolver.circularReferences[i]) + } + } + + return res +} + +// GetJourneysTaken returns the number of journeys taken by the resolver +func (resolver *Resolver) GetJourneysTaken() int { + return resolver.journeysTaken +} + +// GetReferenceVisited returns the number of references visited by the resolver +func (resolver *Resolver) GetReferenceVisited() int { + return resolver.referencesVisited +} + +// GetIndexesVisited returns the number of indexes visited by the resolver +func (resolver *Resolver) GetIndexesVisited() int { + return resolver.indexesVisited +} + +// GetRelativesSeen returns the number of siblings (nodes at the same level) seen for each reference found. +func (resolver *Resolver) GetRelativesSeen() int { + return resolver.relativesSeen +} + +// Resolve will resolve the specification, everything that is not polymorphic and not circular, will be resolved. +// this data can get big, it results in a massive duplication of data. This is a destructive method and will permanently +// re-organize the node tree. Make sure you have copied your original tree before running this (if you want to preserve +// original data) +func (resolver *Resolver) Resolve() []*ResolvingError { + + visitIndex(resolver, resolver.specIndex) + + for _, circRef := range resolver.circularReferences { + // If the circular reference is not required, we can ignore it, as it's a terminable loop rather than an infinite one + if !circRef.IsInfiniteLoop { + continue + } + + resolver.resolvingErrors = append(resolver.resolvingErrors, &ResolvingError{ + ErrorRef: fmt.Errorf("Infinite circular reference detected: %s", circRef.Start.Name), + Node: circRef.LoopPoint.Node, + Path: circRef.GenerateJourneyPath(), + }) + } + + return resolver.resolvingErrors +} + +// CheckForCircularReferences Check for circular references, without resolving, a non-destructive run. +func (resolver *Resolver) CheckForCircularReferences() []*ResolvingError { + visitIndexWithoutDamagingIt(resolver, resolver.specIndex) + for _, circRef := range resolver.circularReferences { + // If the circular reference is not required, we can ignore it, as it's a terminable loop rather than an infinite one + if !circRef.IsInfiniteLoop { + continue + } + + resolver.resolvingErrors = append(resolver.resolvingErrors, &ResolvingError{ + ErrorRef: fmt.Errorf("Infinite circular reference detected: %s", circRef.Start.Name), + Node: circRef.LoopPoint.Node, + Path: circRef.GenerateJourneyPath(), + CircularReference: circRef, + }) + } + // update our index with any circular refs we found. + resolver.specIndex.SetCircularReferences(resolver.circularReferences) + return resolver.resolvingErrors +} + +func visitIndexWithoutDamagingIt(res *Resolver, idx *index.SpecIndex) { + mapped := idx.GetMappedReferencesSequenced() + mappedIndex := idx.GetMappedReferences() + res.indexesVisited++ + for _, ref := range mapped { + seenReferences := make(map[string]bool) + var journey []*index.Reference + res.journeysTaken++ + res.VisitReference(ref.Reference, seenReferences, journey, false) + } + schemas := idx.GetAllComponentSchemas() + for s, schemaRef := range schemas { + if mappedIndex[s] == nil { + seenReferences := make(map[string]bool) + var journey []*index.Reference + res.journeysTaken++ + res.VisitReference(schemaRef, seenReferences, journey, false) + } + } + for _, c := range idx.GetChildren() { + visitIndexWithoutDamagingIt(res, c) + } +} + +func visitIndex(res *Resolver, idx *index.SpecIndex) { + mapped := idx.GetMappedReferencesSequenced() + mappedIndex := idx.GetMappedReferences() + res.indexesVisited++ + + for _, ref := range mapped { + seenReferences := make(map[string]bool) + var journey []*index.Reference + res.journeysTaken++ + if ref != nil && ref.Reference != nil { + ref.Reference.Node.Content = res.VisitReference(ref.Reference, seenReferences, journey, true) + } + } + + schemas := idx.GetAllComponentSchemas() + for s, schemaRef := range schemas { + if mappedIndex[s] == nil { + seenReferences := make(map[string]bool) + var journey []*index.Reference + res.journeysTaken++ + schemaRef.Node.Content = res.VisitReference(schemaRef, seenReferences, journey, true) + } + } + + // map everything + for _, sequenced := range idx.GetAllSequencedReferences() { + locatedDef := mappedIndex[sequenced.Definition] + if locatedDef != nil { + if !locatedDef.Circular && locatedDef.Seen { + sequenced.Node.Content = locatedDef.Node.Content + } + } + } + for _, c := range idx.GetChildren() { + visitIndex(res, c) + } +} + +// VisitReference will visit a reference as part of a journey and will return resolved nodes. +func (resolver *Resolver) VisitReference(ref *index.Reference, seen map[string]bool, journey []*index.Reference, resolve bool) []*yaml.Node { + resolver.referencesVisited++ + if ref.Resolved || ref.Seen { + return ref.Node.Content + } + + journey = append(journey, ref) + relatives := resolver.extractRelatives(ref.Node, seen, journey, resolve) + + seen = make(map[string]bool) + + seen[ref.Definition] = true + for _, r := range relatives { + // check if we have seen this on the journey before, if so! it's circular + skip := false + for i, j := range journey { + if j.Definition == r.Definition { + + var foundDup *index.Reference + foundRefs := resolver.specIndex.SearchIndexForReference(r.Definition) + if len(foundRefs) > 0 { + foundDup = foundRefs[0] + } + + var circRef *index.CircularReferenceResult + if !foundDup.Circular { + loop := append(journey, foundDup) + + visitedDefinitions := map[string]bool{} + isInfiniteLoop, _ := resolver.isInfiniteCircularDependency(foundDup, visitedDefinitions, nil) + circRef = &index.CircularReferenceResult{ + Journey: loop, + Start: foundDup, + LoopIndex: i, + LoopPoint: foundDup, + IsInfiniteLoop: isInfiniteLoop, + } + resolver.circularReferences = append(resolver.circularReferences, circRef) + + foundDup.Seen = true + foundDup.Circular = true + } + skip = true + } + } + + if !skip { + var original *index.Reference + foundRefs := resolver.specIndex.SearchIndexForReference(r.Definition) + if len(foundRefs) > 0 { + original = foundRefs[0] + } + resolved := resolver.VisitReference(original, seen, journey, resolve) + if resolve { + r.Node.Content = resolved // this is where we perform the actual resolving. + } + r.Seen = true + ref.Seen = true + } + } + ref.Resolved = true + ref.Seen = true + + return ref.Node.Content +} + +func (resolver *Resolver) isInfiniteCircularDependency(ref *index.Reference, visitedDefinitions map[string]bool, initialRef *index.Reference) (bool, map[string]bool) { + if ref == nil { + return false, visitedDefinitions + } + + for refDefinition := range ref.RequiredRefProperties { + r := resolver.specIndex.GetMappedReferences()[refDefinition] + if initialRef != nil && initialRef.Definition == r.Definition { + return true, visitedDefinitions + } + + if visitedDefinitions[r.Definition] { + continue + } + visitedDefinitions[r.Definition] = true + + ir := initialRef + if ir == nil { + ir = ref + } + + var isChildICD bool + isChildICD, visitedDefinitions = resolver.isInfiniteCircularDependency(r, visitedDefinitions, ir) + if isChildICD { + return true, visitedDefinitions + } + } + + return false, visitedDefinitions +} + +func (resolver *Resolver) extractRelatives(node *yaml.Node, + foundRelatives map[string]bool, + journey []*index.Reference, resolve bool) []*index.Reference { + + if len(journey) > 100 { + return nil + } + + var found []*index.Reference + if len(node.Content) > 0 { + for i, n := range node.Content { + if utils.IsNodeMap(n) || utils.IsNodeArray(n) { + found = append(found, resolver.extractRelatives(n, foundRelatives, journey, resolve)...) + } + + if i%2 == 0 && n.Value == "$ref" { + + if !utils.IsNodeStringValue(node.Content[i+1]) { + continue + } + + value := node.Content[i+1].Value + + ref := resolver.specIndex.SearchIndexForReference(value) + + if ref == nil { + _, path := utils.ConvertComponentIdIntoFriendlyPathSearch(value) + err := &ResolvingError{ + ErrorRef: fmt.Errorf("cannot resolve reference `%s`, it's missing", value), + Node: n, + Path: path, + } + resolver.resolvingErrors = append(resolver.resolvingErrors, err) + continue + } + + r := &index.Reference{ + Definition: value, + Name: value, + Node: node, + } + + found = append(found, r) + + foundRelatives[value] = true + } + + if i%2 == 0 && n.Value != "$ref" && n.Value != "" { + + if n.Value == "allOf" || + n.Value == "oneOf" || + n.Value == "anyOf" { + + // if this is a polymorphic link, we want to follow it and see if it becomes circular + if utils.IsNodeMap(node.Content[i+1]) { // check for nested items + // check if items is present, to indicate an array + if _, v := utils.FindKeyNodeTop("items", node.Content[i+1].Content); v != nil { + if utils.IsNodeMap(v) { + if d, _, l := utils.IsNodeRefValue(v); d { + ref := resolver.specIndex.GetMappedReferences()[l] + if ref != nil && !ref.Circular { + circ := false + for f := range journey { + if journey[f].Definition == ref.Definition { + circ = true + break + } + } + if !circ { + resolver.VisitReference(ref, foundRelatives, journey, resolve) + } else { + loop := append(journey, ref) + circRef := &index.CircularReferenceResult{ + Journey: loop, + Start: ref, + LoopIndex: i, + LoopPoint: ref, + IsPolymorphicResult: true, + } + + ref.Seen = true + ref.Circular = true + resolver.circularReferences = append(resolver.circularReferences, circRef) + } + } + } + } + } + } + // for array based polymorphic items + if utils.IsNodeArray(node.Content[i+1]) { // check for nested items + // check if items is present, to indicate an array + for q := range node.Content[i+1].Content { + v := node.Content[i+1].Content[q] + if utils.IsNodeMap(v) { + if d, _, l := utils.IsNodeRefValue(v); d { + ref := resolver.specIndex.GetMappedReferences()[l] + if ref != nil && !ref.Circular { + circ := false + for f := range journey { + if journey[f].Definition == ref.Definition { + circ = true + break + } + } + if !circ { + resolver.VisitReference(ref, foundRelatives, journey, resolve) + } else { + loop := append(journey, ref) + circRef := &index.CircularReferenceResult{ + Journey: loop, + Start: ref, + LoopIndex: i, + LoopPoint: ref, + IsPolymorphicResult: true, + } + + ref.Seen = true + ref.Circular = true + resolver.circularReferences = append(resolver.circularReferences, circRef) + } + } + } + } + } + } + break + } + } + } + } + resolver.relativesSeen += len(found) + return found +} diff --git a/vendor/github.com/pb33f/libopenapi/utils/nodes.go b/vendor/github.com/pb33f/libopenapi/utils/nodes.go new file mode 100644 index 0000000000..b4bdee0993 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/utils/nodes.go @@ -0,0 +1,68 @@ +// Copyright 2023 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package utils + +import "gopkg.in/yaml.v3" + +func CreateRefNode(ref string) *yaml.Node { + m := CreateEmptyMapNode() + nodes := make([]*yaml.Node, 2) + nodes[0] = CreateStringNode("$ref") + nodes[1] = CreateStringNode(ref) + nodes[1].Style = yaml.SingleQuotedStyle + m.Content = nodes + return m +} + +func CreateEmptyMapNode() *yaml.Node { + n := &yaml.Node{ + Kind: yaml.MappingNode, + Tag: "!!map", + } + return n +} + +func CreateEmptySequenceNode() *yaml.Node { + n := &yaml.Node{ + Kind: yaml.SequenceNode, + Tag: "!!seq", + } + return n +} + +func CreateStringNode(str string) *yaml.Node { + n := &yaml.Node{ + Kind: yaml.ScalarNode, + Tag: "!!str", + Value: str, + } + return n +} + +func CreateBoolNode(str string) *yaml.Node { + n := &yaml.Node{ + Kind: yaml.ScalarNode, + Tag: "!!bool", + Value: str, + } + return n +} + +func CreateIntNode(str string) *yaml.Node { + n := &yaml.Node{ + Kind: yaml.ScalarNode, + Tag: "!!int", + Value: str, + } + return n +} + +func CreateFloatNode(str string) *yaml.Node { + n := &yaml.Node{ + Kind: yaml.ScalarNode, + Tag: "!!float", + Value: str, + } + return n +} diff --git a/vendor/github.com/pb33f/libopenapi/utils/type_check.go b/vendor/github.com/pb33f/libopenapi/utils/type_check.go new file mode 100644 index 0000000000..aceee4bb51 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/utils/type_check.go @@ -0,0 +1,49 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package utils + +import "fmt" + +// AreValuesCorrectlyTyped will look through an array of unknown values and check they match +// against the supplied type as a string. The return value is empty if everything is OK, or it +// contains failures in the form of a value as a key and a message as to why it's not valid +func AreValuesCorrectlyTyped(valType string, values interface{}) map[string]string { + var arr []interface{} + if _, ok := values.([]interface{}); !ok { + return nil + } + arr = values.([]interface{}) + + results := make(map[string]string) + for _, v := range arr { + switch v.(type) { + case string: + if valType != "string" { + results[v.(string)] = fmt.Sprintf("enum value '%v' is a "+ + "string, but it's defined as a '%v'", v, valType) + } + case int64: + if valType != "integer" && valType != "number" { + results[fmt.Sprintf("%v", v)] = fmt.Sprintf("enum value '%v' is a "+ + "integer, but it's defined as a '%v'", v, valType) + } + case int: + if valType != "integer" && valType != "number" { + results[fmt.Sprintf("%v", v)] = fmt.Sprintf("enum value '%v' is a "+ + "integer, but it's defined as a '%v'", v, valType) + } + case float64: + if valType != "number" { + results[fmt.Sprintf("%v", v)] = fmt.Sprintf("enum value '%v' is a "+ + "number, but it's defined as a '%v'", v, valType) + } + case bool: + if valType != "boolean" { + results[fmt.Sprintf("%v", v)] = fmt.Sprintf("enum value '%v' is a "+ + "boolean, but it's defined as a '%v'", v, valType) + } + } + } + return results +} diff --git a/vendor/github.com/pb33f/libopenapi/utils/utils.go b/vendor/github.com/pb33f/libopenapi/utils/utils.go new file mode 100644 index 0000000000..d9c27e5d38 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/utils/utils.go @@ -0,0 +1,638 @@ +package utils + +import ( + "encoding/json" + "fmt" + "net/url" + "regexp" + "strconv" + "strings" + + "github.com/vmware-labs/yaml-jsonpath/pkg/yamlpath" + "gopkg.in/yaml.v3" +) + +type Case int8 + +const ( + // OpenApi3 is used by all OpenAPI 3+ docs + OpenApi3 = "openapi" + + // OpenApi2 is used by all OpenAPI 2 docs, formerly known as swagger. + OpenApi2 = "swagger" + + // AsyncApi is used by akk AsyncAPI docs, all versions. + AsyncApi = "asyncapi" + + PascalCase Case = iota + CamelCase + ScreamingSnakeCase + SnakeCase + KebabCase + ScreamingKebabCase + RegularCase + UnknownCase +) + +// FindNodes will find a node based on JSONPath, it accepts raw yaml/json as input. +func FindNodes(yamlData []byte, jsonPath string) ([]*yaml.Node, error) { + jsonPath = FixContext(jsonPath) + + var node yaml.Node + yaml.Unmarshal(yamlData, &node) + + path, err := yamlpath.NewPath(jsonPath) + if err != nil { + return nil, err + } + results, _ := path.Find(&node) + return results, nil +} + +// FindLastChildNode will find the last node in a tree, based on a starting node. +// Deprecated: This function is deprecated, use FindLastChildNodeWithLevel instead. +// this has the potential to cause a stack overflow, so use with caution. It will be removed later. +func FindLastChildNode(node *yaml.Node) *yaml.Node { + s := len(node.Content) - 1 + if s < 0 { + s = 0 + } + if len(node.Content) > 0 && len(node.Content[s].Content) > 0 { + return FindLastChildNode(node.Content[s]) + } else { + if len(node.Content) > 0 { + return node.Content[s] + } + return node + } +} + +// FindLastChildNodeWithLevel will find the last node in a tree, based on a starting node. +// Will stop searching after 100 levels, because that's just silly, we probably have a loop. +func FindLastChildNodeWithLevel(node *yaml.Node, level int) *yaml.Node { + if level > 100 { + return node // we've gone too far, give up. + } + s := len(node.Content) - 1 + if s < 0 { + s = 0 + } + if len(node.Content) > 0 && len(node.Content[s].Content) > 0 { + level++ + return FindLastChildNodeWithLevel(node.Content[s], level) + } else { + if len(node.Content) > 0 { + return node.Content[s] + } + return node + } +} + +// BuildPath will construct a JSONPath from a base and an array of strings. +func BuildPath(basePath string, segs []string) string { + + path := strings.Join(segs, ".") + + // trim that last period. + if len(path) > 0 && path[len(path)-1] == '.' { + path = path[:len(path)-1] + } + return fmt.Sprintf("%s.%s", basePath, path) +} + +// FindNodesWithoutDeserializing will find a node based on JSONPath, without deserializing from yaml/json +func FindNodesWithoutDeserializing(node *yaml.Node, jsonPath string) ([]*yaml.Node, error) { + jsonPath = FixContext(jsonPath) + + path, err := yamlpath.NewPath(jsonPath) + if err != nil { + return nil, err + } + results, _ := path.Find(node) + return results, nil +} + +// ConvertInterfaceIntoStringMap will convert an unknown input into a string map. +func ConvertInterfaceIntoStringMap(context interface{}) map[string]string { + converted := make(map[string]string) + if context != nil { + if v, ok := context.(map[string]interface{}); ok { + for k, n := range v { + if s, okB := n.(string); okB { + converted[k] = s + } + } + } + if v, ok := context.(map[string]string); ok { + for k, n := range v { + converted[k] = n + } + } + } + return converted +} + +// ConvertInterfaceToStringArray will convert an unknown input map type into a string array/slice +func ConvertInterfaceToStringArray(raw interface{}) []string { + if vals, ok := raw.(map[string]interface{}); ok { + var s []string + for _, v := range vals { + if g, y := v.([]interface{}); y { + for _, q := range g { + s = append(s, fmt.Sprint(q)) + } + } + } + return s + } + if vals, ok := raw.(map[string][]string); ok { + var s []string + for _, v := range vals { + s = append(s, v...) + } + return s + } + return nil +} + +// ConvertInterfaceArrayToStringArray will convert an unknown interface array type, into a string slice +func ConvertInterfaceArrayToStringArray(raw interface{}) []string { + if vals, ok := raw.([]interface{}); ok { + s := make([]string, len(vals)) + for i, v := range vals { + s[i] = fmt.Sprint(v) + } + return s + } + if vals, ok := raw.([]string); ok { + return vals + } + return nil +} + +// ExtractValueFromInterfaceMap pulls out an unknown value from a map using a string key +func ExtractValueFromInterfaceMap(name string, raw interface{}) interface{} { + + if propMap, ok := raw.(map[string]interface{}); ok { + if props, okn := propMap[name].([]interface{}); okn { + return props + } else { + return propMap[name] + } + } + if propMap, ok := raw.(map[string][]string); ok { + return propMap[name] + } + + return nil +} + +// FindFirstKeyNode will locate the first key and value yaml.Node based on a key. +func FindFirstKeyNode(key string, nodes []*yaml.Node, depth int) (keyNode *yaml.Node, valueNode *yaml.Node) { + if depth > 40 { + return nil, nil + } + for i, v := range nodes { + if key != "" && key == v.Value { + if i+1 >= len(nodes) { + return v, nodes[i] // this is the node we need. + } + return v, nodes[i+1] // next node is what we need. + } + if len(v.Content) > 0 { + depth++ + x, y := FindFirstKeyNode(key, v.Content, depth) + if x != nil && y != nil { + return x, y + } + } + } + return nil, nil +} + +// KeyNodeResult is a result from a KeyNodeSearch performed by the FindAllKeyNodesWithPath +type KeyNodeResult struct { + KeyNode *yaml.Node + ValueNode *yaml.Node + Parent *yaml.Node + Path []yaml.Node +} + +// KeyNodeSearch keeps a track of everything we have found on our adventure down the trees. +type KeyNodeSearch struct { + Key string + Ignore []string + Results []*KeyNodeResult + AllowExtensions bool +} + +// FindKeyNodeTop is a non-recursive search of top level nodes for a key, will not look at content. +// Returns the key and value +func FindKeyNodeTop(key string, nodes []*yaml.Node) (keyNode *yaml.Node, valueNode *yaml.Node) { + for i, v := range nodes { + if i%2 != 0 { + continue + } + if strings.ToLower(key) == strings.ToLower(v.Value) { + return v, nodes[i+1] // next node is what we need. + } + } + return nil, nil +} + +// FindKeyNode is a non-recursive search of a *yaml.Node Content for a child node with a key. +// Returns the key and value +func FindKeyNode(key string, nodes []*yaml.Node) (keyNode *yaml.Node, valueNode *yaml.Node) { + + //numNodes := len(nodes) + for i, v := range nodes { + if i%2 == 0 && key == v.Value { + return v, nodes[i+1] // next node is what we need. + } + for x, j := range v.Content { + if key == j.Value { + if IsNodeMap(v) { + if x+1 == len(v.Content) { + return v, v.Content[x] + } + return v, v.Content[x+1] // next node is what we need. + + } + if IsNodeArray(v) { + return v, v.Content[x] + } + } + } + } + return nil, nil +} + +// FindKeyNodeFull is an overloaded version of FindKeyNode. This version however returns keys, labels and values. +// generally different things are required from different node trees, so depending on what this function is looking at +// it will return different things. +func FindKeyNodeFull(key string, nodes []*yaml.Node) (keyNode *yaml.Node, labelNode *yaml.Node, valueNode *yaml.Node) { + for i := range nodes { + if i%2 == 0 && key == nodes[i].Value { + return nodes[i], nodes[i], nodes[i+1] // next node is what we need. + } + } + for _, v := range nodes { + for x := range v.Content { + if key == v.Content[x].Value { + if IsNodeMap(v) { + if x+1 == len(v.Content) { + return v, v.Content[x], v.Content[x] + } + return v, v.Content[x], v.Content[x+1] + } + if IsNodeArray(v) { + return v, v.Content[x], v.Content[x] + } + } + } + } + return nil, nil, nil +} + +// FindKeyNodeFullTop is an overloaded version of FindKeyNodeFull. This version only looks at the top +// level of the node and not the children. +func FindKeyNodeFullTop(key string, nodes []*yaml.Node) (keyNode *yaml.Node, labelNode *yaml.Node, valueNode *yaml.Node) { + for i := range nodes { + if i%2 != 0 { + continue + } + if i%2 == 0 && key == nodes[i].Value { + return nodes[i], nodes[i], nodes[i+1] // next node is what we need. + } + } + return nil, nil, nil +} + +type ExtensionNode struct { + Key *yaml.Node + Value *yaml.Node +} + +func FindExtensionNodes(nodes []*yaml.Node) []*ExtensionNode { + var extensions []*ExtensionNode + for i, v := range nodes { + if i%2 == 0 && strings.HasPrefix(v.Value, "x-") { + if i+1 < len(nodes) { + extensions = append(extensions, &ExtensionNode{ + Key: v, + Value: nodes[i+1], + }) + } + } + } + return extensions +} + +var ObjectLabel = "object" +var IntegerLabel = "integer" +var NumberLabel = "number" +var StringLabel = "string" +var BinaryLabel = "binary" +var ArrayLabel = "array" +var BooleanLabel = "boolean" +var SchemaSource = "https://json-schema.org/draft/2020-12/schema" +var SchemaId = "https://pb33f.io/openapi-changes/schema" + +func MakeTagReadable(node *yaml.Node) string { + switch node.Tag { + case "!!map": + return ObjectLabel + case "!!seq": + return ArrayLabel + case "!!str": + return StringLabel + case "!!int": + return IntegerLabel + case "!!float": + return NumberLabel + case "!!bool": + return BooleanLabel + } + return "unknown" +} + +// IsNodeMap checks if the node is a map type +func IsNodeMap(node *yaml.Node) bool { + if node == nil { + return false + } + return node.Tag == "!!map" +} + +// IsNodePolyMorphic will return true if the node contains polymorphic keys. +func IsNodePolyMorphic(node *yaml.Node) bool { + for i, v := range node.Content { + if i%2 == 0 { + if v.Value == "anyOf" || v.Value == "oneOf" || v.Value == "allOf" { + return true + } + } + } + return false +} + +// IsNodeArray checks if a node is an array type +func IsNodeArray(node *yaml.Node) bool { + if node == nil { + return false + } + return node.Tag == "!!seq" +} + +// IsNodeStringValue checks if a node is a string value +func IsNodeStringValue(node *yaml.Node) bool { + if node == nil { + return false + } + return node.Tag == "!!str" +} + +// IsNodeIntValue will check if a node is an int value +func IsNodeIntValue(node *yaml.Node) bool { + if node == nil { + return false + } + return node.Tag == "!!int" +} + +// IsNodeFloatValue will check is a node is a float value. +func IsNodeFloatValue(node *yaml.Node) bool { + if node == nil { + return false + } + return node.Tag == "!!float" +} + +// IsNodeBoolValue will check is a node is a bool +func IsNodeBoolValue(node *yaml.Node) bool { + if node == nil { + return false + } + return node.Tag == "!!bool" +} + +func IsNodeRefValue(node *yaml.Node) (bool, *yaml.Node, string) { + if node == nil { + return false, nil, "" + } + + for i, r := range node.Content { + if i%2 == 0 { + if r.Value == "$ref" { + return true, r, node.Content[i+1].Value + } + } + } + return false, nil, "" +} + +// FixContext will clean up a JSONpath string to be correctly traversable. +func FixContext(context string) string { + tokens := strings.Split(context, ".") + var cleaned = []string{} + + for i, t := range tokens { + if v, err := strconv.Atoi(t); err == nil { + if v < 200 { // codes start here + if cleaned[i-1] != "" { + cleaned[i-1] += fmt.Sprintf("[%v]", t) + } + } else { + cleaned = append(cleaned, t) + } + continue + } + cleaned = append(cleaned, strings.ReplaceAll(t, "(root)", "$")) + } + + return strings.Join(cleaned, ".") +} + +// IsJSON will tell you if a string is JSON or not. +func IsJSON(testString string) bool { + if testString == "" { + return false + } + runes := []rune(strings.TrimSpace(testString)) + if runes[0] == '{' && runes[len(runes)-1] == '}' { + return true + } + return false +} + +// IsYAML will tell you if a string is YAML or not. +func IsYAML(testString string) bool { + if testString == "" { + return false + } + if IsJSON(testString) { + return false + } + var n interface{} + err := yaml.Unmarshal([]byte(testString), &n) + if err != nil { + return false + } + _, err = yaml.Marshal(n) + return err == nil +} + +// ConvertYAMLtoJSON will do exactly what you think it will. It will deserialize YAML into serialized JSON. +func ConvertYAMLtoJSON(yamlData []byte) ([]byte, error) { + var decodedYaml map[string]interface{} + err := yaml.Unmarshal(yamlData, &decodedYaml) + if err != nil { + return nil, err + } + // if the data can be decoded, it can be encoded (that's my view anyway). no need for an error check. + jsonData, _ := json.Marshal(decodedYaml) + return jsonData, nil +} + +// IsHttpVerb will check if an operation is valid or not. +func IsHttpVerb(verb string) bool { + verbs := []string{"get", "post", "put", "patch", "delete", "options", "trace", "head"} + for _, v := range verbs { + if verb == v { + return true + } + } + return false +} + +func ConvertComponentIdIntoFriendlyPathSearch(id string) (string, string) { + segs := strings.Split(id, "/") + name, _ := url.QueryUnescape(strings.ReplaceAll(segs[len(segs)-1], "~1", "/")) + var cleaned []string + + // check for strange spaces, chars and if found, wrap them up, clean them and create a new cleaned path. + for i := range segs { + reg, _ := regexp.MatchString("[%=;~.]", segs[i]) + if reg { + segs[i], _ = url.QueryUnescape(strings.ReplaceAll(segs[i], "~1", "/")) + segs[i] = fmt.Sprintf("['%s']", segs[i]) + if len(cleaned) > 0 { + cleaned[len(cleaned)-1] = fmt.Sprintf("%s%s", segs[i-1], segs[i]) + continue + } + } else { + intVal, err := strconv.ParseInt(segs[i], 10, 32) + if err == nil && intVal <= 99 { + segs[i] = fmt.Sprintf("[%d]", intVal) + cleaned[len(cleaned)-1] = fmt.Sprintf("%s%s", cleaned[len(cleaned)-1], segs[i]) + continue + } + if err == nil && intVal > 99 { + segs[i] = fmt.Sprintf("['%d']", intVal) + cleaned[len(cleaned)-1] = fmt.Sprintf("%s%s", cleaned[len(cleaned)-1], segs[i]) + continue + } + cleaned = append(cleaned, segs[i]) + } + } + _, err := strconv.ParseInt(name, 10, 32) + var replaced string + if err != nil { + replaced = strings.ReplaceAll(fmt.Sprintf("%s", + strings.Join(cleaned, ".")), "#", "$") + } else { + replaced = strings.ReplaceAll(fmt.Sprintf("%s", + strings.Join(cleaned, ".")), "#", "$") + } + + if len(replaced) > 0 { + if replaced[0] != '$' { + replaced = fmt.Sprintf("$%s", replaced) + } + } + return name, replaced +} + +func ConvertComponentIdIntoPath(id string) (string, string) { + segs := strings.Split(id, "/") + name := segs[len(segs)-1] + + return name, strings.ReplaceAll(fmt.Sprintf("%s.%s", + strings.Join(segs[:len(segs)-1], "."), name), "#", "$") +} + +func RenderCodeSnippet(startNode *yaml.Node, specData []string, before, after int) string { + + buf := new(strings.Builder) + + startLine := startNode.Line - before + endLine := startNode.Line + after + + if startLine < 0 { + startLine = 0 + } + + if endLine >= len(specData) { + endLine = len(specData) - 1 + } + + delta := endLine - startLine + + for i := 0; i < delta; i++ { + l := startLine + i + if l < len(specData) { + line := specData[l] + buf.WriteString(fmt.Sprintf("%s\n", line)) + } + } + + return buf.String() +} + +func DetectCase(input string) Case { + trim := strings.TrimSpace(input) + if trim == "" { + return UnknownCase + } + + pascalCase := regexp.MustCompile("^[A-Z][a-z]+(?:[A-Z][a-z]+)*$") + camelCase := regexp.MustCompile("^[a-z]+(?:[A-Z][a-z]+)*$") + screamingSnakeCase := regexp.MustCompile("^[A-Z]+(_[A-Z]+)*$") + snakeCase := regexp.MustCompile("^[a-z]+(_[a-z]+)*$") + kebabCase := regexp.MustCompile("^[a-z]+(-[a-z]+)*$") + screamingKebabCase := regexp.MustCompile("^[A-Z]+(-[A-Z]+)*$") + if pascalCase.MatchString(trim) { + return PascalCase + } + if camelCase.MatchString(trim) { + return CamelCase + } + if screamingSnakeCase.MatchString(trim) { + return ScreamingSnakeCase + } + if snakeCase.MatchString(trim) { + return SnakeCase + } + if kebabCase.MatchString(trim) { + return KebabCase + } + if screamingKebabCase.MatchString(trim) { + return ScreamingKebabCase + } + return RegularCase +} + +// CheckEnumForDuplicates will check an array of nodes to check if there are any duplicate values. +func CheckEnumForDuplicates(seq []*yaml.Node) []*yaml.Node { + var res []*yaml.Node + seen := make(map[string]*yaml.Node) + + for _, enum := range seq { + if seen[enum.Value] != nil { + res = append(res, enum) + continue + } + seen[enum.Value] = enum + } + return res +} diff --git a/vendor/github.com/pb33f/libopenapi/what-changed/model/callback.go b/vendor/github.com/pb33f/libopenapi/what-changed/model/callback.go new file mode 100644 index 0000000000..04dbea06e2 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/what-changed/model/callback.go @@ -0,0 +1,113 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package model + +import ( + "github.com/pb33f/libopenapi/datamodel/low" + "github.com/pb33f/libopenapi/datamodel/low/v3" +) + +// CallbackChanges represents all changes made between two Callback OpenAPI objects. +type CallbackChanges struct { + *PropertyChanges + ExpressionChanges map[string]*PathItemChanges `json:"expressions,omitempty" yaml:"expressions,omitempty"` + ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"` +} + +// TotalChanges returns a total count of all changes made between Callback objects +func (c *CallbackChanges) TotalChanges() int { + d := c.PropertyChanges.TotalChanges() + for k := range c.ExpressionChanges { + d += c.ExpressionChanges[k].TotalChanges() + } + if c.ExtensionChanges != nil { + d += c.ExtensionChanges.TotalChanges() + } + return d +} + +// GetAllChanges returns a slice of all changes made between Callback objects +func (c *CallbackChanges) GetAllChanges() []*Change { + var changes []*Change + changes = append(changes, c.Changes...) + for k := range c.ExpressionChanges { + changes = append(changes, c.ExpressionChanges[k].GetAllChanges()...) + } + if c.ExtensionChanges != nil { + changes = append(changes, c.ExtensionChanges.GetAllChanges()...) + } + return changes +} + +// TotalBreakingChanges returns a total count of all changes made between Callback objects +func (c *CallbackChanges) TotalBreakingChanges() int { + d := c.PropertyChanges.TotalBreakingChanges() + for k := range c.ExpressionChanges { + d += c.ExpressionChanges[k].TotalBreakingChanges() + } + if c.ExtensionChanges != nil { + d += c.ExtensionChanges.TotalBreakingChanges() + } + return d +} + +// CompareCallback will compare two Callback objects and return a pointer to CallbackChanges with all the things +// that have changed between them. +func CompareCallback(l, r *v3.Callback) *CallbackChanges { + + cc := new(CallbackChanges) + var changes []*Change + + lHashes := make(map[string]string) + rHashes := make(map[string]string) + + lValues := make(map[string]low.ValueReference[*v3.PathItem]) + rValues := make(map[string]low.ValueReference[*v3.PathItem]) + + for k := range l.Expression.Value { + lHashes[k.Value] = low.GenerateHashString(l.Expression.Value[k].Value) + lValues[k.Value] = l.Expression.Value[k] + } + + for k := range r.Expression.Value { + rHashes[k.Value] = low.GenerateHashString(r.Expression.Value[k].Value) + rValues[k.Value] = r.Expression.Value[k] + } + + expChanges := make(map[string]*PathItemChanges) + + // check left path item hashes + for k := range lHashes { + rhash := rHashes[k] + if rhash == "" { + CreateChange(&changes, ObjectRemoved, k, + lValues[k].GetValueNode(), nil, true, + lValues[k].GetValue(), nil) + continue + } + if lHashes[k] == rHashes[k] { + continue + } + // run comparison. + expChanges[k] = ComparePathItems(lValues[k].Value, rValues[k].Value) + } + + //check right path item hashes + for k := range rHashes { + lhash := lHashes[k] + if lhash == "" { + CreateChange(&changes, ObjectAdded, k, + nil, rValues[k].GetValueNode(), false, + nil, rValues[k].GetValue()) + continue + } + } + cc.ExpressionChanges = expChanges + cc.ExtensionChanges = CompareExtensions(l.Extensions, r.Extensions) + cc.PropertyChanges = NewPropertyChanges(changes) + if cc.TotalChanges() <= 0 { + return nil + } + return cc +} diff --git a/vendor/github.com/pb33f/libopenapi/what-changed/model/change_types.go b/vendor/github.com/pb33f/libopenapi/what-changed/model/change_types.go new file mode 100644 index 0000000000..dceb9a2849 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/what-changed/model/change_types.go @@ -0,0 +1,139 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package model + +import ( + "gopkg.in/yaml.v3" +) + +// Definitions of the possible changes between two items +const ( + + // Modified means that was a modification of a value was made + Modified = iota + 1 + + // PropertyAdded means that a new property to an object was added + PropertyAdded + + // ObjectAdded means that a new object was added to a parent object + ObjectAdded + + // ObjectRemoved means that an object was removed from a parent object + ObjectRemoved + + // PropertyRemoved means that a property of an object was removed + PropertyRemoved +) + +// WhatChanged is a summary object that contains a high level summary of everything changed. +type WhatChanged struct { + Added int `json:"added,omitempty" yaml:"added,omitempty"` + Removed int `json:"removed,omitempty" yaml:"removed,omitempty"` + Modified int `json:"modified,omitempty" yaml:"modified,omitempty"` + TotalChanges int `json:"total,omitempty" yaml:"total,omitempty"` +} + +// ChangeContext holds a reference to the line and column positions of original and new change. +type ChangeContext struct { + OriginalLine *int `json:"originalLine,omitempty" yaml:"originalLine,omitempty"` + OriginalColumn *int `json:"originalColumn,omitempty" yaml:"originalColumn,omitempty"` + NewLine *int `json:"newLine,omitempty" yaml:"newLine,omitempty"` + NewColumn *int `json:"newColumn,omitempty" yaml:"newColumn,omitempty"` +} + +// HasChanged determines if the line and column numbers of the original and new values have changed. +// +// It's worth noting that there is no guarantee to the positions of anything in either left or right, so +// considering these values as 'changes' is going to add a considerable amount of noise to results. +func (c *ChangeContext) HasChanged() bool { + if c.NewLine != nil && c.OriginalLine != nil && *c.NewLine != *c.OriginalLine { + return true + } + //if c.NewColumn != nil && c.OriginalColumn != nil && *c.NewColumn != *c.OriginalColumn { + // return true + //} + if (c.NewLine == nil && c.OriginalLine != nil) || (c.NewLine != nil && c.OriginalLine == nil) { + return true + } + //if (c.NewColumn == nil && c.OriginalColumn != nil) || (c.NewColumn != nil && c.OriginalColumn == nil) { + // return true + //} + return false +} + +// Change represents a change between two different elements inside an OpenAPI specification. +type Change struct { + + // Context represents the lines and column numbers of the original and new values + // It's worth noting that these values may frequently be different and are not used to calculate + // a change. If the positions change, but values do not, then no change is recorded. + Context *ChangeContext `json:"context,omitempty" yaml:"context,omitempty"` + + // ChangeType represents the type of change that occurred. stored as an integer, defined by constants above. + ChangeType int `json:"change,omitempty" yaml:"change,omitempty"` + + // Property is the property name key being changed. + Property string `json:"property,omitempty" yaml:"property,omitempty"` + + // Original is the original value represented as a string. + Original string `json:"original,omitempty" yaml:"original,omitempty"` + + // New is the new value represented as a string. + New string `json:"new,omitempty" yaml:"new,omitempty"` + + // Breaking determines if the change is a breaking one or not. + Breaking bool `json:"breaking" yaml:"breaking"` + + // OriginalObject represents the original object that was changed. + OriginalObject any `json:"-" yaml:"-"` + + // NewObject represents the new object that has been modified. + NewObject any `json:"-" yaml:"-"` +} + +// PropertyChanges holds a slice of Change pointers +type PropertyChanges struct { + //Total *int `json:"total,omitempty" yaml:"total,omitempty"` + //Breaking *int `json:"breaking,omitempty" yaml:"breaking,omitempty"` + Changes []*Change `json:"changes,omitempty" yaml:"changes,omitempty"` +} + +// TotalChanges returns the total number of property changes made. +func (p PropertyChanges) TotalChanges() int { + return len(p.Changes) +} + +// TotalBreakingChanges returns the total number of property breaking changes made. +func (p PropertyChanges) TotalBreakingChanges() int { + return CountBreakingChanges(p.Changes) +} + +func NewPropertyChanges(changes []*Change) *PropertyChanges { + return &PropertyChanges{Changes: changes} +} + +// PropertyCheck is used by functions to check the state of left and right values. +type PropertyCheck struct { + + // Original is the property we're checking on the left + Original any + + // New is s the property we're checking on the right + New any + + // Label is the identifier we're looking for on the left and right hand sides + Label string + + // LeftNode is the yaml.Node pointer that holds the original node structure of the value + LeftNode *yaml.Node + + // RightNode is the yaml.Node pointer that holds the new node structure of the value + RightNode *yaml.Node + + // Breaking determines if the check is a breaking change (modifications or removals etc.) + Breaking bool + + // Changes represents a pointer to the slice to contain all changes found. + Changes *[]*Change +} diff --git a/vendor/github.com/pb33f/libopenapi/what-changed/model/comparison_functions.go b/vendor/github.com/pb33f/libopenapi/what-changed/model/comparison_functions.go new file mode 100644 index 0000000000..ccadd6920c --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/what-changed/model/comparison_functions.go @@ -0,0 +1,380 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package model + +import ( + "fmt" + "reflect" + "strings" + "sync" + + "github.com/pb33f/libopenapi/datamodel/low" + "gopkg.in/yaml.v3" +) + +const ( + HashPh = "%x" + EMPTY_STR = "" +) + +// CreateChange is a generic function that will create a Change of type T, populate all properties if set, and then +// add a pointer to Change[T] in the slice of Change pointers provided +func CreateChange(changes *[]*Change, changeType int, property string, leftValueNode, rightValueNode *yaml.Node, + breaking bool, originalObject, newObject any) *[]*Change { + + // create a new context for the left and right nodes. + ctx := CreateContext(leftValueNode, rightValueNode) + c := &Change{ + Context: ctx, + ChangeType: changeType, + Property: property, + Breaking: breaking, + } + // if the left is not nil, we have an original value + if leftValueNode != nil && leftValueNode.Value != "" { + c.Original = leftValueNode.Value + } + // if the right is not nil, then we have a new value + if rightValueNode != nil && rightValueNode.Value != "" { + c.New = rightValueNode.Value + } + // original and new objects + c.OriginalObject = originalObject + c.NewObject = newObject + + // add the change to supplied changes slice + *changes = append(*changes, c) + return changes +} + +// CreateContext will return a pointer to a ChangeContext containing the original and new line and column numbers +// of the left and right value nodes. +func CreateContext(l, r *yaml.Node) *ChangeContext { + ctx := new(ChangeContext) + if l != nil { + ctx.OriginalLine = &l.Line + ctx.OriginalColumn = &l.Column + } + if r != nil { + ctx.NewLine = &r.Line + ctx.NewColumn = &r.Column + } + return ctx +} + +func FlattenLowLevelMap[T any]( + lowMap map[low.KeyReference[string]]low.ValueReference[T]) map[string]*low.ValueReference[T] { + flat := make(map[string]*low.ValueReference[T]) + for i := range lowMap { + l := lowMap[i] + flat[i.Value] = &l + } + return flat +} + +// CountBreakingChanges counts the number of changes in a slice that are breaking +func CountBreakingChanges(changes []*Change) int { + b := 0 + for i := range changes { + if changes[i].Breaking { + b++ + } + } + return b +} + +// CheckForObjectAdditionOrRemoval will check for the addition or removal of an object from left and right maps. +// The label is the key to look for in the left and right maps. +// +// To determine this a breaking change for an addition then set breakingAdd to true (however I can't think of many +// scenarios that adding things should break anything). Removals are generally breaking, except for non contract +// properties like descriptions, summaries and other non-binding values, so a breakingRemove value can be tuned for +// these circumstances. +func CheckForObjectAdditionOrRemoval[T any](l, r map[string]*low.ValueReference[T], label string, changes *[]*Change, + breakingAdd, breakingRemove bool) { + var left, right T + if CheckSpecificObjectRemoved(l, r, label) { + left = l[label].GetValue() + CreateChange(changes, ObjectRemoved, label, l[label].GetValueNode(), nil, + breakingRemove, left, nil) + } + if CheckSpecificObjectAdded(l, r, label) { + right = r[label].GetValue() + CreateChange(changes, ObjectAdded, label, nil, r[label].GetValueNode(), + breakingAdd, nil, right) + } +} + +// CheckSpecificObjectRemoved returns true if a specific value is not in both maps. +func CheckSpecificObjectRemoved[T any](l, r map[string]*T, label string) bool { + return l[label] != nil && r[label] == nil +} + +// CheckSpecificObjectAdded returns true if a specific value is not in both maps. +func CheckSpecificObjectAdded[T any](l, r map[string]*T, label string) bool { + return l[label] == nil && r[label] != nil +} + +// CheckProperties will iterate through a slice of PropertyCheck pointers of type T. The method is a convenience method +// for running checks on the following methods in order: +// +// CheckPropertyAdditionOrRemoval +// CheckForModification +func CheckProperties(properties []*PropertyCheck) { + + // todo: make this async to really speed things up. + for _, n := range properties { + CheckPropertyAdditionOrRemoval(n.LeftNode, n.RightNode, n.Label, n.Changes, n.Breaking, n.Original, n.New) + CheckForModification(n.LeftNode, n.RightNode, n.Label, n.Changes, n.Breaking, n.Original, n.New) + } +} + +// CheckPropertyAdditionOrRemoval will run both CheckForRemoval (first) and CheckForAddition (second) +func CheckPropertyAdditionOrRemoval[T any](l, r *yaml.Node, + label string, changes *[]*Change, breaking bool, orig, new T) { + CheckForRemoval[T](l, r, label, changes, breaking, orig, new) + CheckForAddition[T](l, r, label, changes, breaking, orig, new) +} + +// CheckForRemoval will check left and right yaml.Node instances for changes. Anything that is found missing on the +// right, but present on the left, is considered a removal. A new Change[T] will be created with the type +// +// PropertyRemoved +// +// The Change is then added to the slice of []Change[T] instances provided as a pointer. +func CheckForRemoval[T any](l, r *yaml.Node, label string, changes *[]*Change, breaking bool, orig, new T) { + if l != nil && l.Value != "" && (r == nil || r.Value == "") { + CreateChange(changes, PropertyRemoved, label, l, r, breaking, orig, new) + return + } + if l != nil && r == nil { + CreateChange(changes, PropertyRemoved, label, l, nil, breaking, orig, nil) + } +} + +// CheckForAddition will check left and right yaml.Node instances for changes. Anything that is found missing on the +// left, but present on the left, is considered an addition. A new Change[T] will be created with the type +// +// PropertyAdded +// +// The Change is then added to the slice of []Change[T] instances provided as a pointer. +func CheckForAddition[T any](l, r *yaml.Node, label string, changes *[]*Change, breaking bool, orig, new T) { + if (l == nil || l.Value == "") && r != nil && r.Value != "" { + CreateChange(changes, PropertyAdded, label, l, r, breaking, orig, new) + } +} + +// CheckForModification will check left and right yaml.Node instances for changes. Anything that is found in both +// sides, but vary in value is considered a modification. +// +// If there is a change in value the function adds a change type of Modified. +// +// The Change is then added to the slice of []Change[T] instances provided as a pointer. +func CheckForModification[T any](l, r *yaml.Node, label string, changes *[]*Change, breaking bool, orig, new T) { + if l != nil && l.Value != "" && r != nil && r.Value != "" && (r.Value != l.Value || r.Tag != l.Tag) { + CreateChange(changes, Modified, label, l, r, breaking, orig, new) + } +} + +// CheckMapForChanges checks a left and right low level map for any additions, subtractions or modifications to +// values. The compareFunc argument should reference the correct comparison function for the generic type. +func CheckMapForChanges[T any, R any](expLeft, expRight map[low.KeyReference[string]]low.ValueReference[T], + changes *[]*Change, label string, compareFunc func(l, r T) R) map[string]R { + return CheckMapForChangesWithComp(expLeft, expRight, changes, label, compareFunc, true) +} + +func CheckMapForAdditionRemoval[T any](expLeft, expRight map[low.KeyReference[string]]low.ValueReference[T], + changes *[]*Change, label string) any { + // do nothing + doNothing := func(l, r T) any { + return nil + } + return CheckMapForChangesWithComp(expLeft, expRight, changes, label, doNothing, false) +} + +//// CheckMapForAdditionRemoval checks a left and right low level map for any additions or subtractions, but not modifications +//func CheckMapForAdditionRemoval[T any, R any](expLeft, expRight map[low.KeyReference[string]]low.ValueReference[T], +// changes *[]*Change, label string) map[string]R { +// +// // do nothing +// doNothing := func(l, r T) R { +// return nil +// } +// return CheckMapForChangesWithComp(expLeft, expRight, changes, label, doNothing, false) +//} + +// CheckMapForChangesWithComp checks a left and right low level map for any additions, subtractions or modifications to +// values. The compareFunc argument should reference the correct comparison function for the generic type. The compare +// bit determines if the comparison should be run or not. +func CheckMapForChangesWithComp[T any, R any](expLeft, expRight map[low.KeyReference[string]]low.ValueReference[T], + changes *[]*Change, label string, compareFunc func(l, r T) R, compare bool) map[string]R { + + // stop concurrent threads screwing up changes. + var chLock sync.Mutex + + lHashes := make(map[string]string) + rHashes := make(map[string]string) + lValues := make(map[string]low.ValueReference[T]) + rValues := make(map[string]low.ValueReference[T]) + + for k := range expLeft { + lHashes[k.Value] = low.GenerateHashString(expLeft[k].Value) + lValues[k.Value] = expLeft[k] + } + + for k := range expRight { + rHashes[k.Value] = low.GenerateHashString(expRight[k].Value) + rValues[k.Value] = expRight[k] + } + + expChanges := make(map[string]R) + + checkLeft := func(k string, doneChan chan bool, f, g map[string]string, p, h map[string]low.ValueReference[T]) { + rhash := g[k] + if rhash == "" { + if p[k].GetValueNode().Value == "" { + p[k].GetValueNode().Value = k + } + chLock.Lock() + CreateChange(changes, ObjectRemoved, label, + p[k].GetValueNode(), nil, true, + p[k].GetValue(), nil) + chLock.Unlock() + doneChan <- true + return + } + if f[k] == g[k] { + doneChan <- true + return + } + // run comparison. + if compare { + chLock.Lock() + ch := compareFunc(p[k].Value, h[k].Value) + // incorrect map results were being generated causing panics. + // https://github.com/pb33f/libopenapi/issues/61 + if !reflect.ValueOf(&ch).Elem().IsZero() { + expChanges[k] = ch + } + chLock.Unlock() + } + doneChan <- true + } + + doneChan := make(chan bool) + count := 0 + + // check left example hashes + for k := range lHashes { + count++ + go checkLeft(k, doneChan, lHashes, rHashes, lValues, rValues) + } + + //check right example hashes + for k := range rHashes { + count++ + go checkRightValue(k, doneChan, lHashes, rValues, changes, label, &chLock) + } + + // wait for all done signals. + completed := 0 + for completed < count { + select { + case <-doneChan: + completed++ + } + } + return expChanges +} + +func checkRightValue[T any](k string, doneChan chan bool, f map[string]string, p map[string]low.ValueReference[T], + changes *[]*Change, label string, lock *sync.Mutex) { + + lhash := f[k] + if lhash == "" { + if p[k].GetValueNode().Value == "" { + p[k].GetValueNode().Value = k // this is kinda dirty, but I don't want to duplicate code so sue me. + } + lock.Lock() + CreateChange(changes, ObjectAdded, label, + nil, p[k].GetValueNode(), false, + nil, p[k].GetValue()) + lock.Unlock() + } + doneChan <- true +} + +// ExtractStringValueSliceChanges will compare two low level string slices for changes. +func ExtractStringValueSliceChanges(lParam, rParam []low.ValueReference[string], + changes *[]*Change, label string, breaking bool) { + lKeys := make([]string, len(lParam)) + rKeys := make([]string, len(rParam)) + lValues := make(map[string]low.ValueReference[string]) + rValues := make(map[string]low.ValueReference[string]) + for i := range lParam { + lKeys[i] = strings.ToLower(lParam[i].Value) + lValues[lKeys[i]] = lParam[i] + } + for i := range rParam { + rKeys[i] = strings.ToLower(rParam[i].Value) + rValues[rKeys[i]] = rParam[i] + } + for i := range lValues { + if _, ok := rValues[i]; !ok { + CreateChange(changes, PropertyRemoved, label, + lValues[i].ValueNode, + nil, + breaking, + lValues[i].Value, + nil) + } + } + for i := range rValues { + if _, ok := lValues[i]; !ok { + CreateChange(changes, PropertyAdded, label, + nil, + rValues[i].ValueNode, + false, + nil, + rValues[i].Value) + } + } +} + +// ExtractRawValueSliceChanges will compare two low level interface{} slices for changes. +func ExtractRawValueSliceChanges(lParam, rParam []low.ValueReference[any], + changes *[]*Change, label string, breaking bool) { + lKeys := make([]string, len(lParam)) + rKeys := make([]string, len(rParam)) + lValues := make(map[string]low.ValueReference[any]) + rValues := make(map[string]low.ValueReference[any]) + for i := range lParam { + lKeys[i] = strings.ToLower(fmt.Sprint(lParam[i].Value)) + lValues[lKeys[i]] = lParam[i] + } + for i := range rParam { + rKeys[i] = strings.ToLower(fmt.Sprint(rParam[i].Value)) + rValues[rKeys[i]] = rParam[i] + } + for i := range lValues { + if _, ok := rValues[i]; !ok { + CreateChange(changes, PropertyRemoved, label, + lValues[i].ValueNode, + nil, + breaking, + lValues[i].Value, + nil) + } + } + for i := range rValues { + if _, ok := lValues[i]; !ok { + CreateChange(changes, PropertyAdded, label, + nil, + rValues[i].ValueNode, + false, + nil, + rValues[i].Value) + } + } +} diff --git a/vendor/github.com/pb33f/libopenapi/what-changed/model/components.go b/vendor/github.com/pb33f/libopenapi/what-changed/model/components.go new file mode 100644 index 0000000000..220e4e5588 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/what-changed/model/components.go @@ -0,0 +1,279 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package model + +import ( + "reflect" + + "github.com/pb33f/libopenapi/datamodel/low" + "github.com/pb33f/libopenapi/datamodel/low/base" + v2 "github.com/pb33f/libopenapi/datamodel/low/v2" + v3 "github.com/pb33f/libopenapi/datamodel/low/v3" +) + +// ComponentsChanges represents changes made to both OpenAPI and Swagger documents. This model is based on OpenAPI 3 +// components, however it's also used to contain Swagger definitions changes. Swagger for some reason decided to not +// contain definitions inside a single parent like Components, and instead scattered them across the root of the +// Swagger document, giving everything a `Definitions` postfix. This design attempts to unify those models into +// a single entity that contains all changes. +// +// Schemas are treated differently from every other component / definition in this library. Schemas can be highly +// recursive, and are not resolved by the model, every ref is recorded, but it's not looked at essentially. This means +// that when what-changed performs a check, everything that is *not* a schema is checked *inline*, Those references are +// resolved in place and a change is recorded in place. Schemas however are *not* resolved. which means no change +// will be recorded in place for any object referencing it. +// +// That is why there is a separate SchemaChanges object in ComponentsChanges. Schemas are checked at the source, and +// not inline when referenced. A schema change will only be found once, however a change to ANY other definition or +// component, will be found inline (and will duplicate for every use). +// +// The other oddity here is SecuritySchemes. For some reason OpenAPI does not use a $ref for these entities, it +// uses a name lookup, which means there are no direct links between any model and a security scheme reference. +// So like Schemas, SecuritySchemes are treated differently and handled individually. +// +// An important note: Everything EXCEPT Schemas and SecuritySchemes is ONLY checked for additions or removals. +// modifications are not checked, these checks occur in-place by implementing objects as they are autp-resolved +// when the model is built. +type ComponentsChanges struct { + *PropertyChanges + SchemaChanges map[string]*SchemaChanges `json:"schemas,omitempty" yaml:"schemas,omitempty"` + SecuritySchemeChanges map[string]*SecuritySchemeChanges `json:"securitySchemes,omitempty" yaml:"securitySchemes,omitempty"` + ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"` +} + +// CompareComponents will compare OpenAPI components for any changes. Accepts Swagger Definition objects +// like ParameterDefinitions or Definitions etc. +func CompareComponents(l, r any) *ComponentsChanges { + + var changes []*Change + + cc := new(ComponentsChanges) + + // Swagger Parameters + if reflect.TypeOf(&v2.ParameterDefinitions{}) == reflect.TypeOf(l) && + reflect.TypeOf(&v2.ParameterDefinitions{}) == reflect.TypeOf(r) { + lDef := l.(*v2.ParameterDefinitions) + rDef := r.(*v2.ParameterDefinitions) + var a, b map[low.KeyReference[string]]low.ValueReference[*v2.Parameter] + if lDef != nil { + a = lDef.Definitions + } + if rDef != nil { + b = rDef.Definitions + } + CheckMapForAdditionRemoval(a, b, &changes, v3.ParametersLabel) + } + + // Swagger Responses + if reflect.TypeOf(&v2.ResponsesDefinitions{}) == reflect.TypeOf(l) && + reflect.TypeOf(&v2.ResponsesDefinitions{}) == reflect.TypeOf(r) { + lDef := l.(*v2.ResponsesDefinitions) + rDef := r.(*v2.ResponsesDefinitions) + var a, b map[low.KeyReference[string]]low.ValueReference[*v2.Response] + if lDef != nil { + a = lDef.Definitions + } + if rDef != nil { + b = rDef.Definitions + } + CheckMapForAdditionRemoval(a, b, &changes, v3.ResponsesLabel) + } + + // Swagger Schemas + if reflect.TypeOf(&v2.Definitions{}) == reflect.TypeOf(l) && + reflect.TypeOf(&v2.Definitions{}) == reflect.TypeOf(r) { + lDef := l.(*v2.Definitions) + rDef := r.(*v2.Definitions) + var a, b map[low.KeyReference[string]]low.ValueReference[*base.SchemaProxy] + if lDef != nil { + a = lDef.Schemas + } + if rDef != nil { + b = rDef.Schemas + } + cc.SchemaChanges = CheckMapForChanges(a, b, &changes, v2.DefinitionsLabel, CompareSchemas) + } + + // Swagger Security Definitions + if reflect.TypeOf(&v2.SecurityDefinitions{}) == reflect.TypeOf(l) && + reflect.TypeOf(&v2.SecurityDefinitions{}) == reflect.TypeOf(r) { + lDef := l.(*v2.SecurityDefinitions) + rDef := r.(*v2.SecurityDefinitions) + var a, b map[low.KeyReference[string]]low.ValueReference[*v2.SecurityScheme] + if lDef != nil { + a = lDef.Definitions + } + if rDef != nil { + b = rDef.Definitions + } + cc.SecuritySchemeChanges = CheckMapForChanges(a, b, &changes, + v3.SecurityDefinitionLabel, CompareSecuritySchemesV2) + } + + // OpenAPI Components + if reflect.TypeOf(&v3.Components{}) == reflect.TypeOf(l) && + reflect.TypeOf(&v3.Components{}) == reflect.TypeOf(r) { + + lComponents := l.(*v3.Components) + rComponents := r.(*v3.Components) + + //if low.AreEqual(lComponents, rComponents) { + // return nil + //} + + doneChan := make(chan componentComparison) + comparisons := 0 + + // run as fast as we can, thread all the things. + if !lComponents.Schemas.IsEmpty() || !rComponents.Schemas.IsEmpty() { + comparisons++ + go runComparison(lComponents.Schemas.Value, rComponents.Schemas.Value, + &changes, v3.SchemasLabel, CompareSchemas, doneChan) + } + + if !lComponents.Responses.IsEmpty() || !rComponents.Responses.IsEmpty() { + comparisons++ + go runComparison(lComponents.Responses.Value, rComponents.Responses.Value, + &changes, v3.ResponsesLabel, CompareResponseV3, doneChan) + } + + if !lComponents.Parameters.IsEmpty() || !rComponents.Parameters.IsEmpty() { + comparisons++ + go runComparison(lComponents.Parameters.Value, rComponents.Parameters.Value, + &changes, v3.ParametersLabel, CompareParametersV3, doneChan) + } + + if !lComponents.Examples.IsEmpty() || !rComponents.Examples.IsEmpty() { + comparisons++ + go runComparison(lComponents.Examples.Value, rComponents.Examples.Value, + &changes, v3.ExamplesLabel, CompareExamples, doneChan) + } + + if !lComponents.RequestBodies.IsEmpty() || !rComponents.RequestBodies.IsEmpty() { + comparisons++ + go runComparison(lComponents.RequestBodies.Value, rComponents.RequestBodies.Value, + &changes, v3.RequestBodiesLabel, CompareRequestBodies, doneChan) + } + + if !lComponents.Headers.IsEmpty() || !rComponents.Headers.IsEmpty() { + comparisons++ + go runComparison(lComponents.Headers.Value, rComponents.Headers.Value, + &changes, v3.HeadersLabel, CompareHeadersV3, doneChan) + } + + if !lComponents.SecuritySchemes.IsEmpty() || !rComponents.SecuritySchemes.IsEmpty() { + comparisons++ + go runComparison(lComponents.SecuritySchemes.Value, rComponents.SecuritySchemes.Value, + &changes, v3.SecuritySchemesLabel, CompareSecuritySchemesV3, doneChan) + } + + if !lComponents.Links.IsEmpty() || !rComponents.Links.IsEmpty() { + comparisons++ + go runComparison(lComponents.Links.Value, rComponents.Links.Value, + &changes, v3.LinksLabel, CompareLinks, doneChan) + } + + if !lComponents.Callbacks.IsEmpty() || !rComponents.Callbacks.IsEmpty() { + comparisons++ + go runComparison(lComponents.Callbacks.Value, rComponents.Callbacks.Value, + &changes, v3.CallbacksLabel, CompareCallback, doneChan) + } + + cc.ExtensionChanges = CompareExtensions(lComponents.Extensions, rComponents.Extensions) + + completedComponents := 0 + for completedComponents < comparisons { + select { + case res := <-doneChan: + switch res.prop { + case v3.SchemasLabel: + completedComponents++ + cc.SchemaChanges = res.result.(map[string]*SchemaChanges) + break + case v3.SecuritySchemesLabel: + completedComponents++ + cc.SecuritySchemeChanges = res.result.(map[string]*SecuritySchemeChanges) + break + case v3.ResponsesLabel, v3.ParametersLabel, v3.ExamplesLabel, v3.RequestBodiesLabel, v3.HeadersLabel, + v3.LinksLabel, v3.CallbacksLabel: + completedComponents++ + break + } + } + } + } + + cc.PropertyChanges = NewPropertyChanges(changes) + if cc.TotalChanges() <= 0 { + return nil + } + return cc +} + +type componentComparison struct { + prop string + result any +} + +// run a generic comparison in a thread which in turn splits checks into further threads. +func runComparison[T any, R any](l, r map[low.KeyReference[string]]low.ValueReference[T], + changes *[]*Change, label string, compareFunc func(l, r T) R, doneChan chan componentComparison) { + + // for schemas + if label == v3.SchemasLabel || label == v2.DefinitionsLabel || label == v3.SecuritySchemesLabel { + doneChan <- componentComparison{ + prop: label, + result: CheckMapForChanges(l, r, changes, label, compareFunc), + } + return + } else { + doneChan <- componentComparison{ + prop: label, + result: CheckMapForAdditionRemoval(l, r, changes, label), + } + } +} + +// GetAllChanges returns a slice of all changes made between Callback objects +func (c *ComponentsChanges) GetAllChanges() []*Change { + var changes []*Change + changes = append(changes, c.Changes...) + for k := range c.SchemaChanges { + changes = append(changes, c.SchemaChanges[k].GetAllChanges()...) + } + for k := range c.SecuritySchemeChanges { + changes = append(changes, c.SecuritySchemeChanges[k].GetAllChanges()...) + } + if c.ExtensionChanges != nil { + changes = append(changes, c.ExtensionChanges.GetAllChanges()...) + } + return changes +} + +// TotalChanges returns total changes for all Components and Definitions +func (c *ComponentsChanges) TotalChanges() int { + v := c.PropertyChanges.TotalChanges() + for k := range c.SchemaChanges { + v += c.SchemaChanges[k].TotalChanges() + } + for k := range c.SecuritySchemeChanges { + v += c.SecuritySchemeChanges[k].TotalChanges() + } + if c.ExtensionChanges != nil { + v += c.ExtensionChanges.TotalChanges() + } + return v +} + +// TotalBreakingChanges returns all breaking changes found for all Components and Definitions +func (c *ComponentsChanges) TotalBreakingChanges() int { + v := c.PropertyChanges.TotalBreakingChanges() + for k := range c.SchemaChanges { + v += c.SchemaChanges[k].TotalBreakingChanges() + } + for k := range c.SecuritySchemeChanges { + v += c.SecuritySchemeChanges[k].TotalBreakingChanges() + } + return v +} diff --git a/vendor/github.com/pb33f/libopenapi/what-changed/model/contact.go b/vendor/github.com/pb33f/libopenapi/what-changed/model/contact.go new file mode 100644 index 0000000000..317b83d8f1 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/what-changed/model/contact.go @@ -0,0 +1,81 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package model + +import ( + "github.com/pb33f/libopenapi/datamodel/low/base" + "github.com/pb33f/libopenapi/datamodel/low/v3" +) + +// ContactChanges Represent changes to a Contact object that is a child of Info, part of an OpenAPI document. +type ContactChanges struct { + *PropertyChanges +} + +// GetAllChanges returns a slice of all changes made between Callback objects +func (c *ContactChanges) GetAllChanges() []*Change { + return c.Changes +} + +// TotalChanges represents the total number of changes that have occurred to a Contact object +func (c *ContactChanges) TotalChanges() int { + return c.PropertyChanges.TotalChanges() +} + +// TotalBreakingChanges always returns 0 for Contact objects, they are non-binding. +func (c *ContactChanges) TotalBreakingChanges() int { + return 0 +} + +// CompareContact will check a left (original) and right (new) Contact object for any changes. If there +// were any, a pointer to a ContactChanges object is returned, otherwise if nothing changed - the function +// returns nil. +func CompareContact(l, r *base.Contact) *ContactChanges { + + var changes []*Change + var props []*PropertyCheck + + // check URL + props = append(props, &PropertyCheck{ + LeftNode: l.URL.ValueNode, + RightNode: r.URL.ValueNode, + Label: v3.URLLabel, + Changes: &changes, + Breaking: false, + Original: l, + New: r, + }) + + // check name + props = append(props, &PropertyCheck{ + LeftNode: l.Name.ValueNode, + RightNode: r.Name.ValueNode, + Label: v3.NameLabel, + Changes: &changes, + Breaking: false, + Original: l, + New: r, + }) + + // check email + props = append(props, &PropertyCheck{ + LeftNode: l.Email.ValueNode, + RightNode: r.Email.ValueNode, + Label: v3.EmailLabel, + Changes: &changes, + Breaking: false, + Original: l, + New: r, + }) + + // check everything. + CheckProperties(props) + + dc := new(ContactChanges) + dc.PropertyChanges = NewPropertyChanges(changes) + if dc.TotalChanges() <= 0 { + return nil + } + return dc +} diff --git a/vendor/github.com/pb33f/libopenapi/what-changed/model/discriminator.go b/vendor/github.com/pb33f/libopenapi/what-changed/model/discriminator.go new file mode 100644 index 0000000000..3351490c81 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/what-changed/model/discriminator.go @@ -0,0 +1,96 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package model + +import ( + "github.com/pb33f/libopenapi/datamodel/low/base" + v3 "github.com/pb33f/libopenapi/datamodel/low/v3" +) + +// DiscriminatorChanges represents changes made to a Discriminator OpenAPI object +type DiscriminatorChanges struct { + *PropertyChanges + MappingChanges []*Change `json:"mappings,omitempty" yaml:"mappings,omitempty"` +} + +// TotalChanges returns a count of everything changed within the Discriminator object +func (d *DiscriminatorChanges) TotalChanges() int { + l := 0 + if k := d.PropertyChanges.TotalChanges(); k > 0 { + l += k + } + if k := len(d.MappingChanges); k > 0 { + l += k + } + return l +} + +// GetAllChanges returns a slice of all changes made between Callback objects +func (c *DiscriminatorChanges) GetAllChanges() []*Change { + var changes []*Change + changes = append(changes, c.Changes...) + if c.MappingChanges != nil { + changes = append(changes, c.MappingChanges...) + } + return changes +} + +// TotalBreakingChanges returns the number of breaking changes made by the Discriminator +func (d *DiscriminatorChanges) TotalBreakingChanges() int { + return d.PropertyChanges.TotalBreakingChanges() + CountBreakingChanges(d.MappingChanges) +} + +// CompareDiscriminator will check a left (original) and right (new) Discriminator object for changes +// and will return a pointer to DiscriminatorChanges +func CompareDiscriminator(l, r *base.Discriminator) *DiscriminatorChanges { + dc := new(DiscriminatorChanges) + var changes []*Change + var props []*PropertyCheck + var mappingChanges []*Change + + // Name (breaking change) + props = append(props, &PropertyCheck{ + LeftNode: l.PropertyName.ValueNode, + RightNode: r.PropertyName.ValueNode, + Label: v3.PropertyNameLabel, + Changes: &changes, + Breaking: true, + Original: l, + New: r, + }) + + // check properties + CheckProperties(props) + + // flatten maps + lMap := FlattenLowLevelMap[string](l.Mapping.Value) + rMap := FlattenLowLevelMap[string](r.Mapping.Value) + + // check for removals, modifications and moves + for i := range lMap { + CheckForObjectAdditionOrRemoval[string](lMap, rMap, i, &mappingChanges, false, true) + // if the existing tag exists, let's check it. + if rMap[i] != nil { + if lMap[i].Value != rMap[i].Value { + CreateChange(&mappingChanges, Modified, i, lMap[i].GetValueNode(), + rMap[i].GetValueNode(), true, lMap[i].GetValue(), rMap[i].GetValue()) + } + } + } + + for i := range rMap { + if lMap[i] == nil { + CreateChange(&mappingChanges, ObjectAdded, i, nil, + rMap[i].GetValueNode(), false, nil, rMap[i].GetValue()) + } + } + + dc.PropertyChanges = NewPropertyChanges(changes) + dc.MappingChanges = mappingChanges + if dc.TotalChanges() <= 0 { + return nil + } + return dc + +} diff --git a/vendor/github.com/pb33f/libopenapi/what-changed/model/document.go b/vendor/github.com/pb33f/libopenapi/what-changed/model/document.go new file mode 100644 index 0000000000..3135b42475 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/what-changed/model/document.go @@ -0,0 +1,324 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +// Package model +// +// What-changed models are unified across OpenAPI and Swagger. Everything is kept flat for simplicity, so please +// excuse the size of the package. There is a lot of data to crunch! +// +// Every model in here is either universal (works across both versions of OpenAPI) or is bound to a specific version +// of OpenAPI. There is only a single model however - so version specific objects are marked accordingly. +package model + +import ( + "reflect" + + "github.com/pb33f/libopenapi/datamodel/low" + "github.com/pb33f/libopenapi/datamodel/low/base" + v2 "github.com/pb33f/libopenapi/datamodel/low/v2" + v3 "github.com/pb33f/libopenapi/datamodel/low/v3" +) + +// DocumentChanges represents all the changes made to an OpenAPI document. +type DocumentChanges struct { + *PropertyChanges + InfoChanges *InfoChanges `json:"info,omitempty" yaml:"info,omitempty"` + PathsChanges *PathsChanges `json:"paths,omitempty" yaml:"paths,omitempty"` + TagChanges []*TagChanges `json:"tags,omitempty" yaml:"tags,omitempty"` + ExternalDocChanges *ExternalDocChanges `json:"externalDoc,omitempty" yaml:"externalDoc,omitempty"` + WebhookChanges map[string]*PathItemChanges `json:"webhooks,omitempty" yaml:"webhooks,omitempty"` + ServerChanges []*ServerChanges `json:"servers,omitempty" yaml:"servers,omitempty"` + SecurityRequirementChanges []*SecurityRequirementChanges `json:"securityRequirements,omitempty" yaml:"securityRequirements,omitempty"` + ComponentsChanges *ComponentsChanges `json:"components,omitempty" yaml:"components,omitempty"` + ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"` +} + +// TotalChanges returns a total count of all changes made in the Document +func (d *DocumentChanges) TotalChanges() int { + c := d.PropertyChanges.TotalChanges() + if d.InfoChanges != nil { + c += d.InfoChanges.TotalChanges() + } + if d.PathsChanges != nil { + c += d.PathsChanges.TotalChanges() + } + for k := range d.TagChanges { + c += d.TagChanges[k].TotalChanges() + } + if d.ExternalDocChanges != nil { + c += d.ExternalDocChanges.TotalChanges() + } + for k := range d.WebhookChanges { + c += d.WebhookChanges[k].TotalChanges() + } + for k := range d.ServerChanges { + c += d.ServerChanges[k].TotalChanges() + } + for k := range d.SecurityRequirementChanges { + c += d.SecurityRequirementChanges[k].TotalChanges() + } + if d.ComponentsChanges != nil { + c += d.ComponentsChanges.TotalChanges() + } + if d.ExtensionChanges != nil { + c += d.ExtensionChanges.TotalChanges() + } + return c +} + +// GetAllChanges returns a slice of all changes made between Document objects +func (d *DocumentChanges) GetAllChanges() []*Change { + var changes []*Change + changes = append(changes, d.Changes...) + if d.InfoChanges != nil { + changes = append(changes, d.InfoChanges.GetAllChanges()...) + } + if d.PathsChanges != nil { + changes = append(changes, d.PathsChanges.GetAllChanges()...) + } + for k := range d.TagChanges { + changes = append(changes, d.TagChanges[k].GetAllChanges()...) + } + if d.ExternalDocChanges != nil { + changes = append(changes, d.ExternalDocChanges.GetAllChanges()...) + } + for k := range d.WebhookChanges { + changes = append(changes, d.WebhookChanges[k].GetAllChanges()...) + } + for k := range d.ServerChanges { + changes = append(changes, d.ServerChanges[k].GetAllChanges()...) + } + for k := range d.SecurityRequirementChanges { + changes = append(changes, d.SecurityRequirementChanges[k].GetAllChanges()...) + } + if d.ComponentsChanges != nil { + changes = append(changes, d.ComponentsChanges.GetAllChanges()...) + } + if d.ExtensionChanges != nil { + changes = append(changes, d.ExtensionChanges.GetAllChanges()...) + } + return changes +} + +// TotalBreakingChanges returns a total count of all breaking changes made in the Document +func (d *DocumentChanges) TotalBreakingChanges() int { + c := d.PropertyChanges.TotalBreakingChanges() + if d.InfoChanges != nil { + c += d.InfoChanges.TotalBreakingChanges() + } + if d.PathsChanges != nil { + c += d.PathsChanges.TotalBreakingChanges() + } + for k := range d.TagChanges { + c += d.TagChanges[k].TotalBreakingChanges() + } + if d.ExternalDocChanges != nil { + c += d.ExternalDocChanges.TotalBreakingChanges() + } + for k := range d.WebhookChanges { + c += d.WebhookChanges[k].TotalBreakingChanges() + } + for k := range d.ServerChanges { + c += d.ServerChanges[k].TotalBreakingChanges() + } + for k := range d.SecurityRequirementChanges { + c += d.SecurityRequirementChanges[k].TotalBreakingChanges() + } + if d.ComponentsChanges != nil { + c += d.ComponentsChanges.TotalBreakingChanges() + } + return c +} + +// CompareDocuments will compare any two OpenAPI documents (either Swagger or OpenAPI) and return a pointer to +// DocumentChanges that outlines everything that was found to have changed. +func CompareDocuments(l, r any) *DocumentChanges { + + var changes []*Change + var props []*PropertyCheck + + dc := new(DocumentChanges) + + if reflect.TypeOf(&v2.Swagger{}) == reflect.TypeOf(l) && reflect.TypeOf(&v2.Swagger{}) == reflect.TypeOf(r) { + lDoc := l.(*v2.Swagger) + rDoc := r.(*v2.Swagger) + + // version + addPropertyCheck(&props, lDoc.Swagger.ValueNode, rDoc.Swagger.ValueNode, + lDoc.Swagger.Value, rDoc.Swagger.Value, &changes, v3.SwaggerLabel, true) + + // host + addPropertyCheck(&props, lDoc.Host.ValueNode, rDoc.Host.ValueNode, + lDoc.Host.Value, rDoc.Host.Value, &changes, v3.HostLabel, true) + + // base path + addPropertyCheck(&props, lDoc.BasePath.ValueNode, rDoc.BasePath.ValueNode, + lDoc.BasePath.Value, rDoc.BasePath.Value, &changes, v3.BasePathLabel, true) + + // schemes + if len(lDoc.Schemes.Value) > 0 || len(rDoc.Schemes.Value) > 0 { + ExtractStringValueSliceChanges(lDoc.Schemes.Value, rDoc.Schemes.Value, + &changes, v3.SchemesLabel, true) + } + // consumes + if len(lDoc.Consumes.Value) > 0 || len(rDoc.Consumes.Value) > 0 { + ExtractStringValueSliceChanges(lDoc.Consumes.Value, rDoc.Consumes.Value, + &changes, v3.ConsumesLabel, true) + } + // produces + if len(lDoc.Produces.Value) > 0 || len(rDoc.Produces.Value) > 0 { + ExtractStringValueSliceChanges(lDoc.Produces.Value, rDoc.Produces.Value, + &changes, v3.ProducesLabel, true) + } + + // tags + dc.TagChanges = CompareTags(lDoc.Tags.Value, rDoc.Tags.Value) + + // paths + if !lDoc.Paths.IsEmpty() || !rDoc.Paths.IsEmpty() { + dc.PathsChanges = ComparePaths(lDoc.Paths.Value, rDoc.Paths.Value) + } + + // external docs + compareDocumentExternalDocs(lDoc, rDoc, dc, &changes) + + // info + compareDocumentInfo(&lDoc.Info, &rDoc.Info, dc, &changes) + + // security + if !lDoc.Security.IsEmpty() || !rDoc.Security.IsEmpty() { + checkSecurity(lDoc.Security, rDoc.Security, &changes, dc) + } + + // components / definitions + // swagger (damn you) decided to put all this stuff at the document root, rather than cleanly + // placing it under a parent, like they did with OpenAPI. This means picking through each definition + // creating a new set of changes and then morphing them into a single changes object. + cc := new(ComponentsChanges) + cc.PropertyChanges = new(PropertyChanges) + if n := CompareComponents(lDoc.Definitions.Value, rDoc.Definitions.Value); n != nil { + cc.SchemaChanges = n.SchemaChanges + } + if n := CompareComponents(lDoc.SecurityDefinitions.Value, rDoc.SecurityDefinitions.Value); n != nil { + cc.SecuritySchemeChanges = n.SecuritySchemeChanges + } + if n := CompareComponents(lDoc.Parameters.Value, rDoc.Parameters.Value); n != nil { + cc.PropertyChanges.Changes = append(cc.PropertyChanges.Changes, n.Changes...) + } + if n := CompareComponents(lDoc.Responses.Value, rDoc.Responses.Value); n != nil { + cc.Changes = append(cc.Changes, n.Changes...) + } + dc.ExtensionChanges = CompareExtensions(lDoc.Extensions, rDoc.Extensions) + if cc.TotalChanges() > 0 { + dc.ComponentsChanges = cc + } + } + + if reflect.TypeOf(&v3.Document{}) == reflect.TypeOf(l) && reflect.TypeOf(&v3.Document{}) == reflect.TypeOf(r) { + lDoc := l.(*v3.Document) + rDoc := r.(*v3.Document) + + // version + addPropertyCheck(&props, lDoc.Version.ValueNode, rDoc.Version.ValueNode, + lDoc.Version.Value, rDoc.Version.Value, &changes, v3.OpenAPILabel, true) + + // schema dialect + addPropertyCheck(&props, lDoc.JsonSchemaDialect.ValueNode, rDoc.JsonSchemaDialect.ValueNode, + lDoc.JsonSchemaDialect.Value, rDoc.JsonSchemaDialect.Value, &changes, v3.JSONSchemaDialectLabel, true) + + // tags + dc.TagChanges = CompareTags(lDoc.Tags.Value, rDoc.Tags.Value) + + // paths + if !lDoc.Paths.IsEmpty() || !rDoc.Paths.IsEmpty() { + dc.PathsChanges = ComparePaths(lDoc.Paths.Value, rDoc.Paths.Value) + } + + // external docs + compareDocumentExternalDocs(lDoc, rDoc, dc, &changes) + + // info + compareDocumentInfo(&lDoc.Info, &rDoc.Info, dc, &changes) + + // security + if !lDoc.Security.IsEmpty() || !rDoc.Security.IsEmpty() { + checkSecurity(lDoc.Security, rDoc.Security, &changes, dc) + } + + // compare components. + if !lDoc.Components.IsEmpty() && !rDoc.Components.IsEmpty() { + if n := CompareComponents(lDoc.Components.Value, rDoc.Components.Value); n != nil { + dc.ComponentsChanges = n + } + } + if !lDoc.Components.IsEmpty() && rDoc.Components.IsEmpty() { + CreateChange(&changes, PropertyRemoved, v3.ComponentsLabel, + lDoc.Components.ValueNode, nil, true, lDoc.Components.Value, nil) + } + if lDoc.Components.IsEmpty() && !rDoc.Components.IsEmpty() { + CreateChange(&changes, PropertyAdded, v3.ComponentsLabel, + rDoc.Components.ValueNode, nil, false, nil, lDoc.Components.Value) + } + + // compare servers + if n := checkServers(lDoc.Servers, rDoc.Servers); n != nil { + dc.ServerChanges = n + } + + // compare webhooks + dc.WebhookChanges = CheckMapForChanges(lDoc.Webhooks.Value, rDoc.Webhooks.Value, &changes, + v3.WebhooksLabel, ComparePathItemsV3) + + // extensions + dc.ExtensionChanges = CompareExtensions(lDoc.Extensions, rDoc.Extensions) + } + + CheckProperties(props) + dc.PropertyChanges = NewPropertyChanges(changes) + if dc.TotalChanges() <= 0 { + return nil + } + return dc +} + +func compareDocumentExternalDocs(l, r low.HasExternalDocs, dc *DocumentChanges, changes *[]*Change) { + // external docs + if !l.GetExternalDocs().IsEmpty() && !r.GetExternalDocs().IsEmpty() { + lExtDoc := l.GetExternalDocs().Value.(*base.ExternalDoc) + rExtDoc := r.GetExternalDocs().Value.(*base.ExternalDoc) + if !low.AreEqual(lExtDoc, rExtDoc) { + dc.ExternalDocChanges = CompareExternalDocs(lExtDoc, rExtDoc) + } + } + if l.GetExternalDocs().IsEmpty() && !r.GetExternalDocs().IsEmpty() { + CreateChange(changes, PropertyAdded, v3.ExternalDocsLabel, + nil, r.GetExternalDocs().ValueNode, false, nil, + r.GetExternalDocs().Value) + } + if !l.GetExternalDocs().IsEmpty() && r.GetExternalDocs().IsEmpty() { + CreateChange(changes, PropertyRemoved, v3.ExternalDocsLabel, + l.GetExternalDocs().ValueNode, nil, false, l.GetExternalDocs().Value, + nil) + } +} + +func compareDocumentInfo(l, r *low.NodeReference[*base.Info], dc *DocumentChanges, changes *[]*Change) { + // info + if !l.IsEmpty() && !r.IsEmpty() { + lInfo := l.Value + rInfo := r.Value + if !low.AreEqual(lInfo, rInfo) { + dc.InfoChanges = CompareInfo(lInfo, rInfo) + } + } + if l.IsEmpty() && !r.IsEmpty() { + CreateChange(changes, PropertyAdded, v3.InfoLabel, + nil, r.ValueNode, false, nil, + r.Value) + } + if !l.IsEmpty() && r.IsEmpty() { + CreateChange(changes, PropertyRemoved, v3.InfoLabel, + l.ValueNode, nil, false, l.Value, + nil) + } +} diff --git a/vendor/github.com/pb33f/libopenapi/what-changed/model/encoding.go b/vendor/github.com/pb33f/libopenapi/what-changed/model/encoding.go new file mode 100644 index 0000000000..f4673055d2 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/what-changed/model/encoding.go @@ -0,0 +1,99 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package model + +import ( + v3 "github.com/pb33f/libopenapi/datamodel/low/v3" +) + +// EncodingChanges represent all the changes made to an Encoding object +type EncodingChanges struct { + *PropertyChanges + HeaderChanges map[string]*HeaderChanges `json:"headers,omitempty" yaml:"headers,omitempty"` +} + +// GetAllChanges returns a slice of all changes made between Encoding objects +func (e *EncodingChanges) GetAllChanges() []*Change { + var changes []*Change + changes = append(changes, e.Changes...) + for k := range e.HeaderChanges { + changes = append(changes, e.HeaderChanges[k].GetAllChanges()...) + } + return changes +} + +// TotalChanges returns the total number of changes made between two Encoding objects +func (e *EncodingChanges) TotalChanges() int { + c := e.PropertyChanges.TotalChanges() + if e.HeaderChanges != nil { + for i := range e.HeaderChanges { + c += e.HeaderChanges[i].TotalChanges() + } + } + return c +} + +// TotalBreakingChanges returns the number of changes made between two Encoding objects that were breaking. +func (e *EncodingChanges) TotalBreakingChanges() int { + c := e.PropertyChanges.TotalBreakingChanges() + if e.HeaderChanges != nil { + for i := range e.HeaderChanges { + c += e.HeaderChanges[i].TotalBreakingChanges() + } + } + return c +} + +// CompareEncoding returns a pointer to *EncodingChanges that contain all changes made between a left and right +// set of Encoding objects. +func CompareEncoding(l, r *v3.Encoding) *EncodingChanges { + + var changes []*Change + var props []*PropertyCheck + + // ContentType + props = append(props, &PropertyCheck{ + LeftNode: l.ContentType.ValueNode, + RightNode: r.ContentType.ValueNode, + Label: v3.ContentTypeLabel, + Changes: &changes, + Breaking: true, + Original: l, + New: r, + }) + + // Explode + props = append(props, &PropertyCheck{ + LeftNode: l.Explode.ValueNode, + RightNode: r.Explode.ValueNode, + Label: v3.ExplodeLabel, + Changes: &changes, + Breaking: true, + Original: l, + New: r, + }) + + // AllowReserved + props = append(props, &PropertyCheck{ + LeftNode: l.AllowReserved.ValueNode, + RightNode: r.AllowReserved.ValueNode, + Label: v3.AllowReservedLabel, + Changes: &changes, + Breaking: false, + Original: l, + New: r, + }) + + // check everything. + CheckProperties(props) + ec := new(EncodingChanges) + + // headers + ec.HeaderChanges = CheckMapForChanges(l.Headers.Value, r.Headers.Value, &changes, v3.HeadersLabel, CompareHeadersV3) + ec.PropertyChanges = NewPropertyChanges(changes) + if ec.TotalChanges() <= 0 { + return nil + } + return ec +} diff --git a/vendor/github.com/pb33f/libopenapi/what-changed/model/example.go b/vendor/github.com/pb33f/libopenapi/what-changed/model/example.go new file mode 100644 index 0000000000..cf0839c7a7 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/what-changed/model/example.go @@ -0,0 +1,215 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package model + +import ( + "crypto/sha256" + "fmt" + "sort" + + "gopkg.in/yaml.v3" + + "github.com/pb33f/libopenapi/datamodel/low/base" + v3 "github.com/pb33f/libopenapi/datamodel/low/v3" + "github.com/pb33f/libopenapi/utils" +) + +// ExampleChanges represent changes to an Example object, part of an OpenAPI specification. +type ExampleChanges struct { + *PropertyChanges + ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"` +} + +// GetAllChanges returns a slice of all changes made between Example objects +func (e *ExampleChanges) GetAllChanges() []*Change { + var changes []*Change + changes = append(changes, e.Changes...) + if e.ExtensionChanges != nil { + changes = append(changes, e.ExtensionChanges.GetAllChanges()...) + } + return changes +} + +// TotalChanges returns the total number of changes made to Example +func (e *ExampleChanges) TotalChanges() int { + l := e.PropertyChanges.TotalChanges() + if e.ExtensionChanges != nil { + l += e.ExtensionChanges.PropertyChanges.TotalChanges() + } + return l +} + +// TotalBreakingChanges returns the total number of breaking changes made to Example +func (e *ExampleChanges) TotalBreakingChanges() int { + l := e.PropertyChanges.TotalBreakingChanges() + return l +} + +// CompareExamples returns a pointer to ExampleChanges that contains all changes made between +// left and right Example instances. +func CompareExamples(l, r *base.Example) *ExampleChanges { + + ec := new(ExampleChanges) + var changes []*Change + var props []*PropertyCheck + + // Summary + props = append(props, &PropertyCheck{ + LeftNode: l.Summary.ValueNode, + RightNode: r.Summary.ValueNode, + Label: v3.SummaryLabel, + Changes: &changes, + Breaking: false, + Original: l, + New: r, + }) + + // Description + props = append(props, &PropertyCheck{ + LeftNode: l.Description.ValueNode, + RightNode: r.Description.ValueNode, + Label: v3.DescriptionLabel, + Changes: &changes, + Breaking: false, + Original: l, + New: r, + }) + + // Value + if utils.IsNodeMap(l.Value.ValueNode) && utils.IsNodeMap(r.Value.ValueNode) { + lKeys := make([]string, len(l.Value.ValueNode.Content)/2) + rKeys := make([]string, len(r.Value.ValueNode.Content)/2) + z := 0 + for k := range l.Value.ValueNode.Content { + if k%2 == 0 { + // if there is no value (value is another map or something else), render the node into yaml and hash it. + // https://github.com/pb33f/libopenapi/issues/61 + val := l.Value.ValueNode.Content[k+1].Value + if val == "" { + yaml, _ := yaml.Marshal(l.Value.ValueNode.Content[k+1].Content) + val = fmt.Sprint(sha256.Sum256(yaml)) + } + lKeys[z] = fmt.Sprintf("%v-%v-%v", + l.Value.ValueNode.Content[k].Value, + l.Value.ValueNode.Content[k+1].Tag, + fmt.Sprintf("%x", val)) + z++ + } else { + continue + } + } + z = 0 + for k := range r.Value.ValueNode.Content { + if k%2 == 0 { + // if there is no value (value is another map or something else), render the node into yaml and hash it. + // https://github.com/pb33f/libopenapi/issues/61 + val := r.Value.ValueNode.Content[k+1].Value + if val == "" { + yaml, _ := yaml.Marshal(r.Value.ValueNode.Content[k+1].Content) + val = fmt.Sprint(sha256.Sum256(yaml)) + } + rKeys[z] = fmt.Sprintf("%v-%v-%v", + r.Value.ValueNode.Content[k].Value, + r.Value.ValueNode.Content[k+1].Tag, + fmt.Sprintf("%x", val)) + z++ + } else { + continue + } + } + sort.Strings(lKeys) + sort.Strings(rKeys) + //if (len(lKeys) > len(rKeys)) || (len(rKeys) > len(lKeys)) { + // CreateChange(&changes, Modified, v3.ValueLabel, + // l.Value.GetValueNode(), r.Value.GetValueNode(), false, l.Value.GetValue(), r.Value.GetValue()) + //} + for k := range lKeys { + if k < len(rKeys) && lKeys[k] != rKeys[k] { + + if utils.IsNodeMap(l.Value.ValueNode) || utils.IsNodeArray(l.Value.ValueNode) { + // render down object + rendered, _ := yaml.Marshal(l.Value.ValueNode) + l.Value.ValueNode.Value = string(rendered) + } + + if utils.IsNodeMap(r.Value.ValueNode) || utils.IsNodeArray(r.Value.ValueNode) { + // render down object + rendered, _ := yaml.Marshal(r.Value.ValueNode) + r.Value.ValueNode.Value = string(rendered) + } + + CreateChange(&changes, Modified, v3.ValueLabel, + l.Value.GetValueNode(), r.Value.GetValueNode(), false, l.Value.GetValue(), r.Value.GetValue()) + continue + } + if k >= len(rKeys) { + + if utils.IsNodeMap(l.Value.ValueNode) || utils.IsNodeArray(l.Value.ValueNode) { + // render down object + rendered, _ := yaml.Marshal(l.Value.ValueNode) + l.Value.ValueNode.Value = string(rendered) + } + + if utils.IsNodeMap(r.Value.ValueNode) || utils.IsNodeArray(r.Value.ValueNode) { + // render down object + rendered, _ := yaml.Marshal(r.Value.ValueNode) + r.Value.ValueNode.Value = string(rendered) + } + + CreateChange(&changes, PropertyRemoved, v3.ValueLabel, + l.Value.ValueNode, r.Value.ValueNode, false, l.Value.Value, r.Value.Value) + } + } + for k := range rKeys { + if k >= len(lKeys) { + + if utils.IsNodeMap(l.Value.ValueNode) || utils.IsNodeArray(l.Value.ValueNode) { + // render down object + rendered, _ := yaml.Marshal(l.Value.ValueNode) + l.Value.ValueNode.Value = string(rendered) + } + + if utils.IsNodeMap(r.Value.ValueNode) || utils.IsNodeArray(r.Value.ValueNode) { + // render down object + rendered, _ := yaml.Marshal(r.Value.ValueNode) + r.Value.ValueNode.Value = string(rendered) + } + + CreateChange(&changes, PropertyAdded, v3.ValueLabel, + l.Value.ValueNode, r.Value.ValueNode, false, l.Value.Value, r.Value.Value) + } + } + } else { + props = append(props, &PropertyCheck{ + LeftNode: l.Value.ValueNode, + RightNode: r.Value.ValueNode, + Label: v3.ValueLabel, + Changes: &changes, + Breaking: false, + Original: l, + New: r, + }) + } + // ExternalValue + props = append(props, &PropertyCheck{ + LeftNode: l.ExternalValue.ValueNode, + RightNode: r.ExternalValue.ValueNode, + Label: v3.ExternalValue, + Changes: &changes, + Breaking: false, + Original: l, + New: r, + }) + + // check properties + CheckProperties(props) + + // check extensions + ec.ExtensionChanges = CheckExtensions(l, r) + ec.PropertyChanges = NewPropertyChanges(changes) + if ec.TotalChanges() <= 0 { + return nil + } + return ec +} diff --git a/vendor/github.com/pb33f/libopenapi/what-changed/model/examples.go b/vendor/github.com/pb33f/libopenapi/what-changed/model/examples.go new file mode 100644 index 0000000000..ecd6f947a7 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/what-changed/model/examples.go @@ -0,0 +1,86 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package model + +import ( + "github.com/pb33f/libopenapi/datamodel/low" + v2 "github.com/pb33f/libopenapi/datamodel/low/v2" +) + +// ExamplesChanges represents changes made between Swagger Examples objects (Not OpenAPI 3). +type ExamplesChanges struct { + *PropertyChanges +} + +// GetAllChanges returns a slice of all changes made between Examples objects +func (a *ExamplesChanges) GetAllChanges() []*Change { + return a.Changes +} + +// TotalChanges represents the total number of changes made between Example instances. +func (a *ExamplesChanges) TotalChanges() int { + return a.PropertyChanges.TotalChanges() +} + +// TotalBreakingChanges will always return 0. Examples cannot break a contract. +func (a *ExamplesChanges) TotalBreakingChanges() int { + return 0 // not supported. +} + +// CompareExamplesV2 compares two Swagger Examples objects, returning a pointer to +//ExamplesChanges if anything was found. +func CompareExamplesV2(l, r *v2.Examples) *ExamplesChanges { + + lHashes := make(map[string]string) + rHashes := make(map[string]string) + lValues := make(map[string]low.ValueReference[any]) + rValues := make(map[string]low.ValueReference[any]) + + for k := range l.Values { + lHashes[k.Value] = low.GenerateHashString(l.Values[k].Value) + lValues[k.Value] = l.Values[k] + } + + for k := range r.Values { + rHashes[k.Value] = low.GenerateHashString(r.Values[k].Value) + rValues[k.Value] = r.Values[k] + } + var changes []*Change + + // check left example hashes + for k := range lHashes { + rhash := rHashes[k] + if rhash == "" { + CreateChange(&changes, ObjectRemoved, k, + lValues[k].GetValueNode(), nil, false, + lValues[k].GetValue(), nil) + continue + } + if lHashes[k] == rHashes[k] { + continue + } + CreateChange(&changes, Modified, k, + lValues[k].GetValueNode(), rValues[k].GetValueNode(), false, + lValues[k].GetValue(), lValues[k].GetValue()) + + } + + //check right example hashes + for k := range rHashes { + lhash := lHashes[k] + if lhash == "" { + CreateChange(&changes, ObjectAdded, k, + nil, lValues[k].GetValueNode(), false, + nil, lValues[k].GetValue()) + continue + } + } + + ex := new(ExamplesChanges) + ex.PropertyChanges = NewPropertyChanges(changes) + if ex.TotalChanges() <= 0 { + return nil + } + return ex +} diff --git a/vendor/github.com/pb33f/libopenapi/what-changed/model/extensions.go b/vendor/github.com/pb33f/libopenapi/what-changed/model/extensions.go new file mode 100644 index 0000000000..a01d878937 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/what-changed/model/extensions.go @@ -0,0 +1,97 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package model + +import ( + "github.com/pb33f/libopenapi/datamodel/low" + "strings" +) + +// ExtensionChanges represents any changes to custom extensions defined for an OpenAPI object. +type ExtensionChanges struct { + *PropertyChanges +} + +// GetAllChanges returns a slice of all changes made between Extension objects +func (e *ExtensionChanges) GetAllChanges() []*Change { + return e.Changes +} + +// TotalChanges returns the total number of object extensions that were made. +func (e *ExtensionChanges) TotalChanges() int { + return e.PropertyChanges.TotalChanges() +} + +// TotalBreakingChanges always returns 0 for Extension objects, they are non-binding. +func (e *ExtensionChanges) TotalBreakingChanges() int { + return 0 +} + +// CompareExtensions will compare a left and right map of Tag/ValueReference models for any changes to +// anything. This function does not try and cast the value of an extension to perform checks, it +// will perform a basic value check. +// +// A current limitation relates to extensions being objects and a property of the object changes, +// there is currently no support for knowing anything changed - so it is ignored. +func CompareExtensions(l, r map[low.KeyReference[string]]low.ValueReference[any]) *ExtensionChanges { + + // look at the original and then look through the new. + seenLeft := make(map[string]*low.ValueReference[any]) + seenRight := make(map[string]*low.ValueReference[any]) + for i := range l { + h := l[i] + seenLeft[strings.ToLower(i.Value)] = &h + } + for i := range r { + h := r[i] + seenRight[strings.ToLower(i.Value)] = &h + } + + var changes []*Change + for i := range seenLeft { + + CheckForObjectAdditionOrRemoval[any](seenLeft, seenRight, i, &changes, false, true) + + if seenRight[i] != nil { + var props []*PropertyCheck + + props = append(props, &PropertyCheck{ + LeftNode: seenLeft[i].ValueNode, + RightNode: seenRight[i].ValueNode, + Label: i, + Changes: &changes, + Breaking: false, + Original: seenLeft[i].Value, + New: seenRight[i].Value, + }) + + // check properties + CheckProperties(props) + } + } + for i := range seenRight { + if seenLeft[i] == nil { + CheckForObjectAdditionOrRemoval[any](seenLeft, seenRight, i, &changes, false, true) + } + } + ex := new(ExtensionChanges) + ex.PropertyChanges = NewPropertyChanges(changes) + if ex.TotalChanges() <= 0 { + return nil + } + return ex +} + +// CheckExtensions is a helper method to un-pack a left and right model that contains extensions. Once unpacked +// the extensions are compared and returns a pointer to ExtensionChanges. If nothing changed, nil is returned. +func CheckExtensions[T low.HasExtensions[T]](l, r T) *ExtensionChanges { + var lExt, rExt map[low.KeyReference[string]]low.ValueReference[any] + if len(l.GetExtensions()) > 0 { + lExt = l.GetExtensions() + } + if len(r.GetExtensions()) > 0 { + rExt = r.GetExtensions() + } + return CompareExtensions(lExt, rExt) +} diff --git a/vendor/github.com/pb33f/libopenapi/what-changed/model/external_docs.go b/vendor/github.com/pb33f/libopenapi/what-changed/model/external_docs.go new file mode 100644 index 0000000000..47b1bd8420 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/what-changed/model/external_docs.go @@ -0,0 +1,82 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package model + +import ( + "github.com/pb33f/libopenapi/datamodel/low/base" + "github.com/pb33f/libopenapi/datamodel/low/v3" +) + +// ExternalDocChanges represents changes made to any ExternalDoc object from an OpenAPI document. +type ExternalDocChanges struct { + *PropertyChanges + ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"` +} + +// GetAllChanges returns a slice of all changes made between Example objects +func (e *ExternalDocChanges) GetAllChanges() []*Change { + var changes []*Change + changes = append(changes, e.Changes...) + if e.ExtensionChanges != nil { + changes = append(changes, e.ExtensionChanges.GetAllChanges()...) + } + return changes +} + +// TotalChanges returns a count of everything that changed +func (e *ExternalDocChanges) TotalChanges() int { + c := e.PropertyChanges.TotalChanges() + if e.ExtensionChanges != nil { + c += e.ExtensionChanges.TotalChanges() + } + return c +} + +// TotalBreakingChanges always returns 0 for ExternalDoc objects, they are non-binding. +func (e *ExternalDocChanges) TotalBreakingChanges() int { + return 0 +} + +// CompareExternalDocs will compare a left (original) and a right (new) slice of ValueReference +// nodes for any changes between them. If there are changes, then a pointer to ExternalDocChanges +// is returned, otherwise if nothing changed - then nil is returned. +func CompareExternalDocs(l, r *base.ExternalDoc) *ExternalDocChanges { + var changes []*Change + var props []*PropertyCheck + + // URL + props = append(props, &PropertyCheck{ + LeftNode: l.URL.ValueNode, + RightNode: r.URL.ValueNode, + Label: v3.URLLabel, + Changes: &changes, + Breaking: false, + Original: l, + New: r, + }) + + // description. + props = append(props, &PropertyCheck{ + LeftNode: l.Description.ValueNode, + RightNode: r.Description.ValueNode, + Label: v3.DescriptionLabel, + Changes: &changes, + Breaking: false, + Original: l, + New: r, + }) + + // check everything. + CheckProperties(props) + + dc := new(ExternalDocChanges) + dc.PropertyChanges = NewPropertyChanges(changes) + + // check extensions + dc.ExtensionChanges = CheckExtensions(l, r) + if dc.TotalChanges() <= 0 { + return nil + } + return dc +} diff --git a/vendor/github.com/pb33f/libopenapi/what-changed/model/header.go b/vendor/github.com/pb33f/libopenapi/what-changed/model/header.go new file mode 100644 index 0000000000..10a9592433 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/what-changed/model/header.go @@ -0,0 +1,280 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package model + +import ( + "github.com/pb33f/libopenapi/datamodel/low" + v2 "github.com/pb33f/libopenapi/datamodel/low/v2" + "github.com/pb33f/libopenapi/datamodel/low/v3" + "reflect" +) + +// HeaderChanges represents changes made between two Header objects. Supports both Swagger and OpenAPI header +// objects, V2 only property Items is broken out into its own. +type HeaderChanges struct { + *PropertyChanges + SchemaChanges *SchemaChanges `json:"schemas,omitempty" yaml:"schemas,omitempty"` + ExamplesChanges map[string]*ExampleChanges `json:"examples,omitempty" yaml:"examples,omitempty"` + ContentChanges map[string]*MediaTypeChanges `json:"content,omitempty" yaml:"content,omitempty"` + ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"` + + // Items only supported by Swagger (V2) + ItemsChanges *ItemsChanges `json:"items,omitempty" yaml:"items,omitempty"` +} + +// GetAllChanges returns a slice of all changes made between Header objects +func (h *HeaderChanges) GetAllChanges() []*Change { + var changes []*Change + changes = append(changes, h.Changes...) + for k := range h.ExamplesChanges { + changes = append(changes, h.ExamplesChanges[k].GetAllChanges()...) + } + for k := range h.ContentChanges { + changes = append(changes, h.ContentChanges[k].GetAllChanges()...) + } + if h.ExtensionChanges != nil { + changes = append(changes, h.ExtensionChanges.GetAllChanges()...) + } + if h.SchemaChanges != nil { + changes = append(changes, h.SchemaChanges.GetAllChanges()...) + } + if h.ItemsChanges != nil { + changes = append(changes, h.ItemsChanges.GetAllChanges()...) + } + return changes +} + +// TotalChanges returns the total number of changes made between two Header objects. +func (h *HeaderChanges) TotalChanges() int { + c := h.PropertyChanges.TotalChanges() + for k := range h.ExamplesChanges { + c += h.ExamplesChanges[k].TotalChanges() + } + for k := range h.ContentChanges { + c += h.ContentChanges[k].TotalChanges() + } + if h.ExtensionChanges != nil { + c += h.ExtensionChanges.TotalChanges() + } + if h.SchemaChanges != nil { + c += h.SchemaChanges.TotalChanges() + } + if h.ItemsChanges != nil { + c += h.ItemsChanges.TotalChanges() + } + return c +} + +// TotalBreakingChanges returns the total number of breaking changes made between two Header instances. +func (h *HeaderChanges) TotalBreakingChanges() int { + c := h.PropertyChanges.TotalBreakingChanges() + for k := range h.ContentChanges { + c += h.ContentChanges[k].TotalBreakingChanges() + } + if h.ItemsChanges != nil { + c += h.ItemsChanges.TotalBreakingChanges() + } + if h.SchemaChanges != nil { + c += h.SchemaChanges.TotalBreakingChanges() + } + return c +} + +// shared header properties +func addOpenAPIHeaderProperties(left, right low.OpenAPIHeader, changes *[]*Change) []*PropertyCheck { + var props []*PropertyCheck + + // style + addPropertyCheck(&props, left.GetStyle().ValueNode, right.GetStyle().ValueNode, + left.GetStyle(), right.GetStyle(), changes, v3.StyleLabel, false) + + // allow reserved + addPropertyCheck(&props, left.GetAllowReserved().ValueNode, right.GetAllowReserved().ValueNode, + left.GetAllowReserved(), right.GetAllowReserved(), changes, v3.AllowReservedLabel, false) + + // allow empty value + addPropertyCheck(&props, left.GetAllowEmptyValue().ValueNode, right.GetAllowEmptyValue().ValueNode, + left.GetAllowEmptyValue(), right.GetAllowEmptyValue(), changes, v3.AllowEmptyValueLabel, true) + + // explode + addPropertyCheck(&props, left.GetExplode().ValueNode, right.GetExplode().ValueNode, + left.GetExplode(), right.GetExplode(), changes, v3.ExplodeLabel, false) + + // example + addPropertyCheck(&props, left.GetExample().ValueNode, right.GetExample().ValueNode, + left.GetExample(), right.GetExample(), changes, v3.ExampleLabel, false) + + // deprecated + addPropertyCheck(&props, left.GetDeprecated().ValueNode, right.GetDeprecated().ValueNode, + left.GetDeprecated(), right.GetDeprecated(), changes, v3.DeprecatedLabel, false) + + // required + addPropertyCheck(&props, left.GetRequired().ValueNode, right.GetRequired().ValueNode, + left.GetRequired(), right.GetRequired(), changes, v3.RequiredLabel, true) + + return props +} + +// swagger only properties +func addSwaggerHeaderProperties(left, right low.SwaggerHeader, changes *[]*Change) []*PropertyCheck { + var props []*PropertyCheck + + // type + addPropertyCheck(&props, left.GetType().ValueNode, right.GetType().ValueNode, + left.GetType(), right.GetType(), changes, v3.TypeLabel, true) + + // format + addPropertyCheck(&props, left.GetFormat().ValueNode, right.GetFormat().ValueNode, + left.GetFormat(), right.GetFormat(), changes, v3.FormatLabel, true) + + // collection format + addPropertyCheck(&props, left.GetCollectionFormat().ValueNode, right.GetCollectionFormat().ValueNode, + left.GetCollectionFormat(), right.GetCollectionFormat(), changes, v3.CollectionFormatLabel, true) + + // maximum + addPropertyCheck(&props, left.GetMaximum().ValueNode, right.GetMaximum().ValueNode, + left.GetMaximum(), right.GetMaximum(), changes, v3.MaximumLabel, true) + + // minimum + addPropertyCheck(&props, left.GetMinimum().ValueNode, right.GetMinimum().ValueNode, + left.GetMinimum(), right.GetMinimum(), changes, v3.MinimumLabel, true) + + // exclusive maximum + addPropertyCheck(&props, left.GetExclusiveMaximum().ValueNode, right.GetExclusiveMaximum().ValueNode, + left.GetExclusiveMaximum(), right.GetExclusiveMaximum(), changes, v3.ExclusiveMaximumLabel, true) + + // exclusive minimum + addPropertyCheck(&props, left.GetExclusiveMinimum().ValueNode, right.GetExclusiveMinimum().ValueNode, + left.GetExclusiveMinimum(), right.GetExclusiveMinimum(), changes, v3.ExclusiveMinimumLabel, true) + + // max length + addPropertyCheck(&props, left.GetMaxLength().ValueNode, right.GetMaxLength().ValueNode, + left.GetMaxLength(), right.GetMaxLength(), changes, v3.MaxLengthLabel, true) + + // min length + addPropertyCheck(&props, left.GetMinLength().ValueNode, right.GetMinLength().ValueNode, + left.GetMinLength(), right.GetMinLength(), changes, v3.MinLengthLabel, true) + + // pattern + addPropertyCheck(&props, left.GetPattern().ValueNode, right.GetPattern().ValueNode, + left.GetPattern(), right.GetPattern(), changes, v3.PatternLabel, true) + + // max items + addPropertyCheck(&props, left.GetMaxItems().ValueNode, right.GetMaxItems().ValueNode, + left.GetMaxItems(), right.GetMaxItems(), changes, v3.MaxItemsLabel, true) + + // min items + addPropertyCheck(&props, left.GetMinItems().ValueNode, right.GetMinItems().ValueNode, + left.GetMinItems(), right.GetMinItems(), changes, v3.MinItemsLabel, true) + + // unique items + addPropertyCheck(&props, left.GetUniqueItems().ValueNode, right.GetUniqueItems().ValueNode, + left.GetUniqueItems(), right.GetUniqueItems(), changes, v3.UniqueItemsLabel, true) + + // multiple of + addPropertyCheck(&props, left.GetMultipleOf().ValueNode, right.GetMultipleOf().ValueNode, + left.GetMultipleOf(), right.GetMultipleOf(), changes, v3.MultipleOfLabel, true) + + return props +} + +// common header properties +func addCommonHeaderProperties(left, right low.HasDescription, changes *[]*Change) []*PropertyCheck { + var props []*PropertyCheck + + // description + addPropertyCheck(&props, left.GetDescription().ValueNode, right.GetDescription().ValueNode, + left.GetDescription(), right.GetDescription(), changes, v3.DescriptionLabel, false) + + return props +} + +// CompareHeadersV2 is a Swagger compatible, typed signature used for other generic functions. It simply +// wraps CompareHeaders and provides nothing other that a typed interface. +func CompareHeadersV2(l, r *v2.Header) *HeaderChanges { + return CompareHeaders(l, r) +} + +// CompareHeadersV3 is an OpenAPI 3+ compatible, typed signature used for other generic functions. It simply +// wraps CompareHeaders and provides nothing other that a typed interface. +func CompareHeadersV3(l, r *v3.Header) *HeaderChanges { + return CompareHeaders(l, r) +} + +// CompareHeaders will compare left and right Header objects (any version of Swagger or OpenAPI) and return +// a pointer to HeaderChanges with anything that has changed, or nil if nothing changed. +func CompareHeaders(l, r any) *HeaderChanges { + + var changes []*Change + var props []*PropertyCheck + hc := new(HeaderChanges) + + // handle swagger. + if reflect.TypeOf(&v2.Header{}) == reflect.TypeOf(l) && reflect.TypeOf(&v2.Header{}) == reflect.TypeOf(r) { + lHeader := l.(*v2.Header) + rHeader := r.(*v2.Header) + + // perform hash check to avoid further processing + if low.AreEqual(lHeader, rHeader) { + return nil + } + + props = append(props, addCommonHeaderProperties(lHeader, rHeader, &changes)...) + props = append(props, addSwaggerHeaderProperties(lHeader, rHeader, &changes)...) + + // enum + if len(lHeader.Enum.Value) > 0 || len(rHeader.Enum.Value) > 0 { + ExtractRawValueSliceChanges(lHeader.Enum.Value, rHeader.Enum.Value, &changes, v3.EnumLabel, true) + } + + // items + if !lHeader.Items.IsEmpty() && !rHeader.Items.IsEmpty() { + if !low.AreEqual(lHeader.Items.Value, rHeader.Items.Value) { + hc.ItemsChanges = CompareItems(lHeader.Items.Value, rHeader.Items.Value) + } + } + if lHeader.Items.IsEmpty() && !rHeader.Items.IsEmpty() { + CreateChange(&changes, ObjectAdded, v3.ItemsLabel, nil, + rHeader.Items.ValueNode, true, nil, rHeader.Items.Value) + } + if !lHeader.Items.IsEmpty() && rHeader.Items.IsEmpty() { + CreateChange(&changes, ObjectRemoved, v3.SchemaLabel, lHeader.Items.ValueNode, + nil, true, lHeader.Items.Value, nil) + } + hc.ExtensionChanges = CompareExtensions(lHeader.Extensions, rHeader.Extensions) + } + + // handle OpenAPI + if reflect.TypeOf(&v3.Header{}) == reflect.TypeOf(l) && reflect.TypeOf(&v3.Header{}) == reflect.TypeOf(r) { + lHeader := l.(*v3.Header) + rHeader := r.(*v3.Header) + + // perform hash check to avoid further processing + if low.AreEqual(lHeader, rHeader) { + return nil + } + + props = append(props, addCommonHeaderProperties(lHeader, rHeader, &changes)...) + props = append(props, addOpenAPIHeaderProperties(lHeader, rHeader, &changes)...) + + // header + if !lHeader.Schema.IsEmpty() || !rHeader.Schema.IsEmpty() { + hc.SchemaChanges = CompareSchemas(lHeader.Schema.Value, rHeader.Schema.Value) + } + + // examples + hc.ExamplesChanges = CheckMapForChanges(lHeader.Examples.Value, rHeader.Examples.Value, + &changes, v3.ExamplesLabel, CompareExamples) + + // content + hc.ContentChanges = CheckMapForChanges(lHeader.Content.Value, rHeader.Content.Value, + &changes, v3.ContentLabel, CompareMediaTypes) + + hc.ExtensionChanges = CompareExtensions(lHeader.Extensions, rHeader.Extensions) + + } + CheckProperties(props) + hc.PropertyChanges = NewPropertyChanges(changes) + return hc +} diff --git a/vendor/github.com/pb33f/libopenapi/what-changed/model/info.go b/vendor/github.com/pb33f/libopenapi/what-changed/model/info.go new file mode 100644 index 0000000000..98021f65c8 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/what-changed/model/info.go @@ -0,0 +1,147 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package model + +import ( + "github.com/pb33f/libopenapi/datamodel/low/base" + v3 "github.com/pb33f/libopenapi/datamodel/low/v3" +) + +// InfoChanges represents the number of changes to an Info object. Part of an OpenAPI document +type InfoChanges struct { + *PropertyChanges + ContactChanges *ContactChanges `json:"contact,omitempty" yaml:"contact,omitempty"` + LicenseChanges *LicenseChanges `json:"license,omitempty" yaml:"license,omitempty"` +} + +// GetAllChanges returns a slice of all changes made between Info objects +func (i *InfoChanges) GetAllChanges() []*Change { + var changes []*Change + changes = append(changes, i.Changes...) + if i.ContactChanges != nil { + changes = append(changes, i.ContactChanges.GetAllChanges()...) + } + if i.LicenseChanges != nil { + changes = append(changes, i.LicenseChanges.GetAllChanges()...) + } + return changes +} + +// TotalChanges represents the total number of changes made to an Info object. +func (i *InfoChanges) TotalChanges() int { + t := i.PropertyChanges.TotalChanges() + if i.ContactChanges != nil { + t += i.ContactChanges.TotalChanges() + } + if i.LicenseChanges != nil { + t += i.LicenseChanges.TotalChanges() + } + return t +} + +// TotalBreakingChanges always returns 0 for Info objects, they are non-binding. +func (i *InfoChanges) TotalBreakingChanges() int { + return 0 +} + +// CompareInfo will compare a left (original) and a right (new) Info object. Any changes +// will be returned in a pointer to InfoChanges, otherwise if nothing is found, then nil is +// returned instead. +func CompareInfo(l, r *base.Info) *InfoChanges { + var changes []*Change + var props []*PropertyCheck + + // Title + props = append(props, &PropertyCheck{ + LeftNode: l.Title.ValueNode, + RightNode: r.Title.ValueNode, + Label: v3.TitleLabel, + Changes: &changes, + Breaking: false, + Original: l, + New: r, + }) + + // Summary + props = append(props, &PropertyCheck{ + LeftNode: l.Summary.ValueNode, + RightNode: r.Summary.ValueNode, + Label: v3.SummaryLabel, + Changes: &changes, + Breaking: false, + Original: l, + New: r, + }) + + // Description + props = append(props, &PropertyCheck{ + LeftNode: l.Description.ValueNode, + RightNode: r.Description.ValueNode, + Label: v3.DescriptionLabel, + Changes: &changes, + Breaking: false, + Original: l, + New: r, + }) + + // TermsOfService + props = append(props, &PropertyCheck{ + LeftNode: l.TermsOfService.ValueNode, + RightNode: r.TermsOfService.ValueNode, + Label: v3.TermsOfServiceLabel, + Changes: &changes, + Breaking: false, + Original: l, + New: r, + }) + + // Version + props = append(props, &PropertyCheck{ + LeftNode: l.Version.ValueNode, + RightNode: r.Version.ValueNode, + Label: v3.VersionLabel, + Changes: &changes, + Breaking: false, + Original: l, + New: r, + }) + + // check properties + CheckProperties(props) + + i := new(InfoChanges) + + // compare contact. + if l.Contact.Value != nil && r.Contact.Value != nil { + i.ContactChanges = CompareContact(l.Contact.Value, r.Contact.Value) + } else { + if l.Contact.Value == nil && r.Contact.Value != nil { + CreateChange(&changes, ObjectAdded, v3.ContactLabel, + nil, r.Contact.ValueNode, false, nil, r.Contact.Value) + } + if l.Contact.Value != nil && r.Contact.Value == nil { + CreateChange(&changes, ObjectRemoved, v3.ContactLabel, + l.Contact.ValueNode, nil, false, l.Contact.Value, nil) + } + } + + // compare license. + if l.License.Value != nil && r.License.Value != nil { + i.LicenseChanges = CompareLicense(l.License.Value, r.License.Value) + } else { + if l.License.Value == nil && r.License.Value != nil { + CreateChange(&changes, ObjectAdded, v3.LicenseLabel, + nil, r.License.ValueNode, false, nil, r.License.Value) + } + if l.License.Value != nil && r.License.Value == nil { + CreateChange(&changes, ObjectRemoved, v3.LicenseLabel, + l.License.ValueNode, nil, false, r.License.Value, nil) + } + } + i.PropertyChanges = NewPropertyChanges(changes) + if i.TotalChanges() <= 0 { + return nil + } + return i +} diff --git a/vendor/github.com/pb33f/libopenapi/what-changed/model/items.go b/vendor/github.com/pb33f/libopenapi/what-changed/model/items.go new file mode 100644 index 0000000000..e0da83ae7d --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/what-changed/model/items.go @@ -0,0 +1,88 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package model + +import ( + v2 "github.com/pb33f/libopenapi/datamodel/low/v2" + v3 "github.com/pb33f/libopenapi/datamodel/low/v3" +) + +// ItemsChanges represent changes found between a left (original) and right (modified) object. Items is only +// used by Swagger documents. +type ItemsChanges struct { + *PropertyChanges + ItemsChanges *ItemsChanges `json:"items,omitempty" yaml:"items,omitempty"` +} + +// GetAllChanges returns a slice of all changes made between Items objects +func (i *ItemsChanges) GetAllChanges() []*Change { + var changes []*Change + changes = append(changes, i.Changes...) + if i.ItemsChanges != nil { + changes = append(changes, i.ItemsChanges.GetAllChanges()...) + } + return changes +} + +// TotalChanges returns the total number of changes found between two Items objects +// This is a recursive function because Items can contain Items. Be careful! +func (i *ItemsChanges) TotalChanges() int { + c := i.PropertyChanges.TotalChanges() + if i.ItemsChanges != nil { + c += i.ItemsChanges.TotalChanges() + } + return c +} + +// TotalBreakingChanges returns the total number of breaking changes found between two Swagger Items objects +// This is a recursive method, Items are recursive, be careful! +func (i *ItemsChanges) TotalBreakingChanges() int { + c := i.PropertyChanges.TotalBreakingChanges() + if i.ItemsChanges != nil { + c += i.ItemsChanges.TotalBreakingChanges() + } + return c +} + +// CompareItems compares two sets of Swagger Item objects. If there are any changes found then a pointer to +// ItemsChanges will be returned, otherwise nil is returned. +// +// It is worth nothing that Items can contain Items. This means recursion is possible and has the potential for +// runaway code if not using the resolver's circular reference checking. +func CompareItems(l, r *v2.Items) *ItemsChanges { + + var changes []*Change + var props []*PropertyCheck + + ic := new(ItemsChanges) + + // header is identical to items, except for a description. + props = append(props, addSwaggerHeaderProperties(l, r, &changes)...) + CheckProperties(props) + + if !l.Items.IsEmpty() && !r.Items.IsEmpty() { + // inline, check hashes, if they don't match, compare. + if l.Items.Value.Hash() != r.Items.Value.Hash() { + // compare. + ic.ItemsChanges = CompareItems(l.Items.Value, r.Items.Value) + } + + } + if l.Items.IsEmpty() && !r.Items.IsEmpty() { + // added items + CreateChange(&changes, PropertyAdded, v3.ItemsLabel, + nil, r.Items.GetValueNode(), true, nil, r.Items.GetValue()) + } + if !l.Items.IsEmpty() && r.Items.IsEmpty() { + // removed items + CreateChange(&changes, PropertyRemoved, v3.ItemsLabel, + l.Items.GetValueNode(), nil, true, l.Items.GetValue(), + nil) + } + ic.PropertyChanges = NewPropertyChanges(changes) + if ic.TotalChanges() <= 0 { + return nil + } + return ic +} diff --git a/vendor/github.com/pb33f/libopenapi/what-changed/model/license.go b/vendor/github.com/pb33f/libopenapi/what-changed/model/license.go new file mode 100644 index 0000000000..6ffbc87a40 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/what-changed/model/license.go @@ -0,0 +1,70 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package model + +import ( + "github.com/pb33f/libopenapi/datamodel/low/base" + "github.com/pb33f/libopenapi/datamodel/low/v3" +) + +// LicenseChanges represent changes to a License object that is a child of Info object. Part of an OpenAPI document +type LicenseChanges struct { + *PropertyChanges +} + +// GetAllChanges returns a slice of all changes made between License objects +func (l *LicenseChanges) GetAllChanges() []*Change { + return l.Changes +} + +// TotalChanges represents the total number of changes made to a License instance. +func (l *LicenseChanges) TotalChanges() int { + return l.PropertyChanges.TotalChanges() +} + +// TotalBreakingChanges always returns 0 for License objects, they are non-binding. +func (l *LicenseChanges) TotalBreakingChanges() int { + return 0 +} + +// CompareLicense will check a left (original) and right (new) License object for any changes. If there +// were any, a pointer to a LicenseChanges object is returned, otherwise if nothing changed - the function +// returns nil. +func CompareLicense(l, r *base.License) *LicenseChanges { + + var changes []*Change + var props []*PropertyCheck + + // check URL + props = append(props, &PropertyCheck{ + LeftNode: l.URL.ValueNode, + RightNode: r.URL.ValueNode, + Label: v3.URLLabel, + Changes: &changes, + Breaking: false, + Original: l, + New: r, + }) + + // check name + props = append(props, &PropertyCheck{ + LeftNode: l.Name.ValueNode, + RightNode: r.Name.ValueNode, + Label: v3.NameLabel, + Changes: &changes, + Breaking: false, + Original: l, + New: r, + }) + + // check everything. + CheckProperties(props) + + lc := new(LicenseChanges) + lc.PropertyChanges = NewPropertyChanges(changes) + if lc.TotalChanges() <= 0 { + return nil + } + return lc +} diff --git a/vendor/github.com/pb33f/libopenapi/what-changed/model/link.go b/vendor/github.com/pb33f/libopenapi/what-changed/model/link.go new file mode 100644 index 0000000000..478a70e572 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/what-changed/model/link.go @@ -0,0 +1,160 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package model + +import ( + "github.com/pb33f/libopenapi/datamodel/low" + v3 "github.com/pb33f/libopenapi/datamodel/low/v3" +) + +// LinkChanges represent changes made between two OpenAPI Link Objects. +type LinkChanges struct { + *PropertyChanges + ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"` + ServerChanges *ServerChanges `json:"server,omitempty" yaml:"server,omitempty"` +} + +// GetAllChanges returns a slice of all changes made between Link objects +func (l *LinkChanges) GetAllChanges() []*Change { + var changes []*Change + changes = append(changes, l.Changes...) + if l.ServerChanges != nil { + changes = append(changes, l.ServerChanges.GetAllChanges()...) + } + if l.ExtensionChanges != nil { + changes = append(changes, l.ExtensionChanges.GetAllChanges()...) + } + return changes +} + +// TotalChanges returns the total changes made between OpenAPI Link objects +func (l *LinkChanges) TotalChanges() int { + c := l.PropertyChanges.TotalChanges() + if l.ExtensionChanges != nil { + c += l.ExtensionChanges.TotalChanges() + } + if l.ServerChanges != nil { + c += l.ServerChanges.TotalChanges() + } + return c +} + +// TotalBreakingChanges returns the number of breaking changes made between two OpenAPI Link Objects +func (l *LinkChanges) TotalBreakingChanges() int { + c := l.PropertyChanges.TotalBreakingChanges() + if l.ServerChanges != nil { + c += l.ServerChanges.TotalBreakingChanges() + } + return c +} + +// CompareLinks checks a left and right OpenAPI Link for any changes. If they are found, returns a pointer to +// LinkChanges, and returns nil if nothing is found. +func CompareLinks(l, r *v3.Link) *LinkChanges { + if low.AreEqual(l, r) { + return nil + } + + var props []*PropertyCheck + var changes []*Change + + // operation ref + props = append(props, &PropertyCheck{ + LeftNode: l.OperationRef.ValueNode, + RightNode: r.OperationRef.ValueNode, + Label: v3.OperationRefLabel, + Changes: &changes, + Breaking: true, + Original: l, + New: r, + }) + + // operation id + props = append(props, &PropertyCheck{ + LeftNode: l.OperationId.ValueNode, + RightNode: r.OperationId.ValueNode, + Label: v3.OperationIdLabel, + Changes: &changes, + Breaking: true, + Original: l, + New: r, + }) + + // request body + props = append(props, &PropertyCheck{ + LeftNode: l.RequestBody.ValueNode, + RightNode: r.RequestBody.ValueNode, + Label: v3.RequestBodyLabel, + Changes: &changes, + Breaking: true, + Original: l, + New: r, + }) + + // description + props = append(props, &PropertyCheck{ + LeftNode: l.Description.ValueNode, + RightNode: r.Description.ValueNode, + Label: v3.DescriptionLabel, + Changes: &changes, + Breaking: false, + Original: l, + New: r, + }) + + CheckProperties(props) + lc := new(LinkChanges) + lc.ExtensionChanges = CompareExtensions(l.Extensions, r.Extensions) + + // server + if !l.Server.IsEmpty() && !r.Server.IsEmpty() { + if !low.AreEqual(l.Server.Value, r.Server.Value) { + lc.ServerChanges = CompareServers(l.Server.Value, r.Server.Value) + } + } + if !l.Server.IsEmpty() && r.Server.IsEmpty() { + CreateChange(&changes, PropertyRemoved, v3.ServerLabel, + l.Server.ValueNode, nil, true, + l.Server.Value, nil) + } + if l.Server.IsEmpty() && !r.Server.IsEmpty() { + CreateChange(&changes, PropertyAdded, v3.ServerLabel, + nil, r.Server.ValueNode, true, + nil, r.Server.Value) + } + + // parameters + lValues := make(map[string]low.ValueReference[string]) + rValues := make(map[string]low.ValueReference[string]) + for i := range l.Parameters.Value { + lValues[i.Value] = l.Parameters.Value[i] + } + for i := range r.Parameters.Value { + rValues[i.Value] = r.Parameters.Value[i] + } + for k := range lValues { + if _, ok := rValues[k]; !ok { + CreateChange(&changes, ObjectRemoved, v3.ParametersLabel, + lValues[k].ValueNode, nil, true, + k, nil) + continue + } + if lValues[k].Value != rValues[k].Value { + CreateChange(&changes, Modified, v3.ParametersLabel, + lValues[k].ValueNode, rValues[k].ValueNode, true, + k, k) + } + + } + for k := range rValues { + if _, ok := lValues[k]; !ok { + CreateChange(&changes, ObjectAdded, v3.ParametersLabel, + nil, rValues[k].ValueNode, true, + nil, k) + } + } + + lc.PropertyChanges = NewPropertyChanges(changes) + return lc +} diff --git a/vendor/github.com/pb33f/libopenapi/what-changed/model/media_type.go b/vendor/github.com/pb33f/libopenapi/what-changed/model/media_type.go new file mode 100644 index 0000000000..796d1a75ab --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/what-changed/model/media_type.go @@ -0,0 +1,149 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package model + +import ( + "github.com/pb33f/libopenapi/datamodel/low" + "github.com/pb33f/libopenapi/datamodel/low/v3" + "github.com/pb33f/libopenapi/utils" + "gopkg.in/yaml.v3" +) + +// MediaTypeChanges represent changes made between two OpenAPI MediaType instances. +type MediaTypeChanges struct { + *PropertyChanges + SchemaChanges *SchemaChanges `json:"schemas,omitempty" yaml:"schemas,omitempty"` + ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"` + ExampleChanges map[string]*ExampleChanges `json:"examples,omitempty" yaml:"examples,omitempty"` + EncodingChanges map[string]*EncodingChanges `json:"encoding,omitempty" yaml:"encoding,omitempty"` +} + +// GetAllChanges returns a slice of all changes made between MediaType objects +func (m *MediaTypeChanges) GetAllChanges() []*Change { + var changes []*Change + changes = append(changes, m.Changes...) + if m.SchemaChanges != nil { + changes = append(changes, m.SchemaChanges.GetAllChanges()...) + } + for k := range m.ExampleChanges { + changes = append(changes, m.ExampleChanges[k].GetAllChanges()...) + } + for k := range m.EncodingChanges { + changes = append(changes, m.EncodingChanges[k].GetAllChanges()...) + } + if m.ExtensionChanges != nil { + changes = append(changes, m.ExtensionChanges.GetAllChanges()...) + } + return changes +} + +// TotalChanges returns the total number of changes between two MediaType instances. +func (m *MediaTypeChanges) TotalChanges() int { + c := m.PropertyChanges.TotalChanges() + for k := range m.ExampleChanges { + c += m.ExampleChanges[k].TotalChanges() + } + if m.SchemaChanges != nil { + c += m.SchemaChanges.TotalChanges() + } + if len(m.EncodingChanges) > 0 { + for i := range m.EncodingChanges { + c += m.EncodingChanges[i].TotalChanges() + } + } + if m.ExtensionChanges != nil { + c += m.ExtensionChanges.TotalChanges() + } + return c +} + +// TotalBreakingChanges returns the total number of breaking changes made between two MediaType instances. +func (m *MediaTypeChanges) TotalBreakingChanges() int { + c := m.PropertyChanges.TotalBreakingChanges() + for k := range m.ExampleChanges { + c += m.ExampleChanges[k].TotalBreakingChanges() + } + if m.SchemaChanges != nil { + c += m.SchemaChanges.TotalBreakingChanges() + } + if len(m.EncodingChanges) > 0 { + for i := range m.EncodingChanges { + c += m.EncodingChanges[i].TotalBreakingChanges() + } + } + return c +} + +// CompareMediaTypes compares a left and a right MediaType object for any changes. If found, a pointer to a +// MediaTypeChanges instance is returned, otherwise nothing is returned. +func CompareMediaTypes(l, r *v3.MediaType) *MediaTypeChanges { + + var props []*PropertyCheck + var changes []*Change + + mc := new(MediaTypeChanges) + + if low.AreEqual(l, r) { + return nil + } + + // Example + if !l.Example.IsEmpty() && !r.Example.IsEmpty() { + if (utils.IsNodeMap(l.Example.ValueNode) && utils.IsNodeMap(r.Example.ValueNode)) || + (utils.IsNodeArray(l.Example.ValueNode) && utils.IsNodeArray(r.Example.ValueNode)) { + render, _ := yaml.Marshal(l.Example.ValueNode) + render, _ = utils.ConvertYAMLtoJSON(render) + l.Example.ValueNode.Value = string(render) + render, _ = yaml.Marshal(r.Example.ValueNode) + render, _ = utils.ConvertYAMLtoJSON(render) + r.Example.ValueNode.Value = string(render) + } + addPropertyCheck(&props, l.Example.ValueNode, r.Example.ValueNode, + l.Example.Value, r.Example.Value, &changes, v3.ExampleLabel, false) + + } else { + + if utils.IsNodeMap(l.Example.ValueNode) || utils.IsNodeArray(l.Example.ValueNode) { + render, _ := yaml.Marshal(l.Example.ValueNode) + render, _ = utils.ConvertYAMLtoJSON(render) + l.Example.ValueNode.Value = string(render) + } + + if utils.IsNodeMap(r.Example.ValueNode) || utils.IsNodeArray(r.Example.ValueNode) { + render, _ := yaml.Marshal(r.Example.ValueNode) + render, _ = utils.ConvertYAMLtoJSON(render) + r.Example.ValueNode.Value = string(render) + } + + addPropertyCheck(&props, l.Example.ValueNode, r.Example.ValueNode, + l.Example.Value, r.Example.Value, &changes, v3.ExampleLabel, false) + } + + CheckProperties(props) + + // schema + if !l.Schema.IsEmpty() && !r.Schema.IsEmpty() { + mc.SchemaChanges = CompareSchemas(l.Schema.Value, r.Schema.Value) + } + if !l.Schema.IsEmpty() && r.Schema.IsEmpty() { + CreateChange(&changes, ObjectRemoved, v3.SchemaLabel, l.Schema.ValueNode, + nil, true, l.Schema.Value, nil) + } + if l.Schema.IsEmpty() && !r.Schema.IsEmpty() { + CreateChange(&changes, ObjectAdded, v3.SchemaLabel, nil, + r.Schema.ValueNode, true, nil, r.Schema.Value) + } + + // examples + mc.ExampleChanges = CheckMapForChanges(l.Examples.Value, r.Examples.Value, + &changes, v3.ExamplesLabel, CompareExamples) + + // encoding + mc.EncodingChanges = CheckMapForChanges(l.Encoding.Value, r.Encoding.Value, + &changes, v3.EncodingLabel, CompareEncoding) + + mc.ExtensionChanges = CompareExtensions(l.Extensions, r.Extensions) + mc.PropertyChanges = NewPropertyChanges(changes) + return mc +} diff --git a/vendor/github.com/pb33f/libopenapi/what-changed/model/oauth_flows.go b/vendor/github.com/pb33f/libopenapi/what-changed/model/oauth_flows.go new file mode 100644 index 0000000000..3045a3b466 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/what-changed/model/oauth_flows.go @@ -0,0 +1,257 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package model + +import ( + "github.com/pb33f/libopenapi/datamodel/low" + "github.com/pb33f/libopenapi/datamodel/low/v3" +) + +// OAuthFlowsChanges represents changes found between two OpenAPI OAuthFlows objects. +type OAuthFlowsChanges struct { + *PropertyChanges + ImplicitChanges *OAuthFlowChanges `json:"implicit,omitempty" yaml:"implicit,omitempty"` + PasswordChanges *OAuthFlowChanges `json:"password,omitempty" yaml:"password,omitempty"` + ClientCredentialsChanges *OAuthFlowChanges `json:"clientCredentials,omitempty" yaml:"clientCredentials,omitempty"` + AuthorizationCodeChanges *OAuthFlowChanges `json:"authCode,omitempty" yaml:"authCode,omitempty"` + ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"` +} + +// GetAllChanges returns a slice of all changes made between OAuthFlows objects +func (o *OAuthFlowsChanges) GetAllChanges() []*Change { + var changes []*Change + changes = append(changes, o.Changes...) + if o.ImplicitChanges != nil { + changes = append(changes, o.ImplicitChanges.GetAllChanges()...) + } + if o.PasswordChanges != nil { + changes = append(changes, o.PasswordChanges.GetAllChanges()...) + } + if o.ClientCredentialsChanges != nil { + changes = append(changes, o.ClientCredentialsChanges.GetAllChanges()...) + } + if o.AuthorizationCodeChanges != nil { + changes = append(changes, o.AuthorizationCodeChanges.GetAllChanges()...) + } + if o.ExtensionChanges != nil { + changes = append(changes, o.ImplicitChanges.GetAllChanges()...) + } + return changes +} + +// TotalChanges returns the number of changes made between two OAuthFlows instances. +func (o *OAuthFlowsChanges) TotalChanges() int { + c := o.PropertyChanges.TotalChanges() + if o.ImplicitChanges != nil { + c += o.ImplicitChanges.TotalChanges() + } + if o.PasswordChanges != nil { + c += o.PasswordChanges.TotalChanges() + } + if o.ClientCredentialsChanges != nil { + c += o.ClientCredentialsChanges.TotalChanges() + } + if o.AuthorizationCodeChanges != nil { + c += o.AuthorizationCodeChanges.TotalChanges() + } + if o.ExtensionChanges != nil { + c += o.ExtensionChanges.TotalChanges() + } + return c +} + +// TotalBreakingChanges returns the number of breaking changes made between two OAuthFlows objects. +func (o *OAuthFlowsChanges) TotalBreakingChanges() int { + c := o.PropertyChanges.TotalBreakingChanges() + if o.ImplicitChanges != nil { + c += o.ImplicitChanges.TotalBreakingChanges() + } + if o.PasswordChanges != nil { + c += o.PasswordChanges.TotalBreakingChanges() + } + if o.ClientCredentialsChanges != nil { + c += o.ClientCredentialsChanges.TotalBreakingChanges() + } + if o.AuthorizationCodeChanges != nil { + c += o.AuthorizationCodeChanges.TotalBreakingChanges() + } + return c +} + +// CompareOAuthFlows compares a left and right OAuthFlows object. If changes are found a pointer to *OAuthFlowsChanges +// is returned, otherwise nil is returned. +func CompareOAuthFlows(l, r *v3.OAuthFlows) *OAuthFlowsChanges { + if low.AreEqual(l, r) { + return nil + } + + oa := new(OAuthFlowsChanges) + var changes []*Change + + // client credentials + if !l.ClientCredentials.IsEmpty() && !r.ClientCredentials.IsEmpty() { + oa.ClientCredentialsChanges = CompareOAuthFlow(l.ClientCredentials.Value, r.ClientCredentials.Value) + } + if !l.ClientCredentials.IsEmpty() && r.ClientCredentials.IsEmpty() { + CreateChange(&changes, ObjectRemoved, v3.ClientCredentialsLabel, + l.ClientCredentials.ValueNode, nil, true, + l.ClientCredentials.Value, nil) + } + if l.ClientCredentials.IsEmpty() && !r.ClientCredentials.IsEmpty() { + CreateChange(&changes, ObjectAdded, v3.ClientCredentialsLabel, + nil, r.ClientCredentials.ValueNode, false, + nil, r.ClientCredentials.Value) + } + + // implicit + if !l.Implicit.IsEmpty() && !r.Implicit.IsEmpty() { + oa.ImplicitChanges = CompareOAuthFlow(l.Implicit.Value, r.Implicit.Value) + } + if !l.Implicit.IsEmpty() && r.Implicit.IsEmpty() { + CreateChange(&changes, ObjectRemoved, v3.ImplicitLabel, + l.Implicit.ValueNode, nil, true, + l.Implicit.Value, nil) + } + if l.Implicit.IsEmpty() && !r.Implicit.IsEmpty() { + CreateChange(&changes, ObjectAdded, v3.ImplicitLabel, + nil, r.Implicit.ValueNode, false, + nil, r.Implicit.Value) + } + + // password + if !l.Password.IsEmpty() && !r.Password.IsEmpty() { + oa.PasswordChanges = CompareOAuthFlow(l.Password.Value, r.Password.Value) + } + if !l.Password.IsEmpty() && r.Password.IsEmpty() { + CreateChange(&changes, ObjectRemoved, v3.PasswordLabel, + l.Password.ValueNode, nil, true, + l.Password.Value, nil) + } + if l.Password.IsEmpty() && !r.Password.IsEmpty() { + CreateChange(&changes, ObjectAdded, v3.PasswordLabel, + nil, r.Password.ValueNode, false, + nil, r.Password.Value) + } + + // auth code + if !l.AuthorizationCode.IsEmpty() && !r.AuthorizationCode.IsEmpty() { + oa.AuthorizationCodeChanges = CompareOAuthFlow(l.AuthorizationCode.Value, r.AuthorizationCode.Value) + } + if !l.AuthorizationCode.IsEmpty() && r.AuthorizationCode.IsEmpty() { + CreateChange(&changes, ObjectRemoved, v3.AuthorizationCodeLabel, + l.AuthorizationCode.ValueNode, nil, true, + l.AuthorizationCode.Value, nil) + } + if l.AuthorizationCode.IsEmpty() && !r.AuthorizationCode.IsEmpty() { + CreateChange(&changes, ObjectAdded, v3.AuthorizationCodeLabel, + nil, r.AuthorizationCode.ValueNode, false, + nil, r.AuthorizationCode.Value) + } + oa.ExtensionChanges = CompareExtensions(l.Extensions, r.Extensions) + oa.PropertyChanges = NewPropertyChanges(changes) + return oa +} + +// OAuthFlowChanges represents an OpenAPI OAuthFlow object. +type OAuthFlowChanges struct { + *PropertyChanges + ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"` +} + +// GetAllChanges returns a slice of all changes made between OAuthFlow objects +func (o *OAuthFlowChanges) GetAllChanges() []*Change { + var changes []*Change + changes = append(changes, o.Changes...) + if o.ExtensionChanges != nil { + changes = append(changes, o.ExtensionChanges.GetAllChanges()...) + } + return changes +} + +// TotalChanges returns the total number of changes made between two OAuthFlow objects +func (o *OAuthFlowChanges) TotalChanges() int { + c := o.PropertyChanges.TotalChanges() + if o.ExtensionChanges != nil { + c += o.ExtensionChanges.TotalChanges() + } + return c +} + +// TotalBreakingChanges returns the total number of breaking changes made between two OAuthFlow objects +func (o *OAuthFlowChanges) TotalBreakingChanges() int { + return o.PropertyChanges.TotalBreakingChanges() +} + +// CompareOAuthFlow checks a left and a right OAuthFlow object for changes. If found, returns a pointer to +// an OAuthFlowChanges instance, or nil if nothing is found. +func CompareOAuthFlow(l, r *v3.OAuthFlow) *OAuthFlowChanges { + if low.AreEqual(l, r) { + return nil + } + + var changes []*Change + var props []*PropertyCheck + + // authorization url + props = append(props, &PropertyCheck{ + LeftNode: l.AuthorizationUrl.ValueNode, + RightNode: r.AuthorizationUrl.ValueNode, + Label: v3.AuthorizationUrlLabel, + Changes: &changes, + Breaking: true, + Original: l, + New: r, + }) + + // token url + props = append(props, &PropertyCheck{ + LeftNode: l.TokenUrl.ValueNode, + RightNode: r.TokenUrl.ValueNode, + Label: v3.TokenUrlLabel, + Changes: &changes, + Breaking: true, + Original: l, + New: r, + }) + + // refresh url + props = append(props, &PropertyCheck{ + LeftNode: l.RefreshUrl.ValueNode, + RightNode: r.RefreshUrl.ValueNode, + Label: v3.RefreshUrlLabel, + Changes: &changes, + Breaking: true, + Original: l, + New: r, + }) + + CheckProperties(props) + + for v := range l.Scopes.Value { + if r != nil && r.FindScope(v.Value) == nil { + CreateChange(&changes, ObjectRemoved, v3.Scopes, + l.Scopes.Value[v].ValueNode, nil, true, + v.Value, nil) + continue + } + if r != nil && r.FindScope(v.Value) != nil { + if l.Scopes.Value[v].Value != r.FindScope(v.Value).Value { + CreateChange(&changes, Modified, v3.Scopes, + l.Scopes.Value[v].ValueNode, r.FindScope(v.Value).ValueNode, true, + l.Scopes.Value[v].Value, r.FindScope(v.Value).Value) + } + } + } + for v := range r.Scopes.Value { + if l != nil && l.FindScope(v.Value) == nil { + CreateChange(&changes, ObjectAdded, v3.Scopes, + nil, r.Scopes.Value[v].ValueNode, false, + nil, v.Value) + } + } + oa := new(OAuthFlowChanges) + oa.PropertyChanges = NewPropertyChanges(changes) + oa.ExtensionChanges = CompareExtensions(l.Extensions, r.Extensions) + return oa +} diff --git a/vendor/github.com/pb33f/libopenapi/what-changed/model/operation.go b/vendor/github.com/pb33f/libopenapi/what-changed/model/operation.go new file mode 100644 index 0000000000..db73e9ab04 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/what-changed/model/operation.go @@ -0,0 +1,561 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package model + +import ( + "reflect" + "sort" + "strings" + + "github.com/pb33f/libopenapi/datamodel/low" + "github.com/pb33f/libopenapi/datamodel/low/base" + v2 "github.com/pb33f/libopenapi/datamodel/low/v2" + v3 "github.com/pb33f/libopenapi/datamodel/low/v3" + "gopkg.in/yaml.v3" +) + +// OperationChanges represent changes made between two Swagger or OpenAPI Operation objects. +type OperationChanges struct { + *PropertyChanges + ExternalDocChanges *ExternalDocChanges `json:"externalDoc,omitempty" yaml:"externalDoc,omitempty"` + ParameterChanges []*ParameterChanges `json:"parameters,omitempty" yaml:"parameters,omitempty"` + ResponsesChanges *ResponsesChanges `json:"responses,omitempty" yaml:"responses,omitempty"` + SecurityRequirementChanges []*SecurityRequirementChanges `json:"securityRequirements,omitempty" yaml:"securityRequirements,omitempty"` + + // OpenAPI 3+ only changes + RequestBodyChanges *RequestBodyChanges `json:"requestBodies,omitempty" yaml:"requestBodies,omitempty"` + ServerChanges []*ServerChanges `json:"servers,omitempty" yaml:"servers,omitempty"` + ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"` + CallbackChanges map[string]*CallbackChanges `json:"callbacks,omitempty" yaml:"callbacks,omitempty"` +} + +// GetAllChanges returns a slice of all changes made between Operation objects +func (o *OperationChanges) GetAllChanges() []*Change { + var changes []*Change + changes = append(changes, o.Changes...) + if o.ExternalDocChanges != nil { + changes = append(changes, o.ExternalDocChanges.GetAllChanges()...) + } + for k := range o.ParameterChanges { + changes = append(changes, o.ParameterChanges[k].GetAllChanges()...) + } + if o.ResponsesChanges != nil { + changes = append(changes, o.ResponsesChanges.GetAllChanges()...) + } + for k := range o.SecurityRequirementChanges { + changes = append(changes, o.SecurityRequirementChanges[k].GetAllChanges()...) + } + if o.RequestBodyChanges != nil { + changes = append(changes, o.RequestBodyChanges.GetAllChanges()...) + } + for k := range o.ServerChanges { + changes = append(changes, o.ServerChanges[k].GetAllChanges()...) + } + for k := range o.CallbackChanges { + changes = append(changes, o.CallbackChanges[k].GetAllChanges()...) + } + if o.ExtensionChanges != nil { + changes = append(changes, o.ExtensionChanges.GetAllChanges()...) + } + return changes +} + +// TotalChanges returns the total number of changes made between two Swagger or OpenAPI Operation objects. +func (o *OperationChanges) TotalChanges() int { + c := o.PropertyChanges.TotalChanges() + if o.ExternalDocChanges != nil { + c += o.ExternalDocChanges.TotalChanges() + } + for k := range o.ParameterChanges { + c += o.ParameterChanges[k].TotalChanges() + } + if o.ResponsesChanges != nil { + c += o.ResponsesChanges.TotalChanges() + } + for k := range o.SecurityRequirementChanges { + c += o.SecurityRequirementChanges[k].TotalChanges() + } + if o.RequestBodyChanges != nil { + c += o.RequestBodyChanges.TotalChanges() + } + for k := range o.ServerChanges { + c += o.ServerChanges[k].TotalChanges() + } + for k := range o.CallbackChanges { + c += o.CallbackChanges[k].TotalChanges() + } + if o.ExtensionChanges != nil { + c += o.ExtensionChanges.TotalChanges() + } + return c +} + +// TotalBreakingChanges returns the total number of breaking changes made between two Swagger +// or OpenAPI Operation objects. +func (o *OperationChanges) TotalBreakingChanges() int { + c := o.PropertyChanges.TotalBreakingChanges() + if o.ExternalDocChanges != nil { + c += o.ExternalDocChanges.TotalBreakingChanges() + } + for k := range o.ParameterChanges { + c += o.ParameterChanges[k].TotalBreakingChanges() + } + if o.ResponsesChanges != nil { + c += o.ResponsesChanges.TotalBreakingChanges() + } + for k := range o.SecurityRequirementChanges { + c += o.SecurityRequirementChanges[k].TotalBreakingChanges() + } + for k := range o.CallbackChanges { + c += o.CallbackChanges[k].TotalBreakingChanges() + } + if o.RequestBodyChanges != nil { + c += o.RequestBodyChanges.TotalBreakingChanges() + } + for k := range o.ServerChanges { + c += o.ServerChanges[k].TotalBreakingChanges() + } + return c +} + +// check for properties shared between operations objects. +func addSharedOperationProperties(left, right low.SharedOperations, changes *[]*Change) []*PropertyCheck { + var props []*PropertyCheck + + // tags + if len(left.GetTags().Value) > 0 || len(right.GetTags().Value) > 0 { + ExtractStringValueSliceChanges(left.GetTags().Value, right.GetTags().Value, + changes, v3.TagsLabel, false) + } + + // summary + addPropertyCheck(&props, left.GetSummary().ValueNode, right.GetSummary().ValueNode, + left.GetSummary(), right.GetSummary(), changes, v3.SummaryLabel, false) + + // description + addPropertyCheck(&props, left.GetDescription().ValueNode, right.GetDescription().ValueNode, + left.GetDescription(), right.GetDescription(), changes, v3.DescriptionLabel, false) + + // deprecated + addPropertyCheck(&props, left.GetDeprecated().ValueNode, right.GetDeprecated().ValueNode, + left.GetDeprecated(), right.GetDeprecated(), changes, v3.DeprecatedLabel, false) + + // operation id + addPropertyCheck(&props, left.GetOperationId().ValueNode, right.GetOperationId().ValueNode, + left.GetOperationId(), right.GetOperationId(), changes, v3.OperationIdLabel, true) + + return props +} + +// check shared objects +func compareSharedOperationObjects(l, r low.SharedOperations, changes *[]*Change, opChanges *OperationChanges) { + + // external docs + if !l.GetExternalDocs().IsEmpty() && !r.GetExternalDocs().IsEmpty() { + lExtDoc := l.GetExternalDocs().Value.(*base.ExternalDoc) + rExtDoc := r.GetExternalDocs().Value.(*base.ExternalDoc) + if !low.AreEqual(lExtDoc, rExtDoc) { + opChanges.ExternalDocChanges = CompareExternalDocs(lExtDoc, rExtDoc) + } + } + if l.GetExternalDocs().IsEmpty() && !r.GetExternalDocs().IsEmpty() { + CreateChange(changes, PropertyAdded, v3.ExternalDocsLabel, + nil, r.GetExternalDocs().ValueNode, false, nil, + r.GetExternalDocs().Value) + } + if !l.GetExternalDocs().IsEmpty() && r.GetExternalDocs().IsEmpty() { + CreateChange(changes, PropertyRemoved, v3.ExternalDocsLabel, + l.GetExternalDocs().ValueNode, nil, false, l.GetExternalDocs().Value, + nil) + } + + // responses + if !l.GetResponses().IsEmpty() && !r.GetResponses().IsEmpty() { + opChanges.ResponsesChanges = CompareResponses(l.GetResponses().Value, r.GetResponses().Value) + } + if l.GetResponses().IsEmpty() && !r.GetResponses().IsEmpty() { + CreateChange(changes, PropertyAdded, v3.ResponsesLabel, + nil, r.GetResponses().ValueNode, false, nil, + r.GetResponses().Value) + } + if !l.GetResponses().IsEmpty() && r.GetResponses().IsEmpty() { + CreateChange(changes, PropertyRemoved, v3.ResponsesLabel, + l.GetResponses().ValueNode, nil, true, l.GetResponses().Value, + nil) + } + +} + +// CompareOperations compares a left and right Swagger or OpenAPI Operation object. If changes are found, returns +// a pointer to an OperationChanges instance, or nil if nothing is found. +func CompareOperations(l, r any) *OperationChanges { + + var changes []*Change + var props []*PropertyCheck + + oc := new(OperationChanges) + + // Swagger + if reflect.TypeOf(&v2.Operation{}) == reflect.TypeOf(l) && + reflect.TypeOf(&v2.Operation{}) == reflect.TypeOf(r) { + + lOperation := l.(*v2.Operation) + rOperation := r.(*v2.Operation) + + // perform hash check to avoid further processing + if low.AreEqual(lOperation, rOperation) { + return nil + } + + props = append(props, addSharedOperationProperties(lOperation, rOperation, &changes)...) + + compareSharedOperationObjects(lOperation, rOperation, &changes, oc) + + // parameters + lParamsUntyped := lOperation.GetParameters() + rParamsUntyped := rOperation.GetParameters() + if !lParamsUntyped.IsEmpty() && !rParamsUntyped.IsEmpty() { + lParams := lParamsUntyped.Value.([]low.ValueReference[*v2.Parameter]) + rParams := rParamsUntyped.Value.([]low.ValueReference[*v2.Parameter]) + + lv := make(map[string]*v2.Parameter, len(lParams)) + rv := make(map[string]*v2.Parameter, len(rParams)) + + for i := range lParams { + s := lParams[i].Value.Name.Value + lv[s] = lParams[i].Value + } + for i := range rParams { + s := rParams[i].Value.Name.Value + rv[s] = rParams[i].Value + } + + var paramChanges []*ParameterChanges + for n := range lv { + if _, ok := rv[n]; ok { + if !low.AreEqual(lv[n], rv[n]) { + ch := CompareParameters(lv[n], rv[n]) + if ch != nil { + paramChanges = append(paramChanges, ch) + } + } + continue + } + CreateChange(&changes, ObjectRemoved, v3.ParametersLabel, + lv[n].Name.ValueNode, nil, true, lv[n].Name.Value, + nil) + + } + for n := range rv { + if _, ok := lv[n]; !ok { + CreateChange(&changes, ObjectAdded, v3.ParametersLabel, + nil, rv[n].Name.ValueNode, true, nil, + rv[n].Name.Value) + } + } + oc.ParameterChanges = paramChanges + } + if !lParamsUntyped.IsEmpty() && rParamsUntyped.IsEmpty() { + CreateChange(&changes, PropertyRemoved, v3.ParametersLabel, + lParamsUntyped.ValueNode, nil, true, lParamsUntyped.Value, + nil) + } + if lParamsUntyped.IsEmpty() && !rParamsUntyped.IsEmpty() { + CreateChange(&changes, PropertyAdded, v3.ParametersLabel, + nil, rParamsUntyped.ValueNode, true, nil, + rParamsUntyped.Value) + } + + // security + if !lOperation.Security.IsEmpty() || !rOperation.Security.IsEmpty() { + checkSecurity(lOperation.Security, rOperation.Security, &changes, oc) + } + + // produces + if len(lOperation.Produces.Value) > 0 || len(rOperation.Produces.Value) > 0 { + ExtractStringValueSliceChanges(lOperation.Produces.Value, rOperation.Produces.Value, + &changes, v3.ProducesLabel, true) + } + + // consumes + if len(lOperation.Consumes.Value) > 0 || len(rOperation.Consumes.Value) > 0 { + ExtractStringValueSliceChanges(lOperation.Consumes.Value, rOperation.Consumes.Value, + &changes, v3.ConsumesLabel, true) + } + + // schemes + if len(lOperation.Schemes.Value) > 0 || len(rOperation.Schemes.Value) > 0 { + ExtractStringValueSliceChanges(lOperation.Schemes.Value, rOperation.Schemes.Value, + &changes, v3.SchemesLabel, true) + } + + oc.ExtensionChanges = CompareExtensions(lOperation.Extensions, rOperation.Extensions) + } + + // OpenAPI + if reflect.TypeOf(&v3.Operation{}) == reflect.TypeOf(l) && + reflect.TypeOf(&v3.Operation{}) == reflect.TypeOf(r) { + + lOperation := l.(*v3.Operation) + rOperation := r.(*v3.Operation) + + // perform hash check to avoid further processing + if low.AreEqual(lOperation, rOperation) { + return nil + } + + props = append(props, addSharedOperationProperties(lOperation, rOperation, &changes)...) + compareSharedOperationObjects(lOperation, rOperation, &changes, oc) + + // parameters + lParamsUntyped := lOperation.GetParameters() + rParamsUntyped := rOperation.GetParameters() + if !lParamsUntyped.IsEmpty() && !rParamsUntyped.IsEmpty() { + lParams := lParamsUntyped.Value.([]low.ValueReference[*v3.Parameter]) + rParams := rParamsUntyped.Value.([]low.ValueReference[*v3.Parameter]) + + lv := make(map[string]*v3.Parameter, len(lParams)) + rv := make(map[string]*v3.Parameter, len(rParams)) + + for i := range lParams { + s := lParams[i].Value.Name.Value + lv[s] = lParams[i].Value + } + for i := range rParams { + s := rParams[i].Value.Name.Value + rv[s] = rParams[i].Value + } + + var paramChanges []*ParameterChanges + for n := range lv { + if _, ok := rv[n]; ok { + if !low.AreEqual(lv[n], rv[n]) { + ch := CompareParameters(lv[n], rv[n]) + if ch != nil { + paramChanges = append(paramChanges, ch) + } + } + continue + } + CreateChange(&changes, ObjectRemoved, v3.ParametersLabel, + lv[n].Name.ValueNode, nil, true, lv[n].Name.Value, + nil) + + } + for n := range rv { + if _, ok := lv[n]; !ok { + CreateChange(&changes, ObjectAdded, v3.ParametersLabel, + nil, rv[n].Name.ValueNode, true, nil, + rv[n].Name.Value) + } + } + oc.ParameterChanges = paramChanges + } + if !lParamsUntyped.IsEmpty() && rParamsUntyped.IsEmpty() { + CreateChange(&changes, PropertyRemoved, v3.ParametersLabel, + lParamsUntyped.ValueNode, nil, true, lParamsUntyped.Value, + nil) + } + if lParamsUntyped.IsEmpty() && !rParamsUntyped.IsEmpty() { + CreateChange(&changes, PropertyAdded, v3.ParametersLabel, + nil, rParamsUntyped.ValueNode, true, nil, + rParamsUntyped.Value) + } + + // security + if !lOperation.Security.IsEmpty() || !rOperation.Security.IsEmpty() { + checkSecurity(lOperation.Security, rOperation.Security, &changes, oc) + } + + // request body + if !lOperation.RequestBody.IsEmpty() && !rOperation.RequestBody.IsEmpty() { + if !low.AreEqual(lOperation.RequestBody.Value, rOperation.RequestBody.Value) { + oc.RequestBodyChanges = CompareRequestBodies(lOperation.RequestBody.Value, rOperation.RequestBody.Value) + } + } + if !lOperation.RequestBody.IsEmpty() && rOperation.RequestBody.IsEmpty() { + CreateChange(&changes, PropertyRemoved, v3.RequestBodyLabel, + lOperation.RequestBody.ValueNode, nil, true, lOperation.RequestBody.Value, + nil) + } + if lOperation.RequestBody.IsEmpty() && !rOperation.RequestBody.IsEmpty() { + CreateChange(&changes, PropertyAdded, v3.RequestBodyLabel, + nil, rOperation.RequestBody.ValueNode, true, nil, + rOperation.RequestBody.Value) + } + + // callbacks + if !lOperation.GetCallbacks().IsEmpty() && !rOperation.GetCallbacks().IsEmpty() { + oc.CallbackChanges = CheckMapForChanges(lOperation.Callbacks.Value, rOperation.Callbacks.Value, &changes, + v3.CallbacksLabel, CompareCallback) + } + if !lOperation.GetCallbacks().IsEmpty() && rOperation.GetCallbacks().IsEmpty() { + CreateChange(&changes, PropertyRemoved, v3.CallbacksLabel, + lOperation.Callbacks.ValueNode, nil, true, lOperation.Callbacks.Value, + nil) + } + if lOperation.Callbacks.IsEmpty() && !rOperation.Callbacks.IsEmpty() { + CreateChange(&changes, PropertyAdded, v3.CallbacksLabel, + nil, rOperation.Callbacks.ValueNode, false, nil, + rOperation.Callbacks.Value) + } + + // servers + oc.ServerChanges = checkServers(lOperation.Servers, rOperation.Servers) + oc.ExtensionChanges = CompareExtensions(lOperation.Extensions, rOperation.Extensions) + + // todo: callbacks + } + CheckProperties(props) + oc.PropertyChanges = NewPropertyChanges(changes) + return oc +} + +// check servers property +func checkServers(lServers, rServers low.NodeReference[[]low.ValueReference[*v3.Server]]) []*ServerChanges { + + var serverChanges []*ServerChanges + + if !lServers.IsEmpty() && !rServers.IsEmpty() { + + lv := make(map[string]low.ValueReference[*v3.Server], len(lServers.Value)) + rv := make(map[string]low.ValueReference[*v3.Server], len(rServers.Value)) + + for i := range lServers.Value { + var s string + if !lServers.Value[i].Value.URL.IsEmpty() { + s = lServers.Value[i].Value.URL.Value + } else { + s = low.GenerateHashString(lServers.Value[i].Value) + } + lv[s] = lServers.Value[i] + } + for i := range rServers.Value { + var s string + if !rServers.Value[i].Value.URL.IsEmpty() { + s = rServers.Value[i].Value.URL.Value + } else { + s = low.GenerateHashString(rServers.Value[i].Value) + } + rv[s] = rServers.Value[i] + } + + for k := range lv { + + var changes []*Change + + if _, ok := rv[k]; ok { + if !low.AreEqual(lv[k].Value, rv[k].Value) { + serverChanges = append(serverChanges, CompareServers(lv[k].Value, rv[k].Value)) + } + continue + } + lv[k].ValueNode.Value = lv[k].Value.URL.Value + CreateChange(&changes, ObjectRemoved, v3.ServersLabel, + lv[k].ValueNode, nil, true, lv[k].Value.URL.Value, + nil) + sc := new(ServerChanges) + sc.PropertyChanges = NewPropertyChanges(changes) + serverChanges = append(serverChanges, sc) + + } + + for k := range rv { + + if _, ok := lv[k]; !ok { + + var changes []*Change + rv[k].ValueNode.Value = rv[k].Value.URL.Value + CreateChange(&changes, ObjectAdded, v3.ServersLabel, + nil, rv[k].ValueNode, false, nil, + rv[k].Value.URL.Value) + + sc := new(ServerChanges) + sc.PropertyChanges = NewPropertyChanges(changes) + serverChanges = append(serverChanges, sc) + } + + } + } + var changes []*Change + sc := new(ServerChanges) + if !lServers.IsEmpty() && rServers.IsEmpty() { + CreateChange(&changes, PropertyRemoved, v3.ServersLabel, + lServers.ValueNode, nil, true, lServers.Value, + nil) + } + if lServers.IsEmpty() && !rServers.IsEmpty() { + CreateChange(&changes, PropertyAdded, v3.ServersLabel, + nil, rServers.ValueNode, false, nil, + rServers.Value) + } + sc.PropertyChanges = NewPropertyChanges(changes) + if len(changes) > 0 { + serverChanges = append(serverChanges, sc) + } + if len(serverChanges) <= 0 { + return nil + } + return serverChanges +} + +// check security property. +func checkSecurity(lSecurity, rSecurity low.NodeReference[[]low.ValueReference[*base.SecurityRequirement]], + changes *[]*Change, oc any) { + + lv := make(map[string]*base.SecurityRequirement, len(lSecurity.Value)) + rv := make(map[string]*base.SecurityRequirement, len(rSecurity.Value)) + lvn := make(map[string]*yaml.Node, len(lSecurity.Value)) + rvn := make(map[string]*yaml.Node, len(rSecurity.Value)) + + for i := range lSecurity.Value { + keys := lSecurity.Value[i].Value.GetKeys() + sort.Strings(keys) + s := strings.Join(keys, "|") + lv[s] = lSecurity.Value[i].Value + lvn[s] = lSecurity.Value[i].ValueNode + + } + for i := range rSecurity.Value { + keys := rSecurity.Value[i].Value.GetKeys() + sort.Strings(keys) + s := strings.Join(keys, "|") + rv[s] = rSecurity.Value[i].Value + rvn[s] = rSecurity.Value[i].ValueNode + } + + var secChanges []*SecurityRequirementChanges + for n := range lv { + if _, ok := rv[n]; ok { + if !low.AreEqual(lv[n], rv[n]) { + ch := CompareSecurityRequirement(lv[n], rv[n]) + if ch != nil { + secChanges = append(secChanges, ch) + } + } + continue + } + lvn[n].Value = strings.Join(lv[n].GetKeys(), ", ") + CreateChange(changes, ObjectRemoved, v3.SecurityLabel, + lvn[n], nil, true, lv[n], + nil) + + } + for n := range rv { + if _, ok := lv[n]; !ok { + rvn[n].Value = strings.Join(rv[n].GetKeys(), ", ") + CreateChange(changes, ObjectAdded, v3.SecurityLabel, + nil, rvn[n], false, nil, + rv[n]) + } + } + + // handle different change types. + if reflect.TypeOf(&OperationChanges{}) == reflect.TypeOf(oc) { + oc.(*OperationChanges).SecurityRequirementChanges = secChanges + } + if reflect.TypeOf(&DocumentChanges{}) == reflect.TypeOf(oc) { + oc.(*DocumentChanges).SecurityRequirementChanges = secChanges + } +} diff --git a/vendor/github.com/pb33f/libopenapi/what-changed/model/parameter.go b/vendor/github.com/pb33f/libopenapi/what-changed/model/parameter.go new file mode 100644 index 0000000000..b926884e10 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/what-changed/model/parameter.go @@ -0,0 +1,354 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package model + +import ( + "github.com/pb33f/libopenapi/datamodel/low" + "github.com/pb33f/libopenapi/datamodel/low/base" + v2 "github.com/pb33f/libopenapi/datamodel/low/v2" + v3 "github.com/pb33f/libopenapi/datamodel/low/v3" + "gopkg.in/yaml.v3" + "reflect" +) + +// ParameterChanges represents changes found between Swagger or OpenAPI Parameter objects. +type ParameterChanges struct { + *PropertyChanges + SchemaChanges *SchemaChanges `json:"schemas,omitempty" yaml:"schemas,omitempty"` + ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"` + + // Swagger supports Items. + ItemsChanges *ItemsChanges `json:"items,omitempty" yaml:"items,omitempty"` + + // OpenAPI supports examples and content types. + ExamplesChanges map[string]*ExampleChanges `json:"examples,omitempty" yaml:"examples,omitempty"` + ContentChanges map[string]*MediaTypeChanges `json:"content,omitempty" yaml:"content,omitempty"` +} + +// GetAllChanges returns a slice of all changes made between Parameter objects +func (p *ParameterChanges) GetAllChanges() []*Change { + var changes []*Change + changes = append(changes, p.Changes...) + if p.SchemaChanges != nil { + changes = append(changes, p.SchemaChanges.GetAllChanges()...) + } + for i := range p.ExamplesChanges { + changes = append(changes, p.ExamplesChanges[i].GetAllChanges()...) + } + if p.ItemsChanges != nil { + changes = append(changes, p.ItemsChanges.GetAllChanges()...) + } + if p.ExtensionChanges != nil { + changes = append(changes, p.ExtensionChanges.GetAllChanges()...) + } + for i := range p.ContentChanges { + changes = append(changes, p.ContentChanges[i].GetAllChanges()...) + } + return changes +} + +// TotalChanges returns a count of everything that changed +func (p *ParameterChanges) TotalChanges() int { + c := p.PropertyChanges.TotalChanges() + if p.SchemaChanges != nil { + c += p.SchemaChanges.TotalChanges() + } + for i := range p.ExamplesChanges { + c += p.ExamplesChanges[i].TotalChanges() + } + if p.ItemsChanges != nil { + c += p.ItemsChanges.TotalChanges() + } + if p.ExtensionChanges != nil { + c += p.ExtensionChanges.TotalChanges() + } + for i := range p.ContentChanges { + c += p.ContentChanges[i].TotalChanges() + } + return c +} + +// TotalBreakingChanges always returns 0 for ExternalDoc objects, they are non-binding. +func (p *ParameterChanges) TotalBreakingChanges() int { + c := p.PropertyChanges.TotalBreakingChanges() + if p.SchemaChanges != nil { + c += p.SchemaChanges.TotalBreakingChanges() + } + if p.ItemsChanges != nil { + c += p.ItemsChanges.TotalBreakingChanges() + } + for i := range p.ContentChanges { + c += p.ContentChanges[i].TotalBreakingChanges() + } + return c +} + +func addPropertyCheck(props *[]*PropertyCheck, + lvn, rvn *yaml.Node, lv, rv any, changes *[]*Change, label string, breaking bool) { + *props = append(*props, &PropertyCheck{ + LeftNode: lvn, + RightNode: rvn, + Label: label, + Changes: changes, + Breaking: breaking, + Original: lv, + New: rv, + }) +} + +func addOpenAPIParameterProperties(left, right low.OpenAPIParameter, changes *[]*Change) []*PropertyCheck { + var props []*PropertyCheck + + // style + addPropertyCheck(&props, left.GetStyle().ValueNode, right.GetStyle().ValueNode, + left.GetStyle(), right.GetStyle(), changes, v3.StyleLabel, false) + + // allow reserved + addPropertyCheck(&props, left.GetAllowReserved().ValueNode, right.GetAllowReserved().ValueNode, + left.GetAllowReserved(), right.GetAllowReserved(), changes, v3.AllowReservedLabel, true) + + // explode + addPropertyCheck(&props, left.GetExplode().ValueNode, right.GetExplode().ValueNode, + left.GetExplode(), right.GetExplode(), changes, v3.ExplodeLabel, false) + + // deprecated + addPropertyCheck(&props, left.GetDeprecated().ValueNode, right.GetDeprecated().ValueNode, + left.GetDeprecated(), right.GetDeprecated(), changes, v3.DeprecatedLabel, false) + + // example + addPropertyCheck(&props, left.GetExample().ValueNode, right.GetExample().ValueNode, + left.GetExample(), right.GetExample(), changes, v3.ExampleLabel, false) + + return props +} + +func addSwaggerParameterProperties(left, right low.SwaggerParameter, changes *[]*Change) []*PropertyCheck { + var props []*PropertyCheck + + // type + addPropertyCheck(&props, left.GetType().ValueNode, right.GetType().ValueNode, + left.GetType(), right.GetType(), changes, v3.TypeLabel, true) + + // format + addPropertyCheck(&props, left.GetFormat().ValueNode, right.GetFormat().ValueNode, + left.GetFormat(), right.GetFormat(), changes, v3.FormatLabel, true) + + // collection format + addPropertyCheck(&props, left.GetCollectionFormat().ValueNode, right.GetCollectionFormat().ValueNode, + left.GetCollectionFormat(), right.GetCollectionFormat(), changes, v3.CollectionFormatLabel, true) + + // maximum + addPropertyCheck(&props, left.GetMaximum().ValueNode, right.GetMaximum().ValueNode, + left.GetMaximum(), right.GetMaximum(), changes, v3.MaximumLabel, true) + + // minimum + addPropertyCheck(&props, left.GetMinimum().ValueNode, right.GetMinimum().ValueNode, + left.GetMinimum(), right.GetMinimum(), changes, v3.MinimumLabel, true) + + // exclusive maximum + addPropertyCheck(&props, left.GetExclusiveMaximum().ValueNode, right.GetExclusiveMaximum().ValueNode, + left.GetExclusiveMaximum(), right.GetExclusiveMaximum(), changes, v3.ExclusiveMaximumLabel, true) + + // exclusive minimum + addPropertyCheck(&props, left.GetExclusiveMinimum().ValueNode, right.GetExclusiveMinimum().ValueNode, + left.GetExclusiveMinimum(), right.GetExclusiveMinimum(), changes, v3.ExclusiveMinimumLabel, true) + + // max length + addPropertyCheck(&props, left.GetMaxLength().ValueNode, right.GetMaxLength().ValueNode, + left.GetMaxLength(), right.GetMaxLength(), changes, v3.MaxLengthLabel, true) + + // min length + addPropertyCheck(&props, left.GetMinLength().ValueNode, right.GetMinLength().ValueNode, + left.GetMinLength(), right.GetMinLength(), changes, v3.MinLengthLabel, true) + + // pattern + addPropertyCheck(&props, left.GetPattern().ValueNode, right.GetPattern().ValueNode, + left.GetPattern(), right.GetPattern(), changes, v3.PatternLabel, true) + + // max items + addPropertyCheck(&props, left.GetMaxItems().ValueNode, right.GetMaxItems().ValueNode, + left.GetMaxItems(), right.GetMaxItems(), changes, v3.MaxItemsLabel, true) + + // min items + addPropertyCheck(&props, left.GetMinItems().ValueNode, right.GetMinItems().ValueNode, + left.GetMinItems(), right.GetMinItems(), changes, v3.MinItemsLabel, true) + + // unique items + addPropertyCheck(&props, left.GetUniqueItems().ValueNode, right.GetUniqueItems().ValueNode, + left.GetUniqueItems(), right.GetUniqueItems(), changes, v3.UniqueItemsLabel, true) + + // default + addPropertyCheck(&props, left.GetDefault().ValueNode, right.GetDefault().ValueNode, + left.GetDefault(), right.GetDefault(), changes, v3.DefaultLabel, true) + + // multiple of + addPropertyCheck(&props, left.GetMultipleOf().ValueNode, right.GetMultipleOf().ValueNode, + left.GetMultipleOf(), right.GetMultipleOf(), changes, v3.MultipleOfLabel, true) + + return props +} + +func addCommonParameterProperties(left, right low.SharedParameters, changes *[]*Change) []*PropertyCheck { + var props []*PropertyCheck + + addPropertyCheck(&props, left.GetName().ValueNode, right.GetName().ValueNode, + left.GetName(), right.GetName(), changes, v3.NameLabel, true) + + // in + addPropertyCheck(&props, left.GetIn().ValueNode, right.GetIn().ValueNode, + left.GetIn(), right.GetIn(), changes, v3.InLabel, true) + + // description + addPropertyCheck(&props, left.GetDescription().ValueNode, right.GetDescription().ValueNode, + left.GetDescription(), right.GetDescription(), changes, v3.DescriptionLabel, false) + + // required + addPropertyCheck(&props, left.GetRequired().ValueNode, right.GetRequired().ValueNode, + left.GetRequired(), right.GetRequired(), changes, v3.RequiredLabel, true) + + // allow empty value + addPropertyCheck(&props, left.GetAllowEmptyValue().ValueNode, right.GetAllowEmptyValue().ValueNode, + left.GetAllowEmptyValue(), right.GetAllowEmptyValue(), changes, v3.AllowEmptyValueLabel, true) + + return props +} + +// CompareParametersV3 is an OpenAPI type safe proxy for CompareParameters +func CompareParametersV3(l, r *v3.Parameter) *ParameterChanges { + return CompareParameters(l, r) +} + +// CompareParameters compares a left and right Swagger or OpenAPI Parameter object for any changes. If found returns +// a pointer to ParameterChanges. If nothing is found, returns nil. +func CompareParameters(l, r any) *ParameterChanges { + + var changes []*Change + var props []*PropertyCheck + + pc := new(ParameterChanges) + var lSchema *base.SchemaProxy + var rSchema *base.SchemaProxy + var lext, rext map[low.KeyReference[string]]low.ValueReference[any] + + if reflect.TypeOf(&v2.Parameter{}) == reflect.TypeOf(l) && reflect.TypeOf(&v2.Parameter{}) == reflect.TypeOf(r) { + lParam := l.(*v2.Parameter) + rParam := r.(*v2.Parameter) + + // perform hash check to avoid further processing + if low.AreEqual(lParam, rParam) { + return nil + } + + props = append(props, addSwaggerParameterProperties(lParam, rParam, &changes)...) + props = append(props, addCommonParameterProperties(lParam, rParam, &changes)...) + + // extract schema + if lParam != nil { + lSchema = lParam.Schema.Value + lext = lParam.Extensions + } + if rParam != nil { + rext = rParam.Extensions + rSchema = rParam.Schema.Value + } + + // items + if !lParam.Items.IsEmpty() && !rParam.Items.IsEmpty() { + if lParam.Items.Value.Hash() != rParam.Items.Value.Hash() { + pc.ItemsChanges = CompareItems(lParam.Items.Value, rParam.Items.Value) + } + } + if lParam.Items.IsEmpty() && !rParam.Items.IsEmpty() { + CreateChange(&changes, ObjectAdded, v3.ItemsLabel, + nil, rParam.Items.ValueNode, true, nil, + rParam.Items.Value) + } + if !lParam.Items.IsEmpty() && rParam.Items.IsEmpty() { + CreateChange(&changes, ObjectRemoved, v3.ItemsLabel, + lParam.Items.ValueNode, nil, true, lParam.Items.Value, + nil) + } + + // enum + if len(lParam.Enum.Value) > 0 || len(rParam.Enum.Value) > 0 { + ExtractRawValueSliceChanges(lParam.Enum.Value, rParam.Enum.Value, &changes, v3.EnumLabel, true) + } + } + + // OpenAPI + if reflect.TypeOf(&v3.Parameter{}) == reflect.TypeOf(l) && reflect.TypeOf(&v3.Parameter{}) == reflect.TypeOf(r) { + + lParam := l.(*v3.Parameter) + rParam := r.(*v3.Parameter) + + // perform hash check to avoid further processing + if low.AreEqual(lParam, rParam) { + return nil + } + + props = append(props, addOpenAPIParameterProperties(lParam, rParam, &changes)...) + props = append(props, addCommonParameterProperties(lParam, rParam, &changes)...) + if lParam != nil { + lext = lParam.Extensions + lSchema = lParam.Schema.Value + } + if rParam != nil { + rext = rParam.Extensions + rSchema = rParam.Schema.Value + } + + // example + checkParameterExample(lParam.Example, rParam.Example, changes) + + // examples + pc.ExamplesChanges = CheckMapForChanges(lParam.Examples.Value, rParam.Examples.Value, + &changes, v3.ExamplesLabel, CompareExamples) + + // content + pc.ContentChanges = CheckMapForChanges(lParam.Content.Value, rParam.Content.Value, + &changes, v3.ContentLabel, CompareMediaTypes) + } + CheckProperties(props) + + if lSchema != nil && rSchema != nil { + pc.SchemaChanges = CompareSchemas(lSchema, rSchema) + } + if lSchema != nil && rSchema == nil { + CreateChange(&changes, ObjectRemoved, v3.SchemaLabel, + lSchema.GetValueNode(), nil, true, lSchema, + nil) + } + + if lSchema == nil && rSchema != nil { + CreateChange(&changes, ObjectAdded, v3.SchemaLabel, + nil, rSchema.GetValueNode(), true, nil, + rSchema) + } + + pc.PropertyChanges = NewPropertyChanges(changes) + pc.ExtensionChanges = CompareExtensions(lext, rext) + return pc +} + +func checkParameterExample(expLeft, expRight low.NodeReference[any], changes []*Change) { + if !expLeft.IsEmpty() && !expRight.IsEmpty() { + if low.GenerateHashString(expLeft.GetValue()) != low.GenerateHashString(expRight.GetValue()) { + CreateChange(&changes, Modified, v3.ExampleLabel, + expLeft.GetValueNode(), expRight.GetValueNode(), false, + expLeft.GetValue(), expRight.GetValue()) + } + } + if expLeft.Value == nil && expRight.Value != nil { + CreateChange(&changes, PropertyAdded, v3.ExampleLabel, + nil, expRight.GetValueNode(), false, + nil, expRight.GetValue()) + + } + if expLeft.Value != nil && expRight.Value == nil { + CreateChange(&changes, PropertyRemoved, v3.ExampleLabel, + expLeft.GetValueNode(), nil, false, + expLeft.GetValue(), nil) + + } +} diff --git a/vendor/github.com/pb33f/libopenapi/what-changed/model/path_item.go b/vendor/github.com/pb33f/libopenapi/what-changed/model/path_item.go new file mode 100644 index 0000000000..06dd3d496f --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/what-changed/model/path_item.go @@ -0,0 +1,639 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package model + +import ( + "reflect" + + "github.com/pb33f/libopenapi/datamodel/low" + v2 "github.com/pb33f/libopenapi/datamodel/low/v2" + v3 "github.com/pb33f/libopenapi/datamodel/low/v3" +) + +// PathItemChanges represents changes found between to Swagger or OpenAPI PathItem object. +type PathItemChanges struct { + *PropertyChanges + GetChanges *OperationChanges `json:"get,omitempty" yaml:"get,omitempty"` + PutChanges *OperationChanges `json:"put,omitempty" yaml:"put,omitempty"` + PostChanges *OperationChanges `json:"post,omitempty" yaml:"post,omitempty"` + DeleteChanges *OperationChanges `json:"delete,omitempty" yaml:"delete,omitempty"` + OptionsChanges *OperationChanges `json:"options,omitempty" yaml:"options,omitempty"` + HeadChanges *OperationChanges `json:"head,omitempty" yaml:"head,omitempty"` + PatchChanges *OperationChanges `json:"patch,omitempty" yaml:"patch,omitempty"` + TraceChanges *OperationChanges `json:"trace,omitempty" yaml:"trace,omitempty"` + ServerChanges []*ServerChanges `json:"servers,omitempty" yaml:"servers,omitempty"` + ParameterChanges []*ParameterChanges `json:"parameters,omitempty" yaml:"parameters,omitempty"` + ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"` +} + +// GetAllChanges returns a slice of all changes made between PathItem objects +func (p *PathItemChanges) GetAllChanges() []*Change { + var changes []*Change + changes = append(changes, p.Changes...) + if p.GetChanges != nil { + changes = append(changes, p.GetChanges.GetAllChanges()...) + } + if p.PutChanges != nil { + changes = append(changes, p.PutChanges.GetAllChanges()...) + } + if p.PostChanges != nil { + changes = append(changes, p.PostChanges.GetAllChanges()...) + } + if p.DeleteChanges != nil { + changes = append(changes, p.DeleteChanges.GetAllChanges()...) + } + if p.OptionsChanges != nil { + changes = append(changes, p.OptionsChanges.GetAllChanges()...) + } + if p.HeadChanges != nil { + changes = append(changes, p.HeadChanges.GetAllChanges()...) + } + if p.PatchChanges != nil { + changes = append(changes, p.PatchChanges.GetAllChanges()...) + } + if p.TraceChanges != nil { + changes = append(changes, p.TraceChanges.GetAllChanges()...) + } + for i := range p.ServerChanges { + changes = append(changes, p.ServerChanges[i].GetAllChanges()...) + } + for i := range p.ParameterChanges { + changes = append(changes, p.ParameterChanges[i].GetAllChanges()...) + } + if p.ExtensionChanges != nil { + changes = append(changes, p.ExtensionChanges.GetAllChanges()...) + } + return changes +} + +// TotalChanges returns the total number of changes found between two Swagger or OpenAPI PathItems +func (p *PathItemChanges) TotalChanges() int { + c := p.PropertyChanges.TotalChanges() + if p.GetChanges != nil { + c += p.GetChanges.TotalChanges() + } + if p.PutChanges != nil { + c += p.PutChanges.TotalChanges() + } + if p.PostChanges != nil { + c += p.PostChanges.TotalChanges() + } + if p.DeleteChanges != nil { + c += p.DeleteChanges.TotalChanges() + } + if p.OptionsChanges != nil { + c += p.OptionsChanges.TotalChanges() + } + if p.HeadChanges != nil { + c += p.HeadChanges.TotalChanges() + } + if p.PatchChanges != nil { + c += p.PatchChanges.TotalChanges() + } + if p.TraceChanges != nil { + c += p.TraceChanges.TotalChanges() + } + for i := range p.ServerChanges { + c += p.ServerChanges[i].TotalChanges() + } + for i := range p.ParameterChanges { + c += p.ParameterChanges[i].TotalChanges() + } + if p.ExtensionChanges != nil { + c += p.ExtensionChanges.TotalChanges() + } + return c +} + +// TotalBreakingChanges returns the total number of breaking changes found between two Swagger or OpenAPI PathItems +func (p *PathItemChanges) TotalBreakingChanges() int { + c := p.PropertyChanges.TotalBreakingChanges() + if p.GetChanges != nil { + c += p.GetChanges.TotalBreakingChanges() + } + if p.PutChanges != nil { + c += p.PutChanges.TotalBreakingChanges() + } + if p.PostChanges != nil { + c += p.PostChanges.TotalBreakingChanges() + } + if p.DeleteChanges != nil { + c += p.DeleteChanges.TotalBreakingChanges() + } + if p.OptionsChanges != nil { + c += p.OptionsChanges.TotalBreakingChanges() + } + if p.HeadChanges != nil { + c += p.HeadChanges.TotalBreakingChanges() + } + if p.PatchChanges != nil { + c += p.PatchChanges.TotalBreakingChanges() + } + if p.TraceChanges != nil { + c += p.TraceChanges.TotalBreakingChanges() + } + for i := range p.ServerChanges { + c += p.ServerChanges[i].TotalBreakingChanges() + } + for i := range p.ParameterChanges { + c += p.ParameterChanges[i].TotalBreakingChanges() + } + return c +} + +type opCheck struct { + label string + changes *OperationChanges +} + +// ComparePathItemsV3 is an OpenAPI typesafe proxy method for ComparePathItems +func ComparePathItemsV3(l, r *v3.PathItem) *PathItemChanges { + return ComparePathItems(l, r) +} + +// ComparePathItems compare a left and right Swagger or OpenAPI PathItem object for changes. If found, returns +// a pointer to PathItemChanges, or returns nil if nothing is found. +func ComparePathItems(l, r any) *PathItemChanges { + + var changes []*Change + var props []*PropertyCheck + + pc := new(PathItemChanges) + + // Swagger + if reflect.TypeOf(&v2.PathItem{}) == reflect.TypeOf(l) && + reflect.TypeOf(&v2.PathItem{}) == reflect.TypeOf(r) { + + lPath := l.(*v2.PathItem) + rPath := r.(*v2.PathItem) + + // perform hash check to avoid further processing + if low.AreEqual(lPath, rPath) { + return nil + } + + props = append(props, compareSwaggerPathItem(lPath, rPath, &changes, pc)...) + } + + // OpenAPI + if reflect.TypeOf(&v3.PathItem{}) == reflect.TypeOf(l) && + reflect.TypeOf(&v3.PathItem{}) == reflect.TypeOf(r) { + + lPath := l.(*v3.PathItem) + rPath := r.(*v3.PathItem) + + // perform hash check to avoid further processing + if low.AreEqual(lPath, rPath) { + return nil + } + + // description + props = append(props, &PropertyCheck{ + LeftNode: lPath.Description.ValueNode, + RightNode: rPath.Description.ValueNode, + Label: v3.DescriptionLabel, + Changes: &changes, + Breaking: false, + Original: lPath, + New: lPath, + }) + + // summary + props = append(props, &PropertyCheck{ + LeftNode: lPath.Summary.ValueNode, + RightNode: rPath.Summary.ValueNode, + Label: v3.SummaryLabel, + Changes: &changes, + Breaking: false, + Original: lPath, + New: lPath, + }) + + compareOpenAPIPathItem(lPath, rPath, &changes, pc) + } + + CheckProperties(props) + pc.PropertyChanges = NewPropertyChanges(changes) + return pc +} + +func compareSwaggerPathItem(lPath, rPath *v2.PathItem, changes *[]*Change, pc *PathItemChanges) []*PropertyCheck { + + var props []*PropertyCheck + + totalOps := 0 + opChan := make(chan opCheck) + // get + if !lPath.Get.IsEmpty() && !rPath.Get.IsEmpty() { + totalOps++ + go checkOperation(lPath.Get.Value, rPath.Get.Value, opChan, v3.GetLabel) + } + if !lPath.Get.IsEmpty() && rPath.Get.IsEmpty() { + CreateChange(changes, PropertyRemoved, v3.GetLabel, + lPath.Get.ValueNode, nil, true, lPath.Get.Value, nil) + } + if lPath.Get.IsEmpty() && !rPath.Get.IsEmpty() { + CreateChange(changes, PropertyAdded, v3.GetLabel, + nil, rPath.Get.ValueNode, false, nil, lPath.Get.Value) + } + + // put + if !lPath.Put.IsEmpty() && !rPath.Put.IsEmpty() { + totalOps++ + go checkOperation(lPath.Put.Value, rPath.Put.Value, opChan, v3.PutLabel) + } + if !lPath.Put.IsEmpty() && rPath.Put.IsEmpty() { + CreateChange(changes, PropertyRemoved, v3.PutLabel, + lPath.Put.ValueNode, nil, true, lPath.Put.Value, nil) + } + if lPath.Put.IsEmpty() && !rPath.Put.IsEmpty() { + CreateChange(changes, PropertyAdded, v3.PutLabel, + nil, rPath.Put.ValueNode, false, nil, lPath.Put.Value) + } + + // post + if !lPath.Post.IsEmpty() && !rPath.Post.IsEmpty() { + totalOps++ + go checkOperation(lPath.Post.Value, rPath.Post.Value, opChan, v3.PostLabel) + } + if !lPath.Post.IsEmpty() && rPath.Post.IsEmpty() { + CreateChange(changes, PropertyRemoved, v3.PostLabel, + lPath.Post.ValueNode, nil, true, lPath.Post.Value, nil) + } + if lPath.Post.IsEmpty() && !rPath.Post.IsEmpty() { + CreateChange(changes, PropertyAdded, v3.PostLabel, + nil, rPath.Post.ValueNode, false, nil, lPath.Post.Value) + } + + // delete + if !lPath.Delete.IsEmpty() && !rPath.Delete.IsEmpty() { + totalOps++ + go checkOperation(lPath.Delete.Value, rPath.Delete.Value, opChan, v3.DeleteLabel) + } + if !lPath.Delete.IsEmpty() && rPath.Delete.IsEmpty() { + CreateChange(changes, PropertyRemoved, v3.DeleteLabel, + lPath.Delete.ValueNode, nil, true, lPath.Delete.Value, nil) + } + if lPath.Delete.IsEmpty() && !rPath.Delete.IsEmpty() { + CreateChange(changes, PropertyAdded, v3.DeleteLabel, + nil, rPath.Delete.ValueNode, false, nil, lPath.Delete.Value) + } + + // options + if !lPath.Options.IsEmpty() && !rPath.Options.IsEmpty() { + totalOps++ + go checkOperation(lPath.Options.Value, rPath.Options.Value, opChan, v3.OptionsLabel) + } + if !lPath.Options.IsEmpty() && rPath.Options.IsEmpty() { + CreateChange(changes, PropertyRemoved, v3.OptionsLabel, + lPath.Options.ValueNode, nil, true, lPath.Options.Value, nil) + } + if lPath.Options.IsEmpty() && !rPath.Options.IsEmpty() { + CreateChange(changes, PropertyAdded, v3.OptionsLabel, + nil, rPath.Options.ValueNode, false, nil, lPath.Options.Value) + } + + // head + if !lPath.Head.IsEmpty() && !rPath.Head.IsEmpty() { + totalOps++ + go checkOperation(lPath.Head.Value, rPath.Head.Value, opChan, v3.HeadLabel) + } + if !lPath.Head.IsEmpty() && rPath.Head.IsEmpty() { + CreateChange(changes, PropertyRemoved, v3.HeadLabel, + lPath.Head.ValueNode, nil, true, lPath.Head.Value, nil) + } + if lPath.Head.IsEmpty() && !rPath.Head.IsEmpty() { + CreateChange(changes, PropertyAdded, v3.HeadLabel, + nil, rPath.Head.ValueNode, false, nil, lPath.Head.Value) + } + + // patch + if !lPath.Patch.IsEmpty() && !rPath.Patch.IsEmpty() { + totalOps++ + go checkOperation(lPath.Patch.Value, rPath.Patch.Value, opChan, v3.PatchLabel) + } + if !lPath.Patch.IsEmpty() && rPath.Patch.IsEmpty() { + CreateChange(changes, PropertyRemoved, v3.PatchLabel, + lPath.Patch.ValueNode, nil, true, lPath.Patch.Value, nil) + } + if lPath.Patch.IsEmpty() && !rPath.Patch.IsEmpty() { + CreateChange(changes, PropertyAdded, v3.PatchLabel, + nil, rPath.Patch.ValueNode, false, nil, lPath.Patch.Value) + } + + // parameters + if !lPath.Parameters.IsEmpty() && !rPath.Parameters.IsEmpty() { + lParams := lPath.Parameters.Value + rParams := rPath.Parameters.Value + lp, rp := extractV2ParametersIntoInterface(lParams, rParams) + checkParameters(lp, rp, changes, pc) + } + if !lPath.Parameters.IsEmpty() && rPath.Parameters.IsEmpty() { + CreateChange(changes, PropertyRemoved, v3.ParametersLabel, + lPath.Parameters.ValueNode, nil, true, lPath.Parameters.Value, + nil) + } + if lPath.Parameters.IsEmpty() && !rPath.Parameters.IsEmpty() { + CreateChange(changes, PropertyAdded, v3.ParametersLabel, + nil, rPath.Parameters.ValueNode, true, nil, + rPath.Parameters.Value) + } + + // collect up operations changes. + completedOperations := 0 + for completedOperations < totalOps { + select { + case n := <-opChan: + switch n.label { + case v3.GetLabel: + pc.GetChanges = n.changes + break + case v3.PutLabel: + pc.PutChanges = n.changes + break + case v3.PostLabel: + pc.PostChanges = n.changes + break + case v3.DeleteLabel: + pc.DeleteChanges = n.changes + break + case v3.OptionsLabel: + pc.OptionsChanges = n.changes + break + case v2.HeadLabel: + pc.HeadChanges = n.changes + break + case v2.PatchLabel: + pc.PatchChanges = n.changes + break + } + completedOperations++ + } + } + pc.ExtensionChanges = CompareExtensions(lPath.Extensions, rPath.Extensions) + return props +} + +func extractV2ParametersIntoInterface(l, r []low.ValueReference[*v2.Parameter]) ([]low.ValueReference[low.SharedParameters], + []low.ValueReference[low.SharedParameters]) { + lp := make([]low.ValueReference[low.SharedParameters], len(l)) + rp := make([]low.ValueReference[low.SharedParameters], len(r)) + for i := range l { + lp[i] = low.ValueReference[low.SharedParameters]{ + Value: l[i].Value, + ValueNode: l[i].ValueNode, + } + } + for i := range r { + rp[i] = low.ValueReference[low.SharedParameters]{ + Value: r[i].Value, + ValueNode: r[i].ValueNode, + } + } + return lp, rp +} + +func extractV3ParametersIntoInterface(l, r []low.ValueReference[*v3.Parameter]) ([]low.ValueReference[low.SharedParameters], + []low.ValueReference[low.SharedParameters]) { + lp := make([]low.ValueReference[low.SharedParameters], len(l)) + rp := make([]low.ValueReference[low.SharedParameters], len(r)) + for i := range l { + lp[i] = low.ValueReference[low.SharedParameters]{ + Value: l[i].Value, + ValueNode: l[i].ValueNode, + } + } + for i := range r { + rp[i] = low.ValueReference[low.SharedParameters]{ + Value: r[i].Value, + ValueNode: r[i].ValueNode, + } + } + return lp, rp +} + +func checkParameters(lParams, rParams []low.ValueReference[low.SharedParameters], changes *[]*Change, pc *PathItemChanges) { + + lv := make(map[string]low.SharedParameters, len(lParams)) + rv := make(map[string]low.SharedParameters, len(rParams)) + + for i := range lParams { + s := lParams[i].Value.GetName().Value + lv[s] = lParams[i].Value + } + for i := range rParams { + s := rParams[i].Value.GetName().Value + rv[s] = rParams[i].Value + } + + var paramChanges []*ParameterChanges + for n := range lv { + if _, ok := rv[n]; ok { + if !low.AreEqual(lv[n], rv[n]) { + ch := CompareParameters(lv[n], rv[n]) + if ch != nil { + paramChanges = append(paramChanges, ch) + } + } + continue + } + CreateChange(changes, ObjectRemoved, v3.ParametersLabel, + lv[n].GetName().ValueNode, nil, true, lv[n].GetName().Value, + nil) + + } + for n := range rv { + if _, ok := lv[n]; !ok { + CreateChange(changes, ObjectAdded, v3.ParametersLabel, + nil, rv[n].GetName().ValueNode, true, nil, + rv[n].GetName().Value) + } + } + pc.ParameterChanges = paramChanges +} + +func compareOpenAPIPathItem(lPath, rPath *v3.PathItem, changes *[]*Change, pc *PathItemChanges) { + + //var props []*PropertyCheck + + totalOps := 0 + opChan := make(chan opCheck) + + // get + if !lPath.Get.IsEmpty() && !rPath.Get.IsEmpty() { + totalOps++ + go checkOperation(lPath.Get.Value, rPath.Get.Value, opChan, v3.GetLabel) + } + if !lPath.Get.IsEmpty() && rPath.Get.IsEmpty() { + CreateChange(changes, PropertyRemoved, v3.GetLabel, + lPath.Get.ValueNode, nil, true, lPath.Get.Value, nil) + } + if lPath.Get.IsEmpty() && !rPath.Get.IsEmpty() { + CreateChange(changes, PropertyAdded, v3.GetLabel, + nil, rPath.Get.ValueNode, false, nil, lPath.Get.Value) + } + + // put + if !lPath.Put.IsEmpty() && !rPath.Put.IsEmpty() { + totalOps++ + go checkOperation(lPath.Put.Value, rPath.Put.Value, opChan, v3.PutLabel) + } + if !lPath.Put.IsEmpty() && rPath.Put.IsEmpty() { + CreateChange(changes, PropertyRemoved, v3.PutLabel, + lPath.Put.ValueNode, nil, true, lPath.Put.Value, nil) + } + if lPath.Put.IsEmpty() && !rPath.Put.IsEmpty() { + CreateChange(changes, PropertyAdded, v3.PutLabel, + nil, rPath.Put.ValueNode, false, nil, lPath.Put.Value) + } + + // post + if !lPath.Post.IsEmpty() && !rPath.Post.IsEmpty() { + totalOps++ + go checkOperation(lPath.Post.Value, rPath.Post.Value, opChan, v3.PostLabel) + } + if !lPath.Post.IsEmpty() && rPath.Post.IsEmpty() { + CreateChange(changes, PropertyRemoved, v3.PostLabel, + lPath.Post.ValueNode, nil, true, lPath.Post.Value, nil) + } + if lPath.Post.IsEmpty() && !rPath.Post.IsEmpty() { + CreateChange(changes, PropertyAdded, v3.PostLabel, + nil, rPath.Post.ValueNode, false, nil, lPath.Post.Value) + } + + // delete + if !lPath.Delete.IsEmpty() && !rPath.Delete.IsEmpty() { + totalOps++ + go checkOperation(lPath.Delete.Value, rPath.Delete.Value, opChan, v3.DeleteLabel) + } + if !lPath.Delete.IsEmpty() && rPath.Delete.IsEmpty() { + CreateChange(changes, PropertyRemoved, v3.DeleteLabel, + lPath.Delete.ValueNode, nil, true, lPath.Delete.Value, nil) + } + if lPath.Delete.IsEmpty() && !rPath.Delete.IsEmpty() { + CreateChange(changes, PropertyAdded, v3.DeleteLabel, + nil, rPath.Delete.ValueNode, false, nil, lPath.Delete.Value) + } + + // options + if !lPath.Options.IsEmpty() && !rPath.Options.IsEmpty() { + totalOps++ + go checkOperation(lPath.Options.Value, rPath.Options.Value, opChan, v3.OptionsLabel) + } + if !lPath.Options.IsEmpty() && rPath.Options.IsEmpty() { + CreateChange(changes, PropertyRemoved, v3.OptionsLabel, + lPath.Options.ValueNode, nil, true, lPath.Options.Value, nil) + } + if lPath.Options.IsEmpty() && !rPath.Options.IsEmpty() { + CreateChange(changes, PropertyAdded, v3.OptionsLabel, + nil, rPath.Options.ValueNode, false, nil, lPath.Options.Value) + } + + // head + if !lPath.Head.IsEmpty() && !rPath.Head.IsEmpty() { + totalOps++ + go checkOperation(lPath.Head.Value, rPath.Head.Value, opChan, v3.HeadLabel) + } + if !lPath.Head.IsEmpty() && rPath.Head.IsEmpty() { + CreateChange(changes, PropertyRemoved, v3.HeadLabel, + lPath.Head.ValueNode, nil, true, lPath.Head.Value, nil) + } + if lPath.Head.IsEmpty() && !rPath.Head.IsEmpty() { + CreateChange(changes, PropertyAdded, v3.HeadLabel, + nil, rPath.Head.ValueNode, false, nil, lPath.Head.Value) + } + + // patch + if !lPath.Patch.IsEmpty() && !rPath.Patch.IsEmpty() { + totalOps++ + go checkOperation(lPath.Patch.Value, rPath.Patch.Value, opChan, v3.PatchLabel) + } + if !lPath.Patch.IsEmpty() && rPath.Patch.IsEmpty() { + CreateChange(changes, PropertyRemoved, v3.PatchLabel, + lPath.Patch.ValueNode, nil, true, lPath.Patch.Value, nil) + } + if lPath.Patch.IsEmpty() && !rPath.Patch.IsEmpty() { + CreateChange(changes, PropertyAdded, v3.PatchLabel, + nil, rPath.Patch.ValueNode, false, nil, lPath.Patch.Value) + } + + // trace + if !lPath.Trace.IsEmpty() && !rPath.Trace.IsEmpty() { + totalOps++ + go checkOperation(lPath.Trace.Value, rPath.Trace.Value, opChan, v3.TraceLabel) + } + if !lPath.Trace.IsEmpty() && rPath.Trace.IsEmpty() { + CreateChange(changes, PropertyRemoved, v3.TraceLabel, + lPath.Trace.ValueNode, nil, true, lPath.Trace.Value, nil) + } + if lPath.Trace.IsEmpty() && !rPath.Trace.IsEmpty() { + CreateChange(changes, PropertyAdded, v3.TraceLabel, + nil, rPath.Trace.ValueNode, false, nil, lPath.Trace.Value) + } + + // servers + pc.ServerChanges = checkServers(lPath.Servers, rPath.Servers) + + // parameters + if !lPath.Parameters.IsEmpty() && !rPath.Parameters.IsEmpty() { + lParams := lPath.Parameters.Value + rParams := rPath.Parameters.Value + lp, rp := extractV3ParametersIntoInterface(lParams, rParams) + checkParameters(lp, rp, changes, pc) + } + + if !lPath.Parameters.IsEmpty() && rPath.Parameters.IsEmpty() { + CreateChange(changes, PropertyRemoved, v3.ParametersLabel, + lPath.Parameters.ValueNode, nil, true, lPath.Parameters.Value, + nil) + } + if lPath.Parameters.IsEmpty() && !rPath.Parameters.IsEmpty() { + CreateChange(changes, PropertyAdded, v3.ParametersLabel, + nil, rPath.Parameters.ValueNode, true, nil, + rPath.Parameters.Value) + } + + // collect up operations changes. + completedOperations := 0 + for completedOperations < totalOps { + select { + case n := <-opChan: + switch n.label { + case v3.GetLabel: + pc.GetChanges = n.changes + break + case v3.PutLabel: + pc.PutChanges = n.changes + break + case v3.PostLabel: + pc.PostChanges = n.changes + break + case v3.DeleteLabel: + pc.DeleteChanges = n.changes + break + case v3.OptionsLabel: + pc.OptionsChanges = n.changes + break + case v3.HeadLabel: + pc.HeadChanges = n.changes + break + case v3.PatchLabel: + pc.PatchChanges = n.changes + break + case v3.TraceLabel: + pc.TraceChanges = n.changes + break + } + completedOperations++ + } + } + pc.ExtensionChanges = CompareExtensions(lPath.Extensions, rPath.Extensions) +} + +func checkOperation(l, r any, done chan opCheck, method string) { + done <- opCheck{ + label: method, + changes: CompareOperations(l, r), + } +} diff --git a/vendor/github.com/pb33f/libopenapi/what-changed/model/paths.go b/vendor/github.com/pb33f/libopenapi/what-changed/model/paths.go new file mode 100644 index 0000000000..2c54d1481c --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/what-changed/model/paths.go @@ -0,0 +1,206 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package model + +import ( + "github.com/pb33f/libopenapi/datamodel/low" + "github.com/pb33f/libopenapi/datamodel/low/v2" + v3 "github.com/pb33f/libopenapi/datamodel/low/v3" + "reflect" + "sync" +) + +// PathsChanges represents changes found between two Swagger or OpenAPI Paths Objects. +type PathsChanges struct { + *PropertyChanges + PathItemsChanges map[string]*PathItemChanges `json:"pathItems,omitempty" yaml:"pathItems,omitempty"` + ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"` +} + +// GetAllChanges returns a slice of all changes made between Paths objects +func (p *PathsChanges) GetAllChanges() []*Change { + var changes []*Change + changes = append(changes, p.Changes...) + for k := range p.PathItemsChanges { + changes = append(changes, p.PathItemsChanges[k].GetAllChanges()...) + } + if p.ExtensionChanges != nil { + changes = append(changes, p.ExtensionChanges.GetAllChanges()...) + } + return changes +} + +// TotalChanges returns the total number of changes between two Swagger or OpenAPI Paths Objects +func (p *PathsChanges) TotalChanges() int { + c := p.PropertyChanges.TotalChanges() + for k := range p.PathItemsChanges { + c += p.PathItemsChanges[k].TotalChanges() + } + if p.ExtensionChanges != nil { + c += p.ExtensionChanges.TotalChanges() + } + return c +} + +// TotalBreakingChanges returns tht total number of changes found between two Swagger or OpenAPI Path Objects +func (p *PathsChanges) TotalBreakingChanges() int { + c := p.PropertyChanges.TotalBreakingChanges() + for k := range p.PathItemsChanges { + c += p.PathItemsChanges[k].TotalBreakingChanges() + } + return c +} + +// ComparePaths compares a left and right Swagger or OpenAPI Paths Object for changes. If found, returns a pointer +// to a PathsChanges instance. Returns nil if nothing is found. +func ComparePaths(l, r any) *PathsChanges { + + var changes []*Change + + pc := new(PathsChanges) + pathChanges := make(map[string]*PathItemChanges) + + // Swagger + if reflect.TypeOf(&v2.Paths{}) == reflect.TypeOf(l) && + reflect.TypeOf(&v2.Paths{}) == reflect.TypeOf(r) { + + lPath := l.(*v2.Paths) + rPath := r.(*v2.Paths) + + // perform hash check to avoid further processing + if low.AreEqual(lPath, rPath) { + return nil + } + + lKeys := make(map[string]low.ValueReference[*v2.PathItem]) + rKeys := make(map[string]low.ValueReference[*v2.PathItem]) + for k := range lPath.PathItems { + lKeys[k.Value] = lPath.PathItems[k] + } + for k := range rPath.PathItems { + rKeys[k.Value] = rPath.PathItems[k] + } + + // run every comparison in a thread. + var mLock sync.Mutex + compare := func(path string, pChanges map[string]*PathItemChanges, l, r *v2.PathItem, doneChan chan bool) { + if !low.AreEqual(l, r) { + mLock.Lock() + pathChanges[path] = ComparePathItems(l, r) + mLock.Unlock() + } + doneChan <- true + } + + doneChan := make(chan bool) + pathsChecked := 0 + + for k := range lKeys { + if _, ok := rKeys[k]; ok { + go compare(k, pathChanges, lKeys[k].Value, rKeys[k].Value, doneChan) + pathsChecked++ + continue + } + g, p := lPath.FindPathAndKey(k) + CreateChange(&changes, ObjectRemoved, v3.PathLabel, + g.KeyNode, nil, true, + p.Value, nil) + } + + for k := range rKeys { + if _, ok := lKeys[k]; !ok { + g, p := rPath.FindPathAndKey(k) + CreateChange(&changes, ObjectAdded, v3.PathLabel, + nil, g.KeyNode, false, + nil, p.Value) + } + } + + // wait for the things to be done. + completedChecks := 0 + for completedChecks < pathsChecked { + select { + case <-doneChan: + completedChecks++ + } + } + if len(pathChanges) > 0 { + pc.PathItemsChanges = pathChanges + } + + pc.ExtensionChanges = CompareExtensions(lPath.Extensions, rPath.Extensions) + } + + // OpenAPI + if reflect.TypeOf(&v3.Paths{}) == reflect.TypeOf(l) && + reflect.TypeOf(&v3.Paths{}) == reflect.TypeOf(r) { + + lPath := l.(*v3.Paths) + rPath := r.(*v3.Paths) + + // perform hash check to avoid further processing + if low.AreEqual(lPath, rPath) { + return nil + } + + lKeys := make(map[string]low.ValueReference[*v3.PathItem]) + rKeys := make(map[string]low.ValueReference[*v3.PathItem]) + for k := range lPath.PathItems { + lKeys[k.Value] = lPath.PathItems[k] + } + for k := range rPath.PathItems { + rKeys[k.Value] = rPath.PathItems[k] + } + + // run every comparison in a thread. + var mLock sync.Mutex + compare := func(path string, pChanges map[string]*PathItemChanges, l, r *v3.PathItem, doneChan chan bool) { + if !low.AreEqual(l, r) { + mLock.Lock() + pathChanges[path] = ComparePathItems(l, r) + mLock.Unlock() + } + doneChan <- true + } + + doneChan := make(chan bool) + pathsChecked := 0 + + for k := range lKeys { + if _, ok := rKeys[k]; ok { + go compare(k, pathChanges, lKeys[k].Value, rKeys[k].Value, doneChan) + pathsChecked++ + continue + } + g, p := lPath.FindPathAndKey(k) + CreateChange(&changes, ObjectRemoved, v3.PathLabel, + g.KeyNode, nil, true, + p.Value, nil) + } + + for k := range rKeys { + if _, ok := lKeys[k]; !ok { + g, p := rPath.FindPathAndKey(k) + CreateChange(&changes, ObjectAdded, v3.PathLabel, + nil, g.KeyNode, false, + nil, p.Value) + } + } + // wait for the things to be done. + completedChecks := 0 + for completedChecks < pathsChecked { + select { + case <-doneChan: + completedChecks++ + } + } + if len(pathChanges) > 0 { + pc.PathItemsChanges = pathChanges + } + + pc.ExtensionChanges = CompareExtensions(lPath.Extensions, rPath.Extensions) + } + pc.PropertyChanges = NewPropertyChanges(changes) + return pc +} diff --git a/vendor/github.com/pb33f/libopenapi/what-changed/model/request_body.go b/vendor/github.com/pb33f/libopenapi/what-changed/model/request_body.go new file mode 100644 index 0000000000..1f209fa25c --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/what-changed/model/request_body.go @@ -0,0 +1,93 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package model + +import ( + "github.com/pb33f/libopenapi/datamodel/low" + "github.com/pb33f/libopenapi/datamodel/low/v3" +) + +// RequestBodyChanges represents changes made between two OpenAPI RequestBody Objects +type RequestBodyChanges struct { + *PropertyChanges + ContentChanges map[string]*MediaTypeChanges `json:"content,omitempty" yaml:"content,omitempty"` + ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"` +} + +// GetAllChanges returns a slice of all changes made between RequestBody objects +func (rb *RequestBodyChanges) GetAllChanges() []*Change { + var changes []*Change + changes = append(changes, rb.Changes...) + for k := range rb.ContentChanges { + changes = append(changes, rb.ContentChanges[k].GetAllChanges()...) + } + if rb.ExtensionChanges != nil { + changes = append(changes, rb.ExtensionChanges.GetAllChanges()...) + } + return changes +} + +// TotalChanges returns the total number of changes found between two OpenAPI RequestBody objects +func (rb *RequestBodyChanges) TotalChanges() int { + c := rb.PropertyChanges.TotalChanges() + for k := range rb.ContentChanges { + c += rb.ContentChanges[k].TotalChanges() + } + if rb.ExtensionChanges != nil { + c += rb.ExtensionChanges.TotalChanges() + } + return c +} + +// TotalBreakingChanges returns the total number of breaking changes found between OpenAPI RequestBody objects +func (rb *RequestBodyChanges) TotalBreakingChanges() int { + c := rb.PropertyChanges.TotalBreakingChanges() + for k := range rb.ContentChanges { + c += rb.ContentChanges[k].TotalBreakingChanges() + } + return c +} + +// CompareRequestBodies compares a left and right OpenAPI RequestBody object for changes. If found returns a pointer +// to a RequestBodyChanges instance. Returns nil if nothing was found. +func CompareRequestBodies(l, r *v3.RequestBody) *RequestBodyChanges { + if low.AreEqual(l, r) { + return nil + } + + var changes []*Change + var props []*PropertyCheck + + // description + props = append(props, &PropertyCheck{ + LeftNode: l.Description.ValueNode, + RightNode: r.Description.ValueNode, + Label: v3.DescriptionLabel, + Changes: &changes, + Breaking: false, + Original: l, + New: r, + }) + + // required + props = append(props, &PropertyCheck{ + LeftNode: l.Required.ValueNode, + RightNode: r.Required.ValueNode, + Label: v3.RequiredLabel, + Changes: &changes, + Breaking: true, + Original: l, + New: r, + }) + + CheckProperties(props) + + rbc := new(RequestBodyChanges) + rbc.ContentChanges = CheckMapForChanges(l.Content.Value, r.Content.Value, + &changes, v3.ContentLabel, CompareMediaTypes) + rbc.ExtensionChanges = CompareExtensions(l.Extensions, r.Extensions) + rbc.PropertyChanges = NewPropertyChanges(changes) + + return rbc +} diff --git a/vendor/github.com/pb33f/libopenapi/what-changed/model/response.go b/vendor/github.com/pb33f/libopenapi/what-changed/model/response.go new file mode 100644 index 0000000000..beef347d3c --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/what-changed/model/response.go @@ -0,0 +1,199 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package model + +import ( + "github.com/pb33f/libopenapi/datamodel/low" + v3 "github.com/pb33f/libopenapi/datamodel/low/v3" + "reflect" +) + +import ( + "github.com/pb33f/libopenapi/datamodel/low/v2" +) + +// ResponseChanges represents changes found between two Swagger or OpenAPI Response objects. +type ResponseChanges struct { + *PropertyChanges + ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"` + HeadersChanges map[string]*HeaderChanges `json:"headers,omitempty" yaml:"headers,omitempty"` + + // Swagger Response Properties. + SchemaChanges *SchemaChanges `json:"schemas,omitempty" yaml:"schemas,omitempty"` + ExamplesChanges *ExamplesChanges `json:"examples,omitempty" yaml:"examples,omitempty"` + + // OpenAPI Response Properties. + ContentChanges map[string]*MediaTypeChanges `json:"content,omitempty" yaml:"content,omitempty"` + LinkChanges map[string]*LinkChanges `json:"links,omitempty" yaml:"links,omitempty"` +} + +// GetAllChanges returns a slice of all changes made between RequestBody objects +func (r *ResponseChanges) GetAllChanges() []*Change { + var changes []*Change + changes = append(changes, r.Changes...) + if r.ExtensionChanges != nil { + changes = append(changes, r.ExtensionChanges.GetAllChanges()...) + } + if r.SchemaChanges != nil { + changes = append(changes, r.SchemaChanges.GetAllChanges()...) + } + if r.ExamplesChanges != nil { + changes = append(changes, r.ExamplesChanges.GetAllChanges()...) + } + for k := range r.HeadersChanges { + changes = append(changes, r.HeadersChanges[k].GetAllChanges()...) + } + for k := range r.ContentChanges { + changes = append(changes, r.ContentChanges[k].GetAllChanges()...) + } + for k := range r.LinkChanges { + changes = append(changes, r.LinkChanges[k].GetAllChanges()...) + } + return changes +} + +// TotalChanges returns the total number of changes found between two Swagger or OpenAPI Response Objects +func (r *ResponseChanges) TotalChanges() int { + c := r.PropertyChanges.TotalChanges() + if r.ExtensionChanges != nil { + c += r.ExtensionChanges.TotalChanges() + } + if r.SchemaChanges != nil { + c += r.SchemaChanges.TotalChanges() + } + if r.ExamplesChanges != nil { + c += r.ExamplesChanges.TotalChanges() + } + for k := range r.HeadersChanges { + c += r.HeadersChanges[k].TotalChanges() + } + for k := range r.ContentChanges { + c += r.ContentChanges[k].TotalChanges() + } + for k := range r.LinkChanges { + c += r.LinkChanges[k].TotalChanges() + } + return c +} + +// TotalBreakingChanges returns the total number of breaking changes found between two swagger or OpenAPI +// Response Objects +func (r *ResponseChanges) TotalBreakingChanges() int { + c := r.PropertyChanges.TotalBreakingChanges() + if r.SchemaChanges != nil { + c += r.SchemaChanges.TotalBreakingChanges() + } + for k := range r.HeadersChanges { + c += r.HeadersChanges[k].TotalBreakingChanges() + } + for k := range r.ContentChanges { + c += r.ContentChanges[k].TotalBreakingChanges() + } + for k := range r.LinkChanges { + c += r.LinkChanges[k].TotalBreakingChanges() + } + return c +} + +// CompareResponseV2 is a Swagger type safe proxy for CompareResponse +func CompareResponseV2(l, r *v2.Response) *ResponseChanges { + return CompareResponse(l, r) +} + +// CompareResponseV3 is an OpenAPI type safe proxy for CompareResponse +func CompareResponseV3(l, r *v3.Response) *ResponseChanges { + return CompareResponse(l, r) +} + +// CompareResponse compares a left and right Swagger or OpenAPI Response object. If anything is found +// a pointer to a ResponseChanges is returned, otherwise it returns nil. +func CompareResponse(l, r any) *ResponseChanges { + + var changes []*Change + var props []*PropertyCheck + + rc := new(ResponseChanges) + + if reflect.TypeOf(&v2.Response{}) == reflect.TypeOf(l) && reflect.TypeOf(&v2.Response{}) == reflect.TypeOf(r) { + + lResponse := l.(*v2.Response) + rResponse := r.(*v2.Response) + + // perform hash check to avoid further processing + if low.AreEqual(lResponse, rResponse) { + return nil + } + + // description + addPropertyCheck(&props, lResponse.Description.ValueNode, rResponse.Description.ValueNode, + lResponse.Description.Value, rResponse.Description.Value, &changes, v3.DescriptionLabel, false) + + if !lResponse.Schema.IsEmpty() && !rResponse.Schema.IsEmpty() { + rc.SchemaChanges = CompareSchemas(lResponse.Schema.Value, rResponse.Schema.Value) + } + if !lResponse.Schema.IsEmpty() && rResponse.Schema.IsEmpty() { + CreateChange(&changes, ObjectRemoved, v3.SchemaLabel, + lResponse.Schema.ValueNode, nil, true, + lResponse.Schema.Value, nil) + } + if lResponse.Schema.IsEmpty() && !rResponse.Schema.IsEmpty() { + CreateChange(&changes, ObjectAdded, v3.SchemaLabel, + nil, rResponse.Schema.ValueNode, true, + nil, rResponse.Schema.Value) + } + + rc.HeadersChanges = + CheckMapForChanges(lResponse.Headers.Value, rResponse.Headers.Value, + &changes, v3.HeadersLabel, CompareHeadersV2) + + if !lResponse.Examples.IsEmpty() && !rResponse.Examples.IsEmpty() { + rc.ExamplesChanges = CompareExamplesV2(lResponse.Examples.Value, rResponse.Examples.Value) + } + if !lResponse.Examples.IsEmpty() && rResponse.Examples.IsEmpty() { + CreateChange(&changes, PropertyRemoved, v3.ExamplesLabel, + lResponse.Schema.ValueNode, nil, false, + lResponse.Schema.Value, nil) + } + if lResponse.Examples.IsEmpty() && !rResponse.Examples.IsEmpty() { + CreateChange(&changes, ObjectAdded, v3.ExamplesLabel, + nil, rResponse.Schema.ValueNode, false, + nil, lResponse.Schema.Value) + } + + rc.ExtensionChanges = CompareExtensions(lResponse.Extensions, rResponse.Extensions) + } + + if reflect.TypeOf(&v3.Response{}) == reflect.TypeOf(l) && reflect.TypeOf(&v3.Response{}) == reflect.TypeOf(r) { + + lResponse := l.(*v3.Response) + rResponse := r.(*v3.Response) + + // perform hash check to avoid further processing + if low.AreEqual(lResponse, rResponse) { + return nil + } + + // description + addPropertyCheck(&props, lResponse.Description.ValueNode, rResponse.Description.ValueNode, + lResponse.Description.Value, lResponse.Description.Value, &changes, v3.DescriptionLabel, false) + + rc.HeadersChanges = + CheckMapForChanges(lResponse.Headers.Value, rResponse.Headers.Value, + &changes, v3.HeadersLabel, CompareHeadersV3) + + rc.ContentChanges = + CheckMapForChanges(lResponse.Content.Value, rResponse.Content.Value, + &changes, v3.ContentLabel, CompareMediaTypes) + + rc.LinkChanges = + CheckMapForChanges(lResponse.Links.Value, rResponse.Links.Value, + &changes, v3.LinksLabel, CompareLinks) + + rc.ExtensionChanges = CompareExtensions(lResponse.Extensions, rResponse.Extensions) + } + + CheckProperties(props) + rc.PropertyChanges = NewPropertyChanges(changes) + return rc +} diff --git a/vendor/github.com/pb33f/libopenapi/what-changed/model/responses.go b/vendor/github.com/pb33f/libopenapi/what-changed/model/responses.go new file mode 100644 index 0000000000..03c8812c08 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/what-changed/model/responses.go @@ -0,0 +1,140 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package model + +import ( + "github.com/pb33f/libopenapi/datamodel/low" + "github.com/pb33f/libopenapi/datamodel/low/v2" + "github.com/pb33f/libopenapi/datamodel/low/v3" + "reflect" +) + +// ResponsesChanges represents changes made between two Swagger or OpenAPI Responses objects. +type ResponsesChanges struct { + *PropertyChanges + ResponseChanges map[string]*ResponseChanges `json:"response,omitempty" yaml:"response,omitempty"` + DefaultChanges *ResponseChanges `json:"default,omitempty" yaml:"default,omitempty"` + ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"` +} + +// GetAllChanges returns a slice of all changes made between Responses objects +func (r *ResponsesChanges) GetAllChanges() []*Change { + var changes []*Change + changes = append(changes, r.Changes...) + for k := range r.ResponseChanges { + changes = append(changes, r.ResponseChanges[k].GetAllChanges()...) + } + if r.DefaultChanges != nil { + changes = append(changes, r.DefaultChanges.GetAllChanges()...) + } + if r.ExtensionChanges != nil { + changes = append(changes, r.ExtensionChanges.GetAllChanges()...) + } + return changes +} + +// TotalChanges returns the total number of changes found between two Swagger or OpenAPI Responses objects +func (r *ResponsesChanges) TotalChanges() int { + c := r.PropertyChanges.TotalChanges() + for k := range r.ResponseChanges { + c += r.ResponseChanges[k].TotalChanges() + } + if r.DefaultChanges != nil { + c += r.DefaultChanges.TotalChanges() + } + if r.ExtensionChanges != nil { + c += r.ExtensionChanges.TotalChanges() + } + return c +} + +// TotalBreakingChanges returns the total number of changes found between two Swagger or OpenAPI +// Responses Objects +func (r *ResponsesChanges) TotalBreakingChanges() int { + c := r.PropertyChanges.TotalBreakingChanges() + for k := range r.ResponseChanges { + c += r.ResponseChanges[k].TotalBreakingChanges() + } + if r.DefaultChanges != nil { + c += r.DefaultChanges.TotalBreakingChanges() + } + return c +} + +// CompareResponses compares a left and right Swagger or OpenAPI Responses object for any changes. If found +// returns a pointer to ResponsesChanges, or returns nil. +func CompareResponses(l, r any) *ResponsesChanges { + + var changes []*Change + + rc := new(ResponsesChanges) + + // swagger + if reflect.TypeOf(&v2.Responses{}) == reflect.TypeOf(l) && + reflect.TypeOf(&v2.Responses{}) == reflect.TypeOf(r) { + + lResponses := l.(*v2.Responses) + rResponses := r.(*v2.Responses) + + // perform hash check to avoid further processing + if low.AreEqual(lResponses, rResponses) { + return nil + } + + if !lResponses.Default.IsEmpty() && !rResponses.Default.IsEmpty() { + rc.DefaultChanges = CompareResponse(lResponses.Default.Value, rResponses.Default.Value) + } + if !lResponses.Default.IsEmpty() && rResponses.Default.IsEmpty() { + CreateChange(&changes, ObjectRemoved, v3.DefaultLabel, + lResponses.Default.ValueNode, nil, true, + lResponses.Default.Value, nil) + } + if lResponses.Default.IsEmpty() && !rResponses.Default.IsEmpty() { + CreateChange(&changes, ObjectAdded, v3.DefaultLabel, + nil, rResponses.Default.ValueNode, false, + nil, lResponses.Default.Value) + } + + rc.ResponseChanges = CheckMapForChanges(lResponses.Codes, rResponses.Codes, + &changes, v3.CodesLabel, CompareResponseV2) + + rc.ExtensionChanges = CompareExtensions(lResponses.Extensions, rResponses.Extensions) + } + + // openapi + if reflect.TypeOf(&v3.Responses{}) == reflect.TypeOf(l) && + reflect.TypeOf(&v3.Responses{}) == reflect.TypeOf(r) { + + lResponses := l.(*v3.Responses) + rResponses := r.(*v3.Responses) + + //perform hash check to avoid further processing + if low.AreEqual(lResponses, rResponses) { + return nil + } + + if !lResponses.Default.IsEmpty() && !rResponses.Default.IsEmpty() { + rc.DefaultChanges = CompareResponse(lResponses.Default.Value, rResponses.Default.Value) + } + if !lResponses.Default.IsEmpty() && rResponses.Default.IsEmpty() { + CreateChange(&changes, ObjectRemoved, v3.DefaultLabel, + lResponses.Default.ValueNode, nil, true, + lResponses.Default.Value, nil) + } + if lResponses.Default.IsEmpty() && !rResponses.Default.IsEmpty() { + CreateChange(&changes, ObjectAdded, v3.DefaultLabel, + nil, rResponses.Default.ValueNode, false, + nil, lResponses.Default.Value) + } + + rc.ResponseChanges = CheckMapForChanges(lResponses.Codes, rResponses.Codes, + &changes, v3.CodesLabel, CompareResponseV3) + + rc.ExtensionChanges = CompareExtensions(lResponses.Extensions, rResponses.Extensions) + + } + + rc.PropertyChanges = NewPropertyChanges(changes) + return rc +} diff --git a/vendor/github.com/pb33f/libopenapi/what-changed/model/schema.go b/vendor/github.com/pb33f/libopenapi/what-changed/model/schema.go new file mode 100644 index 0000000000..a24d7230fe --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/what-changed/model/schema.go @@ -0,0 +1,1237 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package model + +import ( + "fmt" + "github.com/pb33f/libopenapi/datamodel/low" + "github.com/pb33f/libopenapi/datamodel/low/base" + v3 "github.com/pb33f/libopenapi/datamodel/low/v3" + "github.com/pb33f/libopenapi/utils" + "gopkg.in/yaml.v3" + "sort" + "sync" +) + +// SchemaChanges represent all changes to a base.Schema OpenAPI object. These changes are represented +// by all versions of OpenAPI. +// +// Any additions or removals to slice based results will be recorded in the PropertyChanges of the parent +// changes, and not the child for example, adding a new schema to `anyOf` will create a new change result in +// PropertyChanges.Changes, and not in the AnyOfChanges property. +type SchemaChanges struct { + *PropertyChanges + DiscriminatorChanges *DiscriminatorChanges `json:"discriminator,omitempty" yaml:"discriminator,omitempty"` + AllOfChanges []*SchemaChanges `json:"allOf,omitempty" yaml:"allOf,omitempty"` + AnyOfChanges []*SchemaChanges `json:"anyOf,omitempty" yaml:"anyOf,omitempty"` + OneOfChanges []*SchemaChanges `json:"oneOf,omitempty" yaml:"oneOf,omitempty"` + NotChanges *SchemaChanges `json:"not,omitempty" yaml:"not,omitempty"` + ItemsChanges *SchemaChanges `json:"items,omitempty" yaml:"items,omitempty"` + SchemaPropertyChanges map[string]*SchemaChanges `json:"properties,omitempty" yaml:"properties,omitempty"` + ExternalDocChanges *ExternalDocChanges `json:"externalDoc,omitempty" yaml:"externalDoc,omitempty"` + XMLChanges *XMLChanges `json:"xml,omitempty" yaml:"xml,omitempty"` + ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"` + + // 3.1 specifics + IfChanges *SchemaChanges `json:"if,omitempty" yaml:"if,omitempty"` + ElseChanges *SchemaChanges `json:"else,omitempty" yaml:"else,omitempty"` + ThenChanges *SchemaChanges `json:"then,omitempty" yaml:"then,omitempty"` + PropertyNamesChanges *SchemaChanges `json:"propertyNames,omitempty" yaml:"propertyNames,omitempty"` + ContainsChanges *SchemaChanges `json:"contains,omitempty" yaml:"contains,omitempty"` + UnevaluatedItemsChanges *SchemaChanges `json:"unevaluatedItems,omitempty" yaml:"unevaluatedItems,omitempty"` + UnevaluatedPropertiesChanges *SchemaChanges `json:"unevaluatedProperties,omitempty" yaml:"unevaluatedProperties,omitempty"` + DependentSchemasChanges map[string]*SchemaChanges `json:"dependentSchemas,omitempty" yaml:"dependentSchemas,omitempty"` + PatternPropertiesChanges map[string]*SchemaChanges `json:"patternProperties,omitempty" yaml:"patternProperties,omitempty"` +} + +// GetAllChanges returns a slice of all changes made between Responses objects +func (s *SchemaChanges) GetAllChanges() []*Change { + var changes []*Change + changes = append(changes, s.Changes...) + if s.DiscriminatorChanges != nil { + changes = append(changes, s.DiscriminatorChanges.GetAllChanges()...) + } + if len(s.AllOfChanges) > 0 { + for n := range s.AllOfChanges { + if s.AllOfChanges[n] != nil { + changes = append(changes, s.AllOfChanges[n].GetAllChanges()...) + } + } + } + if len(s.AnyOfChanges) > 0 { + for n := range s.AnyOfChanges { + if s.AnyOfChanges[n] != nil { + changes = append(changes, s.AnyOfChanges[n].GetAllChanges()...) + } + } + } + if len(s.OneOfChanges) > 0 { + for n := range s.OneOfChanges { + if s.OneOfChanges[n] != nil { + changes = append(changes, s.OneOfChanges[n].GetAllChanges()...) + } + } + } + if s.NotChanges != nil { + changes = append(changes, s.NotChanges.GetAllChanges()...) + } + if s.ItemsChanges != nil { + changes = append(changes, s.ItemsChanges.GetAllChanges()...) + } + if s.IfChanges != nil { + changes = append(changes, s.IfChanges.GetAllChanges()...) + } + if s.ElseChanges != nil { + changes = append(changes, s.ElseChanges.GetAllChanges()...) + } + if s.ThenChanges != nil { + changes = append(changes, s.ThenChanges.GetAllChanges()...) + } + if s.PropertyNamesChanges != nil { + changes = append(changes, s.PropertyNamesChanges.GetAllChanges()...) + } + if s.ContainsChanges != nil { + changes = append(changes, s.ContainsChanges.GetAllChanges()...) + } + if s.UnevaluatedItemsChanges != nil { + changes = append(changes, s.UnevaluatedItemsChanges.GetAllChanges()...) + } + if s.UnevaluatedPropertiesChanges != nil { + changes = append(changes, s.UnevaluatedPropertiesChanges.GetAllChanges()...) + } + if s.SchemaPropertyChanges != nil { + for n := range s.SchemaPropertyChanges { + if s.SchemaPropertyChanges[n] != nil { + changes = append(changes, s.SchemaPropertyChanges[n].GetAllChanges()...) + } + } + } + if s.DependentSchemasChanges != nil { + for n := range s.DependentSchemasChanges { + if s.DependentSchemasChanges[n] != nil { + changes = append(changes, s.DependentSchemasChanges[n].GetAllChanges()...) + } + } + } + if s.PatternPropertiesChanges != nil { + for n := range s.PatternPropertiesChanges { + if s.PatternPropertiesChanges[n] != nil { + changes = append(changes, s.PatternPropertiesChanges[n].GetAllChanges()...) + } + } + } + if s.ExternalDocChanges != nil { + changes = append(changes, s.ExternalDocChanges.GetAllChanges()...) + } + if s.XMLChanges != nil { + changes = append(changes, s.XMLChanges.GetAllChanges()...) + } + if s.ExtensionChanges != nil { + changes = append(changes, s.ExtensionChanges.GetAllChanges()...) + } + return changes +} + +// TotalChanges returns a count of the total number of changes made to this schema and all sub-schemas +func (s *SchemaChanges) TotalChanges() int { + t := s.PropertyChanges.TotalChanges() + if s.DiscriminatorChanges != nil { + t += s.DiscriminatorChanges.TotalChanges() + } + if len(s.AllOfChanges) > 0 { + for n := range s.AllOfChanges { + t += s.AllOfChanges[n].TotalChanges() + } + } + if len(s.AnyOfChanges) > 0 { + for n := range s.AnyOfChanges { + if s.AnyOfChanges[n] != nil { + t += s.AnyOfChanges[n].TotalChanges() + } + } + } + if len(s.OneOfChanges) > 0 { + for n := range s.OneOfChanges { + t += s.OneOfChanges[n].TotalChanges() + } + } + if s.NotChanges != nil { + t += s.NotChanges.TotalChanges() + } + if s.ItemsChanges != nil { + t += s.ItemsChanges.TotalChanges() + } + if s.IfChanges != nil { + t += s.IfChanges.TotalChanges() + } + if s.ElseChanges != nil { + t += s.ElseChanges.TotalChanges() + } + if s.ThenChanges != nil { + t += s.ThenChanges.TotalChanges() + } + if s.PropertyNamesChanges != nil { + t += s.PropertyNamesChanges.TotalChanges() + } + if s.ContainsChanges != nil { + t += s.ContainsChanges.TotalChanges() + } + if s.UnevaluatedItemsChanges != nil { + t += s.UnevaluatedItemsChanges.TotalChanges() + } + if s.UnevaluatedPropertiesChanges != nil { + t += s.UnevaluatedPropertiesChanges.TotalChanges() + } + if s.SchemaPropertyChanges != nil { + for n := range s.SchemaPropertyChanges { + if s.SchemaPropertyChanges[n] != nil { + t += s.SchemaPropertyChanges[n].TotalChanges() + } + } + } + if s.DependentSchemasChanges != nil { + for n := range s.DependentSchemasChanges { + t += s.DependentSchemasChanges[n].TotalChanges() + } + } + if s.PatternPropertiesChanges != nil { + for n := range s.PatternPropertiesChanges { + t += s.PatternPropertiesChanges[n].TotalChanges() + } + } + if s.ExternalDocChanges != nil { + t += s.ExternalDocChanges.TotalChanges() + } + if s.XMLChanges != nil { + t += s.XMLChanges.TotalChanges() + } + if s.ExtensionChanges != nil { + t += s.ExtensionChanges.TotalChanges() + } + return t +} + +// TotalBreakingChanges returns the total number of breaking changes made to this schema and all sub-schemas. +func (s *SchemaChanges) TotalBreakingChanges() int { + t := s.PropertyChanges.TotalBreakingChanges() + if s.DiscriminatorChanges != nil { + t += s.DiscriminatorChanges.TotalBreakingChanges() + } + if len(s.AllOfChanges) > 0 { + for n := range s.AllOfChanges { + t += s.AllOfChanges[n].TotalBreakingChanges() + } + } + if len(s.AllOfChanges) > 0 { + for n := range s.AllOfChanges { + t += s.AllOfChanges[n].TotalBreakingChanges() + } + } + if len(s.AnyOfChanges) > 0 { + for n := range s.AnyOfChanges { + t += s.AnyOfChanges[n].TotalBreakingChanges() + } + } + if len(s.OneOfChanges) > 0 { + for n := range s.OneOfChanges { + t += s.OneOfChanges[n].TotalBreakingChanges() + } + } + if s.NotChanges != nil { + t += s.NotChanges.TotalBreakingChanges() + } + if s.ItemsChanges != nil { + t += s.ItemsChanges.TotalBreakingChanges() + } + if s.IfChanges != nil { + t += s.IfChanges.TotalBreakingChanges() + } + if s.ElseChanges != nil { + t += s.ElseChanges.TotalBreakingChanges() + } + if s.ThenChanges != nil { + t += s.ThenChanges.TotalBreakingChanges() + } + if s.PropertyNamesChanges != nil { + t += s.PropertyNamesChanges.TotalBreakingChanges() + } + if s.ContainsChanges != nil { + t += s.ContainsChanges.TotalBreakingChanges() + } + if s.UnevaluatedItemsChanges != nil { + t += s.UnevaluatedItemsChanges.TotalBreakingChanges() + } + if s.UnevaluatedPropertiesChanges != nil { + t += s.UnevaluatedPropertiesChanges.TotalBreakingChanges() + } + if s.DependentSchemasChanges != nil { + for n := range s.DependentSchemasChanges { + t += s.DependentSchemasChanges[n].TotalBreakingChanges() + } + } + if s.PatternPropertiesChanges != nil { + for n := range s.PatternPropertiesChanges { + t += s.PatternPropertiesChanges[n].TotalBreakingChanges() + } + } + if s.XMLChanges != nil { + t += s.XMLChanges.TotalBreakingChanges() + } + if s.SchemaPropertyChanges != nil { + for n := range s.SchemaPropertyChanges { + t += s.SchemaPropertyChanges[n].TotalBreakingChanges() + } + } + return t +} + +// CompareSchemas accepts a left and right SchemaProxy and checks for changes. If anything is found, returns +// a pointer to SchemaChanges, otherwise returns nil +func CompareSchemas(l, r *base.SchemaProxy) *SchemaChanges { + sc := new(SchemaChanges) + var changes []*Change + + // Added + if l == nil && r != nil { + CreateChange(&changes, ObjectAdded, v3.SchemaLabel, + nil, nil, true, nil, r) + sc.PropertyChanges = NewPropertyChanges(changes) + } + + // Removed + if l != nil && r == nil { + CreateChange(&changes, ObjectRemoved, v3.SchemaLabel, + nil, nil, true, l, nil) + sc.PropertyChanges = NewPropertyChanges(changes) + } + + if l != nil && r != nil { + + // if left proxy is a reference and right is a reference (we won't recurse into them) + if l.IsSchemaReference() && r.IsSchemaReference() { + // points to the same schema + if l.GetSchemaReference() == r.GetSchemaReference() { + // there is nothing to be done at this point. + return nil + } else { + // references are different, that's all we care to know. + CreateChange(&changes, Modified, v3.RefLabel, + l.GetValueNode().Content[1], r.GetValueNode().Content[1], true, l.GetSchemaReference(), + r.GetSchemaReference()) + sc.PropertyChanges = NewPropertyChanges(changes) + return sc + } + } + + // changed from inline to ref + if !l.IsSchemaReference() && r.IsSchemaReference() { + CreateChange(&changes, Modified, v3.RefLabel, + l.GetValueNode(), r.GetValueNode().Content[1], true, l, r.GetSchemaReference()) + sc.PropertyChanges = NewPropertyChanges(changes) + return sc // we're done here + } + + // changed from ref to inline + if l.IsSchemaReference() && !r.IsSchemaReference() { + CreateChange(&changes, Modified, v3.RefLabel, + l.GetValueNode().Content[1], r.GetValueNode(), true, l.GetSchemaReference(), r) + sc.PropertyChanges = NewPropertyChanges(changes) + return sc // done, nothing else to do. + } + + lSchema := l.Schema() + rSchema := r.Schema() + + if low.AreEqual(lSchema, rSchema) { + // there is no point going on, we know nothing changed! + return nil + } + + // check XML + checkSchemaXML(lSchema, rSchema, &changes, sc) + + // check examples + checkExamples(lSchema, rSchema, &changes) + + // check schema core properties for changes. + checkSchemaPropertyChanges(lSchema, rSchema, &changes, sc) + + // now for the confusing part, there is also a schema's 'properties' property to parse. + // inception, eat your heart out. + doneChan := make(chan bool) + props, totalProperties := checkMappedSchemaOfASchema(lSchema.Properties.Value, rSchema.Properties.Value, &changes, doneChan) + sc.SchemaPropertyChanges = props + + deps, depsTotal := checkMappedSchemaOfASchema(lSchema.DependentSchemas.Value, rSchema.DependentSchemas.Value, &changes, doneChan) + sc.DependentSchemasChanges = deps + + patterns, patternsTotal := checkMappedSchemaOfASchema(lSchema.PatternProperties.Value, rSchema.PatternProperties.Value, &changes, doneChan) + sc.PatternPropertiesChanges = patterns + + // check polymorphic and multi-values async for speed. + go extractSchemaChanges(lSchema.OneOf.Value, rSchema.OneOf.Value, v3.OneOfLabel, + &sc.OneOfChanges, &changes, doneChan) + + go extractSchemaChanges(lSchema.AllOf.Value, rSchema.AllOf.Value, v3.AllOfLabel, + &sc.AllOfChanges, &changes, doneChan) + + go extractSchemaChanges(lSchema.AnyOf.Value, rSchema.AnyOf.Value, v3.AnyOfLabel, + &sc.AnyOfChanges, &changes, doneChan) + + totalChecks := totalProperties + depsTotal + patternsTotal + 3 + completedChecks := 0 + for completedChecks < totalChecks { + select { + case <-doneChan: + completedChecks++ + } + } + } + // done + if changes != nil { + sc.PropertyChanges = NewPropertyChanges(changes) + } else { + sc.PropertyChanges = NewPropertyChanges(nil) + } + if sc.TotalChanges() > 0 { + return sc + } + return nil +} + +func checkSchemaXML(lSchema *base.Schema, rSchema *base.Schema, changes *[]*Change, sc *SchemaChanges) { + // XML removed + if lSchema.XML.Value != nil && rSchema.XML.Value == nil { + CreateChange(changes, ObjectRemoved, v3.XMLLabel, + lSchema.XML.GetValueNode(), nil, true, lSchema.XML.GetValue(), nil) + } + // XML added + if lSchema.XML.Value == nil && rSchema.XML.Value != nil { + CreateChange(changes, ObjectAdded, v3.XMLLabel, + nil, rSchema.XML.GetValueNode(), false, nil, rSchema.XML.GetValue()) + } + + // compare XML + if lSchema.XML.Value != nil && rSchema.XML.Value != nil { + if !low.AreEqual(lSchema.XML.Value, rSchema.XML.Value) { + sc.XMLChanges = CompareXML(lSchema.XML.Value, rSchema.XML.Value) + } + } +} + +func checkMappedSchemaOfASchema( + lSchema, + rSchema map[low.KeyReference[string]]low.ValueReference[*base.SchemaProxy], + changes *[]*Change, + doneChan chan bool) (map[string]*SchemaChanges, int) { + + propChanges := make(map[string]*SchemaChanges) + + var lProps []string + lEntities := make(map[string]*base.SchemaProxy) + lKeyNodes := make(map[string]*yaml.Node) + var rProps []string + rEntities := make(map[string]*base.SchemaProxy) + rKeyNodes := make(map[string]*yaml.Node) + + for w := range lSchema { + lProps = append(lProps, w.Value) + lEntities[w.Value] = lSchema[w].Value + lKeyNodes[w.Value] = w.KeyNode + } + for w := range rSchema { + rProps = append(rProps, w.Value) + rEntities[w.Value] = rSchema[w].Value + rKeyNodes[w.Value] = w.KeyNode + } + sort.Strings(lProps) + sort.Strings(rProps) + totalProperties := buildProperty(lProps, rProps, lEntities, rEntities, propChanges, doneChan, changes, rKeyNodes, lKeyNodes) + return propChanges, totalProperties +} + +func buildProperty(lProps, rProps []string, lEntities, rEntities map[string]*base.SchemaProxy, + propChanges map[string]*SchemaChanges, doneChan chan bool, changes *[]*Change, rKeyNodes, lKeyNodes map[string]*yaml.Node) int { + var propLock sync.Mutex + checkProperty := func(key string, lp, rp *base.SchemaProxy, propChanges map[string]*SchemaChanges, done chan bool) { + if lp != nil && rp != nil { + if low.AreEqual(lp, rp) { + done <- true + return + } + s := CompareSchemas(lp, rp) + propLock.Lock() + propChanges[key] = s + propLock.Unlock() + done <- true + } + } + + totalProperties := 0 + if len(lProps) == len(rProps) { + for w := range lProps { + lp := lEntities[lProps[w]] + rp := rEntities[rProps[w]] + if lProps[w] == rProps[w] && lp != nil && rp != nil { + totalProperties++ + go checkProperty(lProps[w], lp, rp, propChanges, doneChan) + } + + // keys do not match, even after sorting, means a like for like replacement. + if lProps[w] != rProps[w] { + + // old removed, new added. + CreateChange(changes, ObjectAdded, v3.PropertiesLabel, + nil, rKeyNodes[rProps[w]], false, nil, rEntities[rProps[w]]) + + CreateChange(changes, ObjectRemoved, v3.PropertiesLabel, + lKeyNodes[lProps[w]], nil, true, lEntities[lProps[w]], nil) + } + + } + } + + // something removed + if len(lProps) > len(rProps) { + for w := range lProps { + + if rEntities[lProps[w]] != nil { + totalProperties++ + go checkProperty(lProps[w], lEntities[lProps[w]], rEntities[lProps[w]], propChanges, doneChan) + continue + } else { + CreateChange(changes, ObjectRemoved, v3.PropertiesLabel, + lKeyNodes[lProps[w]], nil, true, lEntities[lProps[w]], nil) + continue + } + } + } + + // something added + if len(rProps) > len(lProps) { + for w := range rProps { + if lEntities[rProps[w]] != nil { + totalProperties++ + go checkProperty(rProps[w], lEntities[rProps[w]], rEntities[rProps[w]], propChanges, doneChan) + } else { + CreateChange(changes, ObjectAdded, v3.PropertiesLabel, + nil, rKeyNodes[rProps[w]], false, nil, rEntities[rProps[w]]) + continue + } + } + } + return totalProperties +} + +func checkSchemaPropertyChanges( + lSchema *base.Schema, + rSchema *base.Schema, + changes *[]*Change, sc *SchemaChanges) { + + var props []*PropertyCheck + + // $schema (breaking change) + props = append(props, &PropertyCheck{ + LeftNode: lSchema.SchemaTypeRef.ValueNode, + RightNode: rSchema.SchemaTypeRef.ValueNode, + Label: v3.SchemaDialectLabel, + Changes: changes, + Breaking: true, + Original: lSchema, + New: rSchema, + }) + + // ExclusiveMaximum + props = append(props, &PropertyCheck{ + LeftNode: lSchema.ExclusiveMaximum.ValueNode, + RightNode: rSchema.ExclusiveMaximum.ValueNode, + Label: v3.ExclusiveMaximumLabel, + Changes: changes, + Breaking: true, + Original: lSchema, + New: rSchema, + }) + + // ExclusiveMinimum + props = append(props, &PropertyCheck{ + LeftNode: lSchema.ExclusiveMinimum.ValueNode, + RightNode: rSchema.ExclusiveMinimum.ValueNode, + Label: v3.ExclusiveMinimumLabel, + Changes: changes, + Breaking: true, + Original: lSchema, + New: rSchema, + }) + + // Type + props = append(props, &PropertyCheck{ + LeftNode: lSchema.Type.ValueNode, + RightNode: rSchema.Type.ValueNode, + Label: v3.TypeLabel, + Changes: changes, + Breaking: true, + Original: lSchema, + New: rSchema, + }) + + // Title + props = append(props, &PropertyCheck{ + LeftNode: lSchema.Title.ValueNode, + RightNode: rSchema.Title.ValueNode, + Label: v3.TitleLabel, + Changes: changes, + Breaking: false, + Original: lSchema, + New: rSchema, + }) + + // MultipleOf + props = append(props, &PropertyCheck{ + LeftNode: lSchema.MultipleOf.ValueNode, + RightNode: rSchema.MultipleOf.ValueNode, + Label: v3.MultipleOfLabel, + Changes: changes, + Breaking: true, + Original: lSchema, + New: rSchema, + }) + + // Maximum + props = append(props, &PropertyCheck{ + LeftNode: lSchema.Maximum.ValueNode, + RightNode: rSchema.Maximum.ValueNode, + Label: v3.MaximumLabel, + Changes: changes, + Breaking: true, + Original: lSchema, + New: rSchema, + }) + + // Minimum + props = append(props, &PropertyCheck{ + LeftNode: lSchema.Minimum.ValueNode, + RightNode: rSchema.Minimum.ValueNode, + Label: v3.MinimumLabel, + Changes: changes, + Breaking: true, + Original: lSchema, + New: rSchema, + }) + + // MaxLength + props = append(props, &PropertyCheck{ + LeftNode: lSchema.MaxLength.ValueNode, + RightNode: rSchema.MaxLength.ValueNode, + Label: v3.MaxLengthLabel, + Changes: changes, + Breaking: true, + Original: lSchema, + New: rSchema, + }) + + // MinLength + props = append(props, &PropertyCheck{ + LeftNode: lSchema.MinLength.ValueNode, + RightNode: rSchema.MinLength.ValueNode, + Label: v3.MinLengthLabel, + Changes: changes, + Breaking: true, + Original: lSchema, + New: rSchema, + }) + + // Pattern + props = append(props, &PropertyCheck{ + LeftNode: lSchema.Pattern.ValueNode, + RightNode: rSchema.Pattern.ValueNode, + Label: v3.PatternLabel, + Changes: changes, + Breaking: true, + Original: lSchema, + New: rSchema, + }) + + // Format + props = append(props, &PropertyCheck{ + LeftNode: lSchema.Format.ValueNode, + RightNode: rSchema.Format.ValueNode, + Label: v3.FormatLabel, + Changes: changes, + Breaking: true, + Original: lSchema, + New: rSchema, + }) + + // MaxItems + props = append(props, &PropertyCheck{ + LeftNode: lSchema.MaxItems.ValueNode, + RightNode: rSchema.MaxItems.ValueNode, + Label: v3.MaxItemsLabel, + Changes: changes, + Breaking: true, + Original: lSchema, + New: rSchema, + }) + + // MinItems + props = append(props, &PropertyCheck{ + LeftNode: lSchema.MinItems.ValueNode, + RightNode: rSchema.MinItems.ValueNode, + Label: v3.MinItemsLabel, + Changes: changes, + Breaking: true, + Original: lSchema, + New: rSchema, + }) + + // MaxProperties + props = append(props, &PropertyCheck{ + LeftNode: lSchema.MaxProperties.ValueNode, + RightNode: rSchema.MaxProperties.ValueNode, + Label: v3.MaxPropertiesLabel, + Changes: changes, + Breaking: true, + Original: lSchema, + New: rSchema, + }) + + // MinProperties + props = append(props, &PropertyCheck{ + LeftNode: lSchema.MinProperties.ValueNode, + RightNode: rSchema.MinProperties.ValueNode, + Label: v3.MinPropertiesLabel, + Changes: changes, + Breaking: true, + Original: lSchema, + New: rSchema, + }) + + // UniqueItems + props = append(props, &PropertyCheck{ + LeftNode: lSchema.UniqueItems.ValueNode, + RightNode: rSchema.UniqueItems.ValueNode, + Label: v3.UniqueItemsLabel, + Changes: changes, + Breaking: true, + Original: lSchema, + New: rSchema, + }) + + // AdditionalProperties (only if not an object) + if !utils.IsNodeMap(lSchema.AdditionalProperties.ValueNode) && + !utils.IsNodeMap(rSchema.AdditionalProperties.ValueNode) { + props = append(props, &PropertyCheck{ + LeftNode: lSchema.AdditionalProperties.ValueNode, + RightNode: rSchema.AdditionalProperties.ValueNode, + Label: v3.AdditionalPropertiesLabel, + Changes: changes, + Breaking: false, + Original: lSchema, + New: rSchema, + }) + } + + //Description + props = append(props, &PropertyCheck{ + LeftNode: lSchema.Description.ValueNode, + RightNode: rSchema.Description.ValueNode, + Label: v3.DescriptionLabel, + Changes: changes, + Breaking: false, + Original: lSchema, + New: rSchema, + }) + + // ContentEncoding + props = append(props, &PropertyCheck{ + LeftNode: lSchema.ContentEncoding.ValueNode, + RightNode: rSchema.ContentEncoding.ValueNode, + Label: v3.ContentEncodingLabel, + Changes: changes, + Breaking: true, + Original: lSchema, + New: rSchema, + }) + + // ContentMediaType + props = append(props, &PropertyCheck{ + LeftNode: lSchema.ContentMediaType.ValueNode, + RightNode: rSchema.ContentMediaType.ValueNode, + Label: v3.ContentMediaType, + Changes: changes, + Breaking: true, + Original: lSchema, + New: rSchema, + }) + + // Default + props = append(props, &PropertyCheck{ + LeftNode: lSchema.Default.ValueNode, + RightNode: rSchema.Default.ValueNode, + Label: v3.DefaultLabel, + Changes: changes, + Breaking: true, + Original: lSchema, + New: rSchema, + }) + + // Nullable + props = append(props, &PropertyCheck{ + LeftNode: lSchema.Nullable.ValueNode, + RightNode: rSchema.Nullable.ValueNode, + Label: v3.NullableLabel, + Changes: changes, + Breaking: true, + Original: lSchema, + New: rSchema, + }) + + // ReadOnly + props = append(props, &PropertyCheck{ + LeftNode: lSchema.ReadOnly.ValueNode, + RightNode: rSchema.ReadOnly.ValueNode, + Label: v3.ReadOnlyLabel, + Changes: changes, + Breaking: true, + Original: lSchema, + New: rSchema, + }) + + // WriteOnly + props = append(props, &PropertyCheck{ + LeftNode: lSchema.WriteOnly.ValueNode, + RightNode: rSchema.WriteOnly.ValueNode, + Label: v3.WriteOnlyLabel, + Changes: changes, + Breaking: true, + Original: lSchema, + New: rSchema, + }) + + // Example + props = append(props, &PropertyCheck{ + LeftNode: lSchema.Example.ValueNode, + RightNode: rSchema.Example.ValueNode, + Label: v3.ExampleLabel, + Changes: changes, + Breaking: false, + Original: lSchema, + New: rSchema, + }) + + // Deprecated + props = append(props, &PropertyCheck{ + LeftNode: lSchema.Deprecated.ValueNode, + RightNode: rSchema.Deprecated.ValueNode, + Label: v3.DeprecatedLabel, + Changes: changes, + Breaking: false, + Original: lSchema, + New: rSchema, + }) + + // Required + j := make(map[string]int) + k := make(map[string]int) + for i := range lSchema.Required.Value { + j[lSchema.Required.Value[i].Value] = i + } + for i := range rSchema.Required.Value { + k[rSchema.Required.Value[i].Value] = i + } + for g := range k { + if _, ok := j[g]; !ok { + CreateChange(changes, PropertyAdded, v3.RequiredLabel, + nil, rSchema.Required.Value[k[g]].GetValueNode(), true, nil, + rSchema.Required.Value[k[g]].GetValue) + } + } + for g := range j { + if _, ok := k[g]; !ok { + CreateChange(changes, PropertyRemoved, v3.RequiredLabel, + lSchema.Required.Value[j[g]].GetValueNode(), nil, true, lSchema.Required.Value[j[g]].GetValue, + nil) + } + } + + // Enums + j = make(map[string]int) + k = make(map[string]int) + for i := range lSchema.Enum.Value { + j[fmt.Sprint(lSchema.Enum.Value[i].Value)] = i + } + for i := range rSchema.Enum.Value { + k[fmt.Sprint(rSchema.Enum.Value[i].Value)] = i + } + for g := range k { + if _, ok := j[g]; !ok { + CreateChange(changes, PropertyAdded, v3.EnumLabel, + nil, rSchema.Enum.Value[k[g]].GetValueNode(), false, nil, + rSchema.Enum.Value[k[g]].GetValue) + } + } + for g := range j { + if _, ok := k[g]; !ok { + CreateChange(changes, PropertyRemoved, v3.EnumLabel, + lSchema.Enum.Value[j[g]].GetValueNode(), nil, true, lSchema.Enum.Value[j[g]].GetValue, + nil) + } + } + + // Discriminator + if lSchema.Discriminator.Value != nil && rSchema.Discriminator.Value != nil { + // check if hash matches, if not then compare. + if lSchema.Discriminator.Value.Hash() != rSchema.Discriminator.Value.Hash() { + sc.DiscriminatorChanges = CompareDiscriminator(lSchema.Discriminator.Value, rSchema.Discriminator.Value) + } + } + // added Discriminator + if lSchema.Discriminator.Value == nil && rSchema.Discriminator.Value != nil { + CreateChange(changes, ObjectAdded, v3.DiscriminatorLabel, + nil, rSchema.Discriminator.ValueNode, true, nil, rSchema.Discriminator.Value) + } + // removed Discriminator + if lSchema.Discriminator.Value != nil && rSchema.Discriminator.Value == nil { + CreateChange(changes, ObjectRemoved, v3.DiscriminatorLabel, + lSchema.Discriminator.ValueNode, nil, true, lSchema.Discriminator.Value, nil) + } + + // ExternalDocs + if lSchema.ExternalDocs.Value != nil && rSchema.ExternalDocs.Value != nil { + // check if hash matches, if not then compare. + if lSchema.ExternalDocs.Value.Hash() != rSchema.ExternalDocs.Value.Hash() { + sc.ExternalDocChanges = CompareExternalDocs(lSchema.ExternalDocs.Value, rSchema.ExternalDocs.Value) + } + } + // added ExternalDocs + if lSchema.ExternalDocs.Value == nil && rSchema.ExternalDocs.Value != nil { + CreateChange(changes, ObjectAdded, v3.ExternalDocsLabel, + nil, rSchema.ExternalDocs.ValueNode, false, nil, rSchema.ExternalDocs.Value) + } + // removed ExternalDocs + if lSchema.ExternalDocs.Value != nil && rSchema.ExternalDocs.Value == nil { + CreateChange(changes, ObjectRemoved, v3.ExternalDocsLabel, + lSchema.ExternalDocs.ValueNode, nil, false, lSchema.ExternalDocs.Value, nil) + } + + // 3.1 properties + // If + if lSchema.If.Value != nil && rSchema.If.Value != nil { + if !low.AreEqual(lSchema.If.Value, rSchema.If.Value) { + sc.IfChanges = CompareSchemas(lSchema.If.Value, rSchema.If.Value) + } + } + // added If + if lSchema.If.Value == nil && rSchema.If.Value != nil { + CreateChange(changes, ObjectAdded, v3.IfLabel, + nil, rSchema.If.ValueNode, true, nil, rSchema.If.Value) + } + // removed If + if lSchema.If.Value != nil && rSchema.If.Value == nil { + CreateChange(changes, ObjectRemoved, v3.IfLabel, + lSchema.If.ValueNode, nil, true, lSchema.If.Value, nil) + } + // Else + if lSchema.Else.Value != nil && rSchema.Else.Value != nil { + if !low.AreEqual(lSchema.Else.Value, rSchema.Else.Value) { + sc.ElseChanges = CompareSchemas(lSchema.Else.Value, rSchema.Else.Value) + } + } + // added Else + if lSchema.Else.Value == nil && rSchema.Else.Value != nil { + CreateChange(changes, ObjectAdded, v3.ElseLabel, + nil, rSchema.Else.ValueNode, true, nil, rSchema.Else.Value) + } + // removed Else + if lSchema.Else.Value != nil && rSchema.Else.Value == nil { + CreateChange(changes, ObjectRemoved, v3.ElseLabel, + lSchema.Else.ValueNode, nil, true, lSchema.Else.Value, nil) + } + // Then + if lSchema.Then.Value != nil && rSchema.Then.Value != nil { + if !low.AreEqual(lSchema.Then.Value, rSchema.Then.Value) { + sc.ThenChanges = CompareSchemas(lSchema.Then.Value, rSchema.Then.Value) + } + } + // added Then + if lSchema.Then.Value == nil && rSchema.Then.Value != nil { + CreateChange(changes, ObjectAdded, v3.ThenLabel, + nil, rSchema.Then.ValueNode, true, nil, rSchema.Then.Value) + } + // removed Then + if lSchema.Then.Value != nil && rSchema.Then.Value == nil { + CreateChange(changes, ObjectRemoved, v3.ThenLabel, + lSchema.Then.ValueNode, nil, true, lSchema.Then.Value, nil) + } + // PropertyNames + if lSchema.PropertyNames.Value != nil && rSchema.PropertyNames.Value != nil { + if !low.AreEqual(lSchema.PropertyNames.Value, rSchema.PropertyNames.Value) { + sc.PropertyNamesChanges = CompareSchemas(lSchema.PropertyNames.Value, rSchema.PropertyNames.Value) + } + } + // added PropertyNames + if lSchema.PropertyNames.Value == nil && rSchema.PropertyNames.Value != nil { + CreateChange(changes, ObjectAdded, v3.PropertyNamesLabel, + nil, rSchema.PropertyNames.ValueNode, true, nil, rSchema.PropertyNames.Value) + } + // removed PropertyNames + if lSchema.PropertyNames.Value != nil && rSchema.PropertyNames.Value == nil { + CreateChange(changes, ObjectRemoved, v3.PropertyNamesLabel, + lSchema.PropertyNames.ValueNode, nil, true, lSchema.PropertyNames.Value, nil) + } + // Contains + if lSchema.Contains.Value != nil && rSchema.Contains.Value != nil { + if !low.AreEqual(lSchema.Contains.Value, rSchema.Contains.Value) { + sc.ContainsChanges = CompareSchemas(lSchema.Contains.Value, rSchema.Contains.Value) + } + } + // added Contains + if lSchema.Contains.Value == nil && rSchema.Contains.Value != nil { + CreateChange(changes, ObjectAdded, v3.ContainsLabel, + nil, rSchema.Contains.ValueNode, true, nil, rSchema.Contains.Value) + } + // removed Contains + if lSchema.Contains.Value != nil && rSchema.Contains.Value == nil { + CreateChange(changes, ObjectRemoved, v3.ContainsLabel, + lSchema.Contains.ValueNode, nil, true, lSchema.Contains.Value, nil) + } + // UnevaluatedItems + if lSchema.UnevaluatedItems.Value != nil && rSchema.UnevaluatedItems.Value != nil { + if !low.AreEqual(lSchema.UnevaluatedItems.Value, rSchema.UnevaluatedItems.Value) { + sc.UnevaluatedItemsChanges = CompareSchemas(lSchema.UnevaluatedItems.Value, rSchema.UnevaluatedItems.Value) + } + } + // added UnevaluatedItems + if lSchema.UnevaluatedItems.Value == nil && rSchema.UnevaluatedItems.Value != nil { + CreateChange(changes, ObjectAdded, v3.UnevaluatedItemsLabel, + nil, rSchema.UnevaluatedItems.ValueNode, true, nil, rSchema.UnevaluatedItems.Value) + } + // removed UnevaluatedItems + if lSchema.UnevaluatedItems.Value != nil && rSchema.UnevaluatedItems.Value == nil { + CreateChange(changes, ObjectRemoved, v3.UnevaluatedItemsLabel, + lSchema.UnevaluatedItems.ValueNode, nil, true, lSchema.UnevaluatedItems.Value, nil) + } + // UnevaluatedProperties + if lSchema.UnevaluatedProperties.Value != nil && rSchema.UnevaluatedProperties.Value != nil { + if !low.AreEqual(lSchema.UnevaluatedProperties.Value, rSchema.UnevaluatedProperties.Value) { + sc.UnevaluatedPropertiesChanges = CompareSchemas(lSchema.UnevaluatedProperties.Value, rSchema.UnevaluatedProperties.Value) + } + } + // added UnevaluatedProperties + if lSchema.UnevaluatedProperties.Value == nil && rSchema.UnevaluatedProperties.Value != nil { + CreateChange(changes, ObjectAdded, v3.UnevaluatedPropertiesLabel, + nil, rSchema.UnevaluatedProperties.ValueNode, true, nil, rSchema.UnevaluatedProperties.Value) + } + // removed UnevaluatedProperties + if lSchema.UnevaluatedProperties.Value != nil && rSchema.UnevaluatedProperties.Value == nil { + CreateChange(changes, ObjectRemoved, v3.UnevaluatedPropertiesLabel, + lSchema.UnevaluatedProperties.ValueNode, nil, true, lSchema.UnevaluatedProperties.Value, nil) + } + + // Not + if lSchema.Not.Value != nil && rSchema.Not.Value != nil { + if !low.AreEqual(lSchema.Not.Value, rSchema.Not.Value) { + sc.NotChanges = CompareSchemas(lSchema.Not.Value, rSchema.Not.Value) + } + } + // added Not + if lSchema.Not.Value == nil && rSchema.Not.Value != nil { + CreateChange(changes, ObjectAdded, v3.NotLabel, + nil, rSchema.Not.ValueNode, true, nil, rSchema.Not.Value) + } + // removed not + if lSchema.Not.Value != nil && rSchema.Not.Value == nil { + CreateChange(changes, ObjectRemoved, v3.NotLabel, + lSchema.Not.ValueNode, nil, true, lSchema.Not.Value, nil) + } + + // items + if lSchema.Items.Value != nil && rSchema.Items.Value != nil { + if lSchema.Items.Value.IsA() && rSchema.Items.Value.IsA() { + if !low.AreEqual(lSchema.Items.Value.A, rSchema.Items.Value.A) { + sc.ItemsChanges = CompareSchemas(lSchema.Items.Value.A, rSchema.Items.Value.A) + } + } else { + CreateChange(changes, Modified, v3.ItemsLabel, + lSchema.Items.ValueNode, rSchema.Items.ValueNode, true, lSchema.Items.Value.B, rSchema.Items.Value.B) + } + } + // added Items + if lSchema.Items.Value == nil && rSchema.Items.Value != nil { + CreateChange(changes, ObjectAdded, v3.ItemsLabel, + nil, rSchema.Items.ValueNode, true, nil, rSchema.Items.Value) + } + // removed Items + if lSchema.Items.Value != nil && rSchema.Items.Value == nil { + CreateChange(changes, ObjectRemoved, v3.ItemsLabel, + lSchema.Items.ValueNode, nil, true, lSchema.Items.Value, nil) + } + + // check extensions + sc.ExtensionChanges = CompareExtensions(lSchema.Extensions, rSchema.Extensions) + + // if additional properties is an object, then hash it + // AdditionalProperties (only if not an object) + if utils.IsNodeMap(lSchema.AdditionalProperties.ValueNode) || + utils.IsNodeMap(rSchema.AdditionalProperties.ValueNode) { + + lHash := low.GenerateHashString(lSchema.AdditionalProperties.ValueNode) + rHash := low.GenerateHashString(rSchema.AdditionalProperties.ValueNode) + if lHash != rHash { + CreateChange(changes, Modified, v3.AdditionalPropertiesLabel, + lSchema.AdditionalProperties.ValueNode, rSchema.AdditionalProperties.ValueNode, false, + lSchema.AdditionalProperties.Value, rSchema.AdditionalProperties.Value) + } + } + + // check core properties + CheckProperties(props) +} + +func checkExamples(lSchema *base.Schema, rSchema *base.Schema, changes *[]*Change) { + // check examples (3.1+) + var lExampKey, rExampKey []string + lExampN := make(map[string]*yaml.Node) + rExampN := make(map[string]*yaml.Node) + lExampVal := make(map[string]any) + rExampVal := make(map[string]any) + + // create keys by hashing values + if lSchema.Examples.ValueNode != nil { + for i := range lSchema.Examples.ValueNode.Content { + key := low.GenerateHashString(lSchema.Examples.ValueNode.Content[i].Value) + lExampKey = append(lExampKey, key) + lExampVal[key] = lSchema.Examples.ValueNode.Content[i].Value + lExampN[key] = lSchema.Examples.ValueNode.Content[i] + + } + } + if rSchema.Examples.ValueNode != nil { + for i := range rSchema.Examples.ValueNode.Content { + key := low.GenerateHashString(rSchema.Examples.ValueNode.Content[i].Value) + rExampKey = append(rExampKey, key) + rExampVal[key] = rSchema.Examples.ValueNode.Content[i].Value + rExampN[key] = rSchema.Examples.ValueNode.Content[i] + } + } + + // if examples equal lengths, check for equality + if len(lExampKey) == len(rExampKey) { + for i := range lExampKey { + if lExampKey[i] != rExampKey[i] { + CreateChange(changes, Modified, v3.ExamplesLabel, + lExampN[lExampKey[i]], rExampN[rExampKey[i]], false, + lExampVal[lExampKey[i]], rExampVal[rExampKey[i]]) + } + } + } + // examples were removed. + if len(lExampKey) > len(rExampKey) { + for i := range lExampKey { + if i < len(rExampKey) && lExampKey[i] != rExampKey[i] { + CreateChange(changes, Modified, v3.ExamplesLabel, + lExampN[lExampKey[i]], rExampN[rExampKey[i]], false, + lExampVal[lExampKey[i]], rExampVal[rExampKey[i]]) + } + if i >= len(rExampKey) { + CreateChange(changes, ObjectRemoved, v3.ExamplesLabel, + lExampN[lExampKey[i]], nil, false, + lExampVal[lExampKey[i]], nil) + } + } + } + + // examples were added + if len(lExampKey) < len(rExampKey) { + for i := range rExampKey { + if i < len(lExampKey) && lExampKey[i] != rExampKey[i] { + CreateChange(changes, Modified, v3.ExamplesLabel, + lExampN[lExampKey[i]], rExampN[rExampKey[i]], false, + lExampVal[lExampKey[i]], rExampVal[rExampKey[i]]) + } + if i >= len(lExampKey) { + CreateChange(changes, ObjectAdded, v3.ExamplesLabel, + nil, rExampN[rExampKey[i]], false, + nil, rExampVal[rExampKey[i]]) + } + } + } +} + +func extractSchemaChanges( + lSchema []low.ValueReference[*base.SchemaProxy], + rSchema []low.ValueReference[*base.SchemaProxy], + label string, + sc *[]*SchemaChanges, + changes *[]*Change, + done chan bool) { + + // if there is nothing here, there is nothing to do. + if lSchema == nil && rSchema == nil { + done <- true + return + } + + x := "%x" + // create hash key maps to check equality + lKeys := make([]string, 0, len(lSchema)) + rKeys := make([]string, 0, len(rSchema)) + lEntities := make(map[string]*base.SchemaProxy) + rEntities := make(map[string]*base.SchemaProxy) + for h := range lSchema { + q := lSchema[h].Value + z := fmt.Sprintf(x, q.Hash()) + lKeys = append(lKeys, z) + lEntities[z] = q + + } + for h := range rSchema { + q := rSchema[h].Value + z := fmt.Sprintf(x, q.Hash()) + rKeys = append(rKeys, z) + rEntities[z] = q + + } + + // sort slices so that like for like is all sequenced. + sort.Strings(lKeys) + sort.Strings(rKeys) + + // check for identical lengths + if len(lKeys) == len(rKeys) { + for w := range lKeys { + // keys are different, which means there are changes. + if lKeys[w] != rKeys[w] { + *sc = append(*sc, CompareSchemas(lEntities[lKeys[w]], rEntities[rKeys[w]])) + } + } + } + + // things were removed + if len(lKeys) > len(rKeys) { + for w := range lKeys { + if w < len(rKeys) && lKeys[w] != rKeys[w] { + *sc = append(*sc, CompareSchemas(lEntities[lKeys[w]], rEntities[rKeys[w]])) + } + if w >= len(rKeys) { + CreateChange(changes, ObjectRemoved, label, + lEntities[lKeys[w]].GetValueNode(), nil, true, lEntities[lKeys[w]], nil) + } + } + } + + // things were added + if len(rKeys) > len(lKeys) { + for w := range rKeys { + if w < len(lKeys) && rKeys[w] != lKeys[w] { + *sc = append(*sc, CompareSchemas(lEntities[lKeys[w]], rEntities[rKeys[w]])) + } + if w >= len(lKeys) { + CreateChange(changes, ObjectAdded, label, + nil, rEntities[rKeys[w]].GetValueNode(), false, nil, rEntities[rKeys[w]]) + } + } + } + done <- true +} diff --git a/vendor/github.com/pb33f/libopenapi/what-changed/model/scopes.go b/vendor/github.com/pb33f/libopenapi/what-changed/model/scopes.go new file mode 100644 index 0000000000..b9608463bd --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/what-changed/model/scopes.go @@ -0,0 +1,76 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package model + +import ( + "github.com/pb33f/libopenapi/datamodel/low" + "github.com/pb33f/libopenapi/datamodel/low/v2" + v3 "github.com/pb33f/libopenapi/datamodel/low/v3" +) + +// ScopesChanges represents changes between two Swagger Scopes Objects +type ScopesChanges struct { + *PropertyChanges + ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"` +} + +// GetAllChanges returns a slice of all changes made between Scopes objects +func (s *ScopesChanges) GetAllChanges() []*Change { + var changes []*Change + changes = append(changes, s.Changes...) + if s.ExtensionChanges != nil { + changes = append(changes, s.ExtensionChanges.GetAllChanges()...) + } + return changes +} + +// TotalChanges returns the total changes found between two Swagger Scopes objects. +func (s *ScopesChanges) TotalChanges() int { + c := s.PropertyChanges.TotalChanges() + if s.ExtensionChanges != nil { + c += s.ExtensionChanges.TotalChanges() + } + return c +} + +// TotalBreakingChanges returns the total number of breaking changes between two Swagger Scopes objects. +func (s *ScopesChanges) TotalBreakingChanges() int { + return s.PropertyChanges.TotalBreakingChanges() +} + +// CompareScopes compares a left and right Swagger Scopes objects for changes. If anything is found, returns +// a pointer to ScopesChanges, or returns nil if nothing is found. +func CompareScopes(l, r *v2.Scopes) *ScopesChanges { + if low.AreEqual(l, r) { + return nil + } + var changes []*Change + for v := range l.Values { + if r != nil && r.FindScope(v.Value) == nil { + CreateChange(&changes, ObjectRemoved, v3.Scopes, + l.Values[v].ValueNode, nil, true, + v.Value, nil) + continue + } + if r != nil && r.FindScope(v.Value) != nil { + if l.Values[v].Value != r.FindScope(v.Value).Value { + CreateChange(&changes, Modified, v3.Scopes, + l.Values[v].ValueNode, r.FindScope(v.Value).ValueNode, true, + l.Values[v].Value, r.FindScope(v.Value).Value) + } + } + } + for v := range r.Values { + if l != nil && l.FindScope(v.Value) == nil { + CreateChange(&changes, ObjectAdded, v3.Scopes, + nil, r.Values[v].ValueNode, false, + nil, v.Value) + } + } + + sc := new(ScopesChanges) + sc.PropertyChanges = NewPropertyChanges(changes) + sc.ExtensionChanges = CompareExtensions(l.Extensions, r.Extensions) + return sc +} diff --git a/vendor/github.com/pb33f/libopenapi/what-changed/model/security_requirement.go b/vendor/github.com/pb33f/libopenapi/what-changed/model/security_requirement.go new file mode 100644 index 0000000000..06f392e306 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/what-changed/model/security_requirement.go @@ -0,0 +1,150 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package model + +import ( + "github.com/pb33f/libopenapi/datamodel/low" + "github.com/pb33f/libopenapi/datamodel/low/base" + "github.com/pb33f/libopenapi/datamodel/low/v3" + "gopkg.in/yaml.v3" +) + +// SecurityRequirementChanges represents changes found between two SecurityRequirement Objects. +type SecurityRequirementChanges struct { + *PropertyChanges +} + +// GetAllChanges returns a slice of all changes made between SecurityRequirement objects +func (s *SecurityRequirementChanges) GetAllChanges() []*Change { + return s.Changes +} + +// TotalChanges returns the total number of changes between two SecurityRequirement Objects. +func (s *SecurityRequirementChanges) TotalChanges() int { + return s.PropertyChanges.TotalChanges() +} + +// TotalBreakingChanges returns the total number of breaking changes between two SecurityRequirement Objects. +func (s *SecurityRequirementChanges) TotalBreakingChanges() int { + return s.PropertyChanges.TotalBreakingChanges() +} + +// CompareSecurityRequirement compares left and right SecurityRequirement objects for changes. If anything +// is found, then a pointer to SecurityRequirementChanges is returned, otherwise nil. +func CompareSecurityRequirement(l, r *base.SecurityRequirement) *SecurityRequirementChanges { + + var changes []*Change + sc := new(SecurityRequirementChanges) + + if low.AreEqual(l, r) { + return nil + } + checkSecurityRequirement(l.Requirements.Value, r.Requirements.Value, &changes) + sc.PropertyChanges = NewPropertyChanges(changes) + return sc +} + +func removedSecurityRequirement(vn *yaml.Node, name string, changes *[]*Change) { + CreateChange(changes, ObjectRemoved, v3.SecurityLabel, + vn, nil, true, name, nil) +} + +func addedSecurityRequirement(vn *yaml.Node, name string, changes *[]*Change) { + CreateChange(changes, ObjectAdded, v3.SecurityLabel, + nil, vn, false, nil, name) +} + +// tricky to do this correctly, this is my solution. +func checkSecurityRequirement(lSec, rSec map[low.KeyReference[string]]low.ValueReference[[]low.ValueReference[string]], + changes *[]*Change) { + + lKeys := make([]string, len(lSec)) + rKeys := make([]string, len(rSec)) + lValues := make(map[string]low.ValueReference[[]low.ValueReference[string]]) + rValues := make(map[string]low.ValueReference[[]low.ValueReference[string]]) + var n, z int + for i := range lSec { + lKeys[n] = i.Value + lValues[i.Value] = lSec[i] + n++ + } + for i := range rSec { + rKeys[z] = i.Value + rValues[i.Value] = rSec[i] + z++ + } + + for z = range lKeys { + if z < len(rKeys) { + if _, ok := rValues[lKeys[z]]; !ok { + removedSecurityRequirement(lValues[lKeys[z]].ValueNode, lKeys[z], changes) + continue + } + + lValue := lValues[lKeys[z]].Value + rValue := rValues[lKeys[z]].Value + + // check if actual values match up + lRoleKeys := make([]string, len(lValue)) + rRoleKeys := make([]string, len(rValue)) + lRoleValues := make(map[string]low.ValueReference[string]) + rRoleValues := make(map[string]low.ValueReference[string]) + var t, k int + for i := range lValue { + lRoleKeys[t] = lValue[i].Value + lRoleValues[lValue[i].Value] = lValue[i] + t++ + } + for i := range rValue { + rRoleKeys[k] = rValue[i].Value + rRoleValues[rValue[i].Value] = rValue[i] + k++ + } + + for t = range lRoleKeys { + if t < len(rRoleKeys) { + if _, ok := rRoleValues[lRoleKeys[t]]; !ok { + removedSecurityRequirement(lRoleValues[lRoleKeys[t]].ValueNode, lRoleKeys[t], changes) + continue + } + } + if t >= len(rRoleKeys) { + if _, ok := rRoleValues[lRoleKeys[t]]; !ok { + removedSecurityRequirement(lRoleValues[lRoleKeys[t]].ValueNode, lRoleKeys[t], changes) + } + } + } + for t = range rRoleKeys { + if t < len(lRoleKeys) { + if _, ok := lRoleValues[rRoleKeys[t]]; !ok { + addedSecurityRequirement(rRoleValues[rRoleKeys[t]].ValueNode, rRoleKeys[t], changes) + continue + } + } + if t >= len(lRoleKeys) { + addedSecurityRequirement(rRoleValues[rRoleKeys[t]].ValueNode, rRoleKeys[t], changes) + } + } + + } + if z >= len(rKeys) { + if _, ok := rValues[lKeys[z]]; !ok { + removedSecurityRequirement(lValues[lKeys[z]].ValueNode, lKeys[z], changes) + } + } + } + for z = range rKeys { + if z < len(lKeys) { + if _, ok := lValues[rKeys[z]]; !ok { + addedSecurityRequirement(rValues[rKeys[z]].ValueNode, rKeys[z], changes) + continue + } + } + if z >= len(lKeys) { + if _, ok := lValues[rKeys[z]]; !ok { + addedSecurityRequirement(rValues[rKeys[z]].ValueNode, rKeys[z], changes) + } + } + } +} diff --git a/vendor/github.com/pb33f/libopenapi/what-changed/model/security_scheme.go b/vendor/github.com/pb33f/libopenapi/what-changed/model/security_scheme.go new file mode 100644 index 0000000000..218f9265f7 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/what-changed/model/security_scheme.go @@ -0,0 +1,181 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package model + +import ( + "github.com/pb33f/libopenapi/datamodel/low" + "github.com/pb33f/libopenapi/datamodel/low/v2" + "github.com/pb33f/libopenapi/datamodel/low/v3" + "reflect" +) + +// SecuritySchemeChanges represents changes made between Swagger or OpenAPI SecurityScheme Objects. +type SecuritySchemeChanges struct { + *PropertyChanges + ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"` + + // OpenAPI Version + OAuthFlowChanges *OAuthFlowsChanges `json:"oAuthFlow,omitempty" yaml:"oAuthFlow,omitempty"` + + // Swagger Version + ScopesChanges *ScopesChanges `json:"scopes,omitempty" yaml:"scopes,omitempty"` +} + +// GetAllChanges returns a slice of all changes made between SecurityRequirement objects +func (ss *SecuritySchemeChanges) GetAllChanges() []*Change { + var changes []*Change + changes = append(changes, ss.Changes...) + if ss.OAuthFlowChanges != nil { + changes = append(changes, ss.OAuthFlowChanges.GetAllChanges()...) + } + if ss.ScopesChanges != nil { + changes = append(changes, ss.ScopesChanges.GetAllChanges()...) + } + if ss.ExtensionChanges != nil { + changes = append(changes, ss.ExtensionChanges.GetAllChanges()...) + } + return changes +} + +// TotalChanges represents total changes found between two Swagger or OpenAPI SecurityScheme instances. +func (ss *SecuritySchemeChanges) TotalChanges() int { + c := ss.PropertyChanges.TotalChanges() + if ss.OAuthFlowChanges != nil { + c += ss.OAuthFlowChanges.TotalChanges() + } + if ss.ScopesChanges != nil { + c += ss.ScopesChanges.TotalChanges() + } + if ss.ExtensionChanges != nil { + c += ss.ExtensionChanges.TotalChanges() + } + return c +} + +// TotalBreakingChanges returns total number of breaking changes between two SecurityScheme Objects. +func (ss *SecuritySchemeChanges) TotalBreakingChanges() int { + c := ss.PropertyChanges.TotalBreakingChanges() + if ss.OAuthFlowChanges != nil { + c += ss.OAuthFlowChanges.TotalBreakingChanges() + } + if ss.ScopesChanges != nil { + c += ss.ScopesChanges.TotalBreakingChanges() + } + return c +} + +// CompareSecuritySchemesV2 is a Swagger type safe proxy for CompareSecuritySchemes +func CompareSecuritySchemesV2(l, r *v2.SecurityScheme) *SecuritySchemeChanges { + return CompareSecuritySchemes(l, r) +} + +// CompareSecuritySchemesV3 is an OpenAPI type safe proxt for CompareSecuritySchemes +func CompareSecuritySchemesV3(l, r *v3.SecurityScheme) *SecuritySchemeChanges { + return CompareSecuritySchemes(l, r) +} + +// CompareSecuritySchemes compares left and right Swagger or OpenAPI Security Scheme objects for changes. +// If anything is found, returns a pointer to *SecuritySchemeChanges or nil if nothing is found. +func CompareSecuritySchemes(l, r any) *SecuritySchemeChanges { + + var props []*PropertyCheck + var changes []*Change + + sc := new(SecuritySchemeChanges) + if reflect.TypeOf(&v2.SecurityScheme{}) == reflect.TypeOf(l) && + reflect.TypeOf(&v2.SecurityScheme{}) == reflect.TypeOf(r) { + + lSS := l.(*v2.SecurityScheme) + rSS := r.(*v2.SecurityScheme) + + if low.AreEqual(lSS, rSS) { + return nil + } + addPropertyCheck(&props, lSS.Type.ValueNode, rSS.Type.ValueNode, + lSS.Type.Value, rSS.Type.Value, &changes, v3.TypeLabel, true) + + addPropertyCheck(&props, lSS.Description.ValueNode, rSS.Description.ValueNode, + lSS.Description.Value, rSS.Description.Value, &changes, v3.DescriptionLabel, false) + + addPropertyCheck(&props, lSS.Name.ValueNode, rSS.Name.ValueNode, + lSS.Name.Value, rSS.Name.Value, &changes, v3.NameLabel, true) + + addPropertyCheck(&props, lSS.In.ValueNode, rSS.In.ValueNode, + lSS.In.Value, rSS.In.Value, &changes, v3.InLabel, true) + + addPropertyCheck(&props, lSS.Flow.ValueNode, rSS.Flow.ValueNode, + lSS.Flow.Value, rSS.Flow.Value, &changes, v3.FlowLabel, true) + + addPropertyCheck(&props, lSS.AuthorizationUrl.ValueNode, rSS.AuthorizationUrl.ValueNode, + lSS.AuthorizationUrl.Value, rSS.AuthorizationUrl.Value, &changes, v3.AuthorizationUrlLabel, true) + + addPropertyCheck(&props, lSS.TokenUrl.ValueNode, rSS.TokenUrl.ValueNode, + lSS.TokenUrl.Value, rSS.TokenUrl.Value, &changes, v3.TokenUrlLabel, true) + + if !lSS.Scopes.IsEmpty() && !rSS.Scopes.IsEmpty() { + if !low.AreEqual(lSS.Scopes.Value, rSS.Scopes.Value) { + sc.ScopesChanges = CompareScopes(lSS.Scopes.Value, rSS.Scopes.Value) + } + } + if lSS.Scopes.IsEmpty() && !rSS.Scopes.IsEmpty() { + CreateChange(&changes, ObjectAdded, v3.ScopesLabel, + nil, rSS.Scopes.ValueNode, false, nil, rSS.Scopes.Value) + } + if !lSS.Scopes.IsEmpty() && rSS.Scopes.IsEmpty() { + CreateChange(&changes, ObjectRemoved, v3.ScopesLabel, + lSS.Scopes.ValueNode, nil, true, lSS.Scopes.Value, nil) + } + + sc.ExtensionChanges = CompareExtensions(lSS.Extensions, rSS.Extensions) + } + + if reflect.TypeOf(&v3.SecurityScheme{}) == reflect.TypeOf(l) && + reflect.TypeOf(&v3.SecurityScheme{}) == reflect.TypeOf(r) { + + lSS := l.(*v3.SecurityScheme) + rSS := r.(*v3.SecurityScheme) + + if low.AreEqual(lSS, rSS) { + return nil + } + addPropertyCheck(&props, lSS.Type.ValueNode, rSS.Type.ValueNode, + lSS.Type.Value, rSS.Type.Value, &changes, v3.TypeLabel, true) + + addPropertyCheck(&props, lSS.Description.ValueNode, rSS.Description.ValueNode, + lSS.Description.Value, rSS.Description.Value, &changes, v3.DescriptionLabel, false) + + addPropertyCheck(&props, lSS.Name.ValueNode, rSS.Name.ValueNode, + lSS.Name.Value, rSS.Name.Value, &changes, v3.NameLabel, true) + + addPropertyCheck(&props, lSS.In.ValueNode, rSS.In.ValueNode, + lSS.In.Value, rSS.In.Value, &changes, v3.InLabel, true) + + addPropertyCheck(&props, lSS.Scheme.ValueNode, rSS.Scheme.ValueNode, + lSS.Scheme.Value, rSS.Scheme.Value, &changes, v3.SchemeLabel, true) + + addPropertyCheck(&props, lSS.BearerFormat.ValueNode, rSS.BearerFormat.ValueNode, + lSS.BearerFormat.Value, rSS.BearerFormat.Value, &changes, v3.SchemeLabel, false) + + addPropertyCheck(&props, lSS.OpenIdConnectUrl.ValueNode, rSS.OpenIdConnectUrl.ValueNode, + lSS.OpenIdConnectUrl.Value, rSS.OpenIdConnectUrl.Value, &changes, v3.OpenIdConnectUrlLabel, false) + + if !lSS.Flows.IsEmpty() && !rSS.Flows.IsEmpty() { + if !low.AreEqual(lSS.Flows.Value, rSS.Flows.Value) { + sc.OAuthFlowChanges = CompareOAuthFlows(lSS.Flows.Value, rSS.Flows.Value) + } + } + if lSS.Flows.IsEmpty() && !rSS.Flows.IsEmpty() { + CreateChange(&changes, ObjectAdded, v3.FlowsLabel, + nil, rSS.Flows.ValueNode, false, nil, rSS.Flows.Value) + } + if !lSS.Flows.IsEmpty() && rSS.Flows.IsEmpty() { + CreateChange(&changes, ObjectRemoved, v3.ScopesLabel, + lSS.Flows.ValueNode, nil, true, lSS.Flows.Value, nil) + } + sc.ExtensionChanges = CompareExtensions(lSS.Extensions, rSS.Extensions) + } + CheckProperties(props) + sc.PropertyChanges = NewPropertyChanges(changes) + return sc +} diff --git a/vendor/github.com/pb33f/libopenapi/what-changed/model/server.go b/vendor/github.com/pb33f/libopenapi/what-changed/model/server.go new file mode 100644 index 0000000000..8266dde635 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/what-changed/model/server.go @@ -0,0 +1,82 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package model + +import ( + "github.com/pb33f/libopenapi/datamodel/low" + "github.com/pb33f/libopenapi/datamodel/low/v3" +) + +// ServerChanges represents changes found between two OpenAPI Server Objects +type ServerChanges struct { + *PropertyChanges + ServerVariableChanges map[string]*ServerVariableChanges `json:"serverVariables,omitempty" yaml:"serverVariables,omitempty"` +} + +// GetAllChanges returns a slice of all changes made between SecurityRequirement objects +func (s *ServerChanges) GetAllChanges() []*Change { + var changes []*Change + changes = append(changes, s.Changes...) + for k := range s.ServerVariableChanges { + changes = append(changes, s.ServerVariableChanges[k].GetAllChanges()...) + } + return changes +} + +// TotalChanges returns total changes found between two OpenAPI Server Objects +func (s *ServerChanges) TotalChanges() int { + c := s.PropertyChanges.TotalChanges() + for k := range s.ServerVariableChanges { + c += s.ServerVariableChanges[k].TotalChanges() + } + return c +} + +// TotalBreakingChanges returns the total number of breaking changes found between two OpenAPI Server objects. +func (s *ServerChanges) TotalBreakingChanges() int { + c := s.PropertyChanges.TotalBreakingChanges() + for k := range s.ServerVariableChanges { + c += s.ServerVariableChanges[k].TotalBreakingChanges() + } + return c +} + +// CompareServers compares two OpenAPI Server objects for any changes. If anything is found, returns a pointer +// to a ServerChanges instance, or returns nil if nothing is found. +func CompareServers(l, r *v3.Server) *ServerChanges { + if low.AreEqual(l, r) { + return nil + } + var changes []*Change + var props []*PropertyCheck + + // URL + props = append(props, &PropertyCheck{ + LeftNode: l.URL.ValueNode, + RightNode: r.URL.ValueNode, + Label: v3.URLLabel, + Changes: &changes, + Breaking: true, + Original: l, + New: r, + }) + // Description + props = append(props, &PropertyCheck{ + LeftNode: l.Description.ValueNode, + RightNode: r.Description.ValueNode, + Label: v3.DescriptionLabel, + Changes: &changes, + Breaking: false, + Original: l, + New: r, + }) + + CheckProperties(props) + sc := new(ServerChanges) + sc.PropertyChanges = NewPropertyChanges(changes) + sc.ServerVariableChanges = CheckMapForChanges(l.Variables.Value, r.Variables.Value, + &changes, v3.VariablesLabel, CompareServerVariables) + + return sc +} diff --git a/vendor/github.com/pb33f/libopenapi/what-changed/model/server_variable.go b/vendor/github.com/pb33f/libopenapi/what-changed/model/server_variable.go new file mode 100644 index 0000000000..74a2b7ee44 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/what-changed/model/server_variable.go @@ -0,0 +1,82 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package model + +import ( + "github.com/pb33f/libopenapi/datamodel/low" + "github.com/pb33f/libopenapi/datamodel/low/v3" +) + +// ServerVariableChanges represents changes found between two OpenAPI ServerVariable Objects +type ServerVariableChanges struct { + *PropertyChanges +} + +// GetAllChanges returns a slice of all changes made between SecurityRequirement objects +func (s *ServerVariableChanges) GetAllChanges() []*Change { + return s.Changes +} + +// CompareServerVariables compares a left and right OpenAPI ServerVariable object for changes. +// If anything is found, returns a pointer to a ServerVariableChanges instance, otherwise returns nil. +func CompareServerVariables(l, r *v3.ServerVariable) *ServerVariableChanges { + if low.AreEqual(l, r) { + return nil + } + + var props []*PropertyCheck + var changes []*Change + + lValues := make(map[string]low.NodeReference[string]) + rValues := make(map[string]low.NodeReference[string]) + for i := range l.Enum { + lValues[l.Enum[i].Value] = l.Enum[i] + } + for i := range r.Enum { + rValues[r.Enum[i].Value] = r.Enum[i] + } + for k := range lValues { + if _, ok := rValues[k]; !ok { + CreateChange(&changes, ObjectRemoved, v3.EnumLabel, + lValues[k].ValueNode, nil, true, + lValues[k].Value, nil) + continue + } + } + for k := range rValues { + if _, ok := lValues[k]; !ok { + CreateChange(&changes, ObjectAdded, v3.EnumLabel, + lValues[k].ValueNode, rValues[k].ValueNode, false, + lValues[k].Value, rValues[k].Value) + } + } + + // default + props = append(props, &PropertyCheck{ + LeftNode: l.Default.ValueNode, + RightNode: r.Default.ValueNode, + Label: v3.DefaultLabel, + Changes: &changes, + Breaking: true, + Original: l, + New: r, + }) + + // description + props = append(props, &PropertyCheck{ + LeftNode: l.Description.ValueNode, + RightNode: r.Description.ValueNode, + Label: v3.DescriptionLabel, + Changes: &changes, + Breaking: false, + Original: l, + New: r, + }) + + // check everything. + CheckProperties(props) + sc := new(ServerVariableChanges) + sc.PropertyChanges = NewPropertyChanges(changes) + return sc +} diff --git a/vendor/github.com/pb33f/libopenapi/what-changed/model/tags.go b/vendor/github.com/pb33f/libopenapi/what-changed/model/tags.go new file mode 100644 index 0000000000..106c9c3b91 --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/what-changed/model/tags.go @@ -0,0 +1,150 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package model + +import ( + "github.com/pb33f/libopenapi/datamodel/low" + "github.com/pb33f/libopenapi/datamodel/low/base" + "github.com/pb33f/libopenapi/datamodel/low/v3" +) + +// TagChanges represents changes made to the Tags object of an OpenAPI document. +type TagChanges struct { + *PropertyChanges + ExternalDocs *ExternalDocChanges `json:"externalDocs,omitempty" yaml:"externalDocs,omitempty"` + ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"` +} + +// GetAllChanges returns a slice of all changes made between Tag objects +func (t *TagChanges) GetAllChanges() []*Change { + var changes []*Change + changes = append(changes, t.Changes...) + if t.ExternalDocs != nil { + changes = append(changes, t.ExternalDocs.GetAllChanges()...) + } + if t.ExtensionChanges != nil { + changes = append(changes, t.ExtensionChanges.GetAllChanges()...) + } + return changes +} + +// TotalChanges returns a count of everything that changed within tags. +func (t *TagChanges) TotalChanges() int { + c := t.PropertyChanges.TotalChanges() + if t.ExternalDocs != nil { + c += t.ExternalDocs.TotalChanges() + } + if t.ExtensionChanges != nil { + c += t.ExtensionChanges.TotalChanges() + } + return c +} + +// TotalBreakingChanges returns the number of breaking changes made by Tags +func (t *TagChanges) TotalBreakingChanges() int { + return t.PropertyChanges.TotalBreakingChanges() +} + +// CompareTags will compare a left (original) and a right (new) slice of ValueReference nodes for +// any changes between them. If there are changes, a pointer to TagChanges is returned, if not then +// nil is returned instead. +func CompareTags(l, r []low.ValueReference[*base.Tag]) []*TagChanges { + + var tagResults []*TagChanges + + // look at the original and then look through the new. + seenLeft := make(map[string]*low.ValueReference[*base.Tag]) + seenRight := make(map[string]*low.ValueReference[*base.Tag]) + for i := range l { + h := l[i] + seenLeft[l[i].Value.Name.Value] = &h + } + for i := range r { + h := r[i] + seenRight[r[i].Value.Name.Value] = &h + } + + //var changes []*Change + + // check for removals, modifications and moves + for i := range seenLeft { + tc := new(TagChanges) + var changes []*Change + + CheckForObjectAdditionOrRemoval[*base.Tag](seenLeft, seenRight, i, &changes, false, true) + + // if the existing tag exists, let's check it. + if seenRight[i] != nil { + + var props []*PropertyCheck + + // Name + props = append(props, &PropertyCheck{ + LeftNode: seenLeft[i].Value.Name.ValueNode, + RightNode: seenRight[i].Value.Name.ValueNode, + Label: v3.NameLabel, + Changes: &changes, + Breaking: true, + Original: seenLeft[i].Value, + New: seenRight[i].Value, + }) + + // Description + props = append(props, &PropertyCheck{ + LeftNode: seenLeft[i].Value.Description.ValueNode, + RightNode: seenRight[i].Value.Description.ValueNode, + Label: v3.DescriptionLabel, + Changes: &changes, + Breaking: false, + Original: seenLeft[i].Value, + New: seenRight[i].Value, + }) + + // check properties + CheckProperties(props) + + // compare external docs + if !seenLeft[i].Value.ExternalDocs.IsEmpty() && !seenRight[i].Value.ExternalDocs.IsEmpty() { + tc.ExternalDocs = CompareExternalDocs(seenLeft[i].Value.ExternalDocs.Value, + seenRight[i].Value.ExternalDocs.Value) + } + if seenLeft[i].Value.ExternalDocs.IsEmpty() && !seenRight[i].Value.ExternalDocs.IsEmpty() { + CreateChange(&changes, ObjectAdded, v3.ExternalDocsLabel, nil, seenRight[i].GetValueNode(), + false, nil, seenRight[i].Value.ExternalDocs.Value) + } + if !seenLeft[i].Value.ExternalDocs.IsEmpty() && seenRight[i].Value.ExternalDocs.IsEmpty() { + CreateChange(&changes, ObjectRemoved, v3.ExternalDocsLabel, seenLeft[i].GetValueNode(), nil, + false, seenLeft[i].Value.ExternalDocs.Value, nil) + } + + // check extensions + tc.ExtensionChanges = CompareExtensions(seenLeft[i].Value.Extensions, seenRight[i].Value.Extensions) + tc.PropertyChanges = NewPropertyChanges(changes) + if tc.TotalChanges() > 0 { + tagResults = append(tagResults, tc) + } + continue + } + + if len(changes) > 0 { + tc.PropertyChanges = NewPropertyChanges(changes) + tagResults = append(tagResults, tc) + } + + } + for i := range seenRight { + if seenLeft[i] == nil { + tc := new(TagChanges) + var changes []*Change + + CreateChange(&changes, ObjectAdded, i, nil, seenRight[i].GetValueNode(), + false, nil, seenRight[i].GetValue()) + + tc.PropertyChanges = NewPropertyChanges(changes) + tagResults = append(tagResults, tc) + + } + } + return tagResults +} diff --git a/vendor/github.com/pb33f/libopenapi/what-changed/model/xml.go b/vendor/github.com/pb33f/libopenapi/what-changed/model/xml.go new file mode 100644 index 0000000000..624e9301af --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/what-changed/model/xml.go @@ -0,0 +1,114 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package model + +import ( + "github.com/pb33f/libopenapi/datamodel/low/base" + v3 "github.com/pb33f/libopenapi/datamodel/low/v3" +) + +// XMLChanges represents changes made to the XML object of an OpenAPI document. +type XMLChanges struct { + *PropertyChanges + ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"` +} + +// GetAllChanges returns a slice of all changes made between XML objects +func (x *XMLChanges) GetAllChanges() []*Change { + var changes []*Change + changes = append(changes, x.Changes...) + if x.ExtensionChanges != nil { + changes = append(changes, x.ExtensionChanges.GetAllChanges()...) + } + return changes +} + +// TotalChanges returns a count of everything that was changed within an XML object. +func (x *XMLChanges) TotalChanges() int { + c := x.PropertyChanges.TotalChanges() + if x.ExtensionChanges != nil { + c += x.ExtensionChanges.TotalChanges() + } + return c +} + +// TotalBreakingChanges returns the number of breaking changes made by the XML object. +func (x *XMLChanges) TotalBreakingChanges() int { + return x.PropertyChanges.TotalBreakingChanges() +} + +// CompareXML will compare a left (original) and a right (new) XML instance, and check for +// any changes between them. If changes are found, the function returns a pointer to XMLChanges, +// otherwise, if nothing changed - it will return nil +func CompareXML(l, r *base.XML) *XMLChanges { + xc := new(XMLChanges) + var changes []*Change + var props []*PropertyCheck + + // Name (breaking change) + props = append(props, &PropertyCheck{ + LeftNode: l.Name.ValueNode, + RightNode: r.Name.ValueNode, + Label: v3.NameLabel, + Changes: &changes, + Breaking: true, + Original: l, + New: r, + }) + + // Namespace (breaking change) + props = append(props, &PropertyCheck{ + LeftNode: l.Namespace.ValueNode, + RightNode: r.Namespace.ValueNode, + Label: v3.NamespaceLabel, + Changes: &changes, + Breaking: true, + Original: l, + New: r, + }) + + // Prefix (breaking change) + props = append(props, &PropertyCheck{ + LeftNode: l.Prefix.ValueNode, + RightNode: r.Prefix.ValueNode, + Label: v3.PrefixLabel, + Changes: &changes, + Breaking: true, + Original: l, + New: r, + }) + + // Attribute (breaking change) + props = append(props, &PropertyCheck{ + LeftNode: l.Attribute.ValueNode, + RightNode: r.Attribute.ValueNode, + Label: v3.AttributeLabel, + Changes: &changes, + Breaking: true, + Original: l, + New: r, + }) + + // Wrapped (breaking change) + props = append(props, &PropertyCheck{ + LeftNode: l.Wrapped.ValueNode, + RightNode: r.Wrapped.ValueNode, + Label: v3.WrappedLabel, + Changes: &changes, + Breaking: true, + Original: l, + New: r, + }) + + // check properties + CheckProperties(props) + + // check extensions + xc.ExtensionChanges = CheckExtensions(l, r) + xc.PropertyChanges = NewPropertyChanges(changes) + if xc.TotalChanges() <= 0 { + return nil + } + return xc +} diff --git a/vendor/github.com/pb33f/libopenapi/what-changed/what_changed.go b/vendor/github.com/pb33f/libopenapi/what-changed/what_changed.go new file mode 100644 index 0000000000..d076a7ca8c --- /dev/null +++ b/vendor/github.com/pb33f/libopenapi/what-changed/what_changed.go @@ -0,0 +1,36 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +// Package what_changed +// +// what changed is a feature that performs an accurate and deep analysis of what has changed between two OpenAPI +// documents. The report generated outlines every single change made between two specifications (left and right) +// rendered in the document hierarchy, so exploring it is the same as exploring the document model. +// +// There are two main functions, one of generating a report for Swagger documents (OpenAPI 2) +// And OpenAPI 3+ documents. +// +// This package uses a combined model for OpenAPI and Swagger changes, it does not break them out into separate +// versions like the datamodel package. The reason for this is to prevent sprawl across versions and to provide +// a single API and model for any application that wants to use this feature. +package what_changed + +import ( + "github.com/pb33f/libopenapi/datamodel/low/v2" + "github.com/pb33f/libopenapi/datamodel/low/v3" + "github.com/pb33f/libopenapi/what-changed/model" +) + +// CompareOpenAPIDocuments will compare left (original) and right (updated) OpenAPI 3+ documents and extract every change +// made across the entire specification. The report outlines every property changed, everything that was added, +// or removed and which of those changes were breaking. +func CompareOpenAPIDocuments(original, updated *v3.Document) *model.DocumentChanges { + return model.CompareDocuments(original, updated) +} + +// CompareSwaggerDocuments will compare left (original) and a right (updated) Swagger documents and extract every change +// made across the entire specification. The report outlines every property changes, everything that was added, +// or removed and which of those changes were breaking. +func CompareSwaggerDocuments(original, updated *v2.Swagger) *model.DocumentChanges { + return model.CompareDocuments(original, updated) +} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/collectors/collectors.go b/vendor/github.com/prometheus/client_golang/prometheus/collectors/collectors.go new file mode 100644 index 0000000000..f4c92913a5 --- /dev/null +++ b/vendor/github.com/prometheus/client_golang/prometheus/collectors/collectors.go @@ -0,0 +1,40 @@ +// Copyright 2021 The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package collectors provides implementations of prometheus.Collector to +// conveniently collect process and Go-related metrics. +package collectors + +import "github.com/prometheus/client_golang/prometheus" + +// NewBuildInfoCollector returns a collector collecting a single metric +// "go_build_info" with the constant value 1 and three labels "path", "version", +// and "checksum". Their label values contain the main module path, version, and +// checksum, respectively. The labels will only have meaningful values if the +// binary is built with Go module support and from source code retrieved from +// the source repository (rather than the local file system). This is usually +// accomplished by building from outside of GOPATH, specifying the full address +// of the main package, e.g. "GO111MODULE=on go run +// github.com/prometheus/client_golang/examples/random". If built without Go +// module support, all label values will be "unknown". If built with Go module +// support but using the source code from the local file system, the "path" will +// be set appropriately, but "checksum" will be empty and "version" will be +// "(devel)". +// +// This collector uses only the build information for the main module. See +// https://github.com/povilasv/prommod for an example of a collector for the +// module dependencies. +func NewBuildInfoCollector() prometheus.Collector { + //nolint:staticcheck // Ignore SA1019 until v2. + return prometheus.NewBuildInfoCollector() +} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/collectors/dbstats_collector.go b/vendor/github.com/prometheus/client_golang/prometheus/collectors/dbstats_collector.go new file mode 100644 index 0000000000..d5a7279fb9 --- /dev/null +++ b/vendor/github.com/prometheus/client_golang/prometheus/collectors/dbstats_collector.go @@ -0,0 +1,119 @@ +// Copyright 2021 The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package collectors + +import ( + "database/sql" + + "github.com/prometheus/client_golang/prometheus" +) + +type dbStatsCollector struct { + db *sql.DB + + maxOpenConnections *prometheus.Desc + + openConnections *prometheus.Desc + inUseConnections *prometheus.Desc + idleConnections *prometheus.Desc + + waitCount *prometheus.Desc + waitDuration *prometheus.Desc + maxIdleClosed *prometheus.Desc + maxIdleTimeClosed *prometheus.Desc + maxLifetimeClosed *prometheus.Desc +} + +// NewDBStatsCollector returns a collector that exports metrics about the given *sql.DB. +// See https://golang.org/pkg/database/sql/#DBStats for more information on stats. +func NewDBStatsCollector(db *sql.DB, dbName string) prometheus.Collector { + fqName := func(name string) string { + return "go_sql_" + name + } + return &dbStatsCollector{ + db: db, + maxOpenConnections: prometheus.NewDesc( + fqName("max_open_connections"), + "Maximum number of open connections to the database.", + nil, prometheus.Labels{"db_name": dbName}, + ), + openConnections: prometheus.NewDesc( + fqName("open_connections"), + "The number of established connections both in use and idle.", + nil, prometheus.Labels{"db_name": dbName}, + ), + inUseConnections: prometheus.NewDesc( + fqName("in_use_connections"), + "The number of connections currently in use.", + nil, prometheus.Labels{"db_name": dbName}, + ), + idleConnections: prometheus.NewDesc( + fqName("idle_connections"), + "The number of idle connections.", + nil, prometheus.Labels{"db_name": dbName}, + ), + waitCount: prometheus.NewDesc( + fqName("wait_count_total"), + "The total number of connections waited for.", + nil, prometheus.Labels{"db_name": dbName}, + ), + waitDuration: prometheus.NewDesc( + fqName("wait_duration_seconds_total"), + "The total time blocked waiting for a new connection.", + nil, prometheus.Labels{"db_name": dbName}, + ), + maxIdleClosed: prometheus.NewDesc( + fqName("max_idle_closed_total"), + "The total number of connections closed due to SetMaxIdleConns.", + nil, prometheus.Labels{"db_name": dbName}, + ), + maxIdleTimeClosed: prometheus.NewDesc( + fqName("max_idle_time_closed_total"), + "The total number of connections closed due to SetConnMaxIdleTime.", + nil, prometheus.Labels{"db_name": dbName}, + ), + maxLifetimeClosed: prometheus.NewDesc( + fqName("max_lifetime_closed_total"), + "The total number of connections closed due to SetConnMaxLifetime.", + nil, prometheus.Labels{"db_name": dbName}, + ), + } +} + +// Describe implements Collector. +func (c *dbStatsCollector) Describe(ch chan<- *prometheus.Desc) { + ch <- c.maxOpenConnections + ch <- c.openConnections + ch <- c.inUseConnections + ch <- c.idleConnections + ch <- c.waitCount + ch <- c.waitDuration + ch <- c.maxIdleClosed + ch <- c.maxLifetimeClosed + ch <- c.maxIdleTimeClosed +} + +// Collect implements Collector. +func (c *dbStatsCollector) Collect(ch chan<- prometheus.Metric) { + stats := c.db.Stats() + ch <- prometheus.MustNewConstMetric(c.maxOpenConnections, prometheus.GaugeValue, float64(stats.MaxOpenConnections)) + ch <- prometheus.MustNewConstMetric(c.openConnections, prometheus.GaugeValue, float64(stats.OpenConnections)) + ch <- prometheus.MustNewConstMetric(c.inUseConnections, prometheus.GaugeValue, float64(stats.InUse)) + ch <- prometheus.MustNewConstMetric(c.idleConnections, prometheus.GaugeValue, float64(stats.Idle)) + ch <- prometheus.MustNewConstMetric(c.waitCount, prometheus.CounterValue, float64(stats.WaitCount)) + ch <- prometheus.MustNewConstMetric(c.waitDuration, prometheus.CounterValue, stats.WaitDuration.Seconds()) + ch <- prometheus.MustNewConstMetric(c.maxIdleClosed, prometheus.CounterValue, float64(stats.MaxIdleClosed)) + ch <- prometheus.MustNewConstMetric(c.maxLifetimeClosed, prometheus.CounterValue, float64(stats.MaxLifetimeClosed)) + ch <- prometheus.MustNewConstMetric(c.maxIdleTimeClosed, prometheus.CounterValue, float64(stats.MaxIdleTimeClosed)) +} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/collectors/expvar_collector.go b/vendor/github.com/prometheus/client_golang/prometheus/collectors/expvar_collector.go new file mode 100644 index 0000000000..3aa8d0590b --- /dev/null +++ b/vendor/github.com/prometheus/client_golang/prometheus/collectors/expvar_collector.go @@ -0,0 +1,57 @@ +// Copyright 2021 The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package collectors + +import "github.com/prometheus/client_golang/prometheus" + +// NewExpvarCollector returns a newly allocated expvar Collector. +// +// An expvar Collector collects metrics from the expvar interface. It provides a +// quick way to expose numeric values that are already exported via expvar as +// Prometheus metrics. Note that the data models of expvar and Prometheus are +// fundamentally different, and that the expvar Collector is inherently slower +// than native Prometheus metrics. Thus, the expvar Collector is probably great +// for experiments and prototying, but you should seriously consider a more +// direct implementation of Prometheus metrics for monitoring production +// systems. +// +// The exports map has the following meaning: +// +// The keys in the map correspond to expvar keys, i.e. for every expvar key you +// want to export as Prometheus metric, you need an entry in the exports +// map. The descriptor mapped to each key describes how to export the expvar +// value. It defines the name and the help string of the Prometheus metric +// proxying the expvar value. The type will always be Untyped. +// +// For descriptors without variable labels, the expvar value must be a number or +// a bool. The number is then directly exported as the Prometheus sample +// value. (For a bool, 'false' translates to 0 and 'true' to 1). Expvar values +// that are not numbers or bools are silently ignored. +// +// If the descriptor has one variable label, the expvar value must be an expvar +// map. The keys in the expvar map become the various values of the one +// Prometheus label. The values in the expvar map must be numbers or bools again +// as above. +// +// For descriptors with more than one variable label, the expvar must be a +// nested expvar map, i.e. where the values of the topmost map are maps again +// etc. until a depth is reached that corresponds to the number of labels. The +// leaves of that structure must be numbers or bools as above to serve as the +// sample values. +// +// Anything that does not fit into the scheme above is silently ignored. +func NewExpvarCollector(exports map[string]*prometheus.Desc) prometheus.Collector { + //nolint:staticcheck // Ignore SA1019 until v2. + return prometheus.NewExpvarCollector(exports) +} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/collectors/go_collector_go116.go b/vendor/github.com/prometheus/client_golang/prometheus/collectors/go_collector_go116.go new file mode 100644 index 0000000000..effc57840a --- /dev/null +++ b/vendor/github.com/prometheus/client_golang/prometheus/collectors/go_collector_go116.go @@ -0,0 +1,49 @@ +// Copyright 2021 The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//go:build !go1.17 +// +build !go1.17 + +package collectors + +import "github.com/prometheus/client_golang/prometheus" + +// NewGoCollector returns a collector that exports metrics about the current Go +// process. This includes memory stats. To collect those, runtime.ReadMemStats +// is called. This requires to “stop the world”, which usually only happens for +// garbage collection (GC). Take the following implications into account when +// deciding whether to use the Go collector: +// +// 1. The performance impact of stopping the world is the more relevant the more +// frequently metrics are collected. However, with Go1.9 or later the +// stop-the-world time per metrics collection is very short (~25µs) so that the +// performance impact will only matter in rare cases. However, with older Go +// versions, the stop-the-world duration depends on the heap size and can be +// quite significant (~1.7 ms/GiB as per +// https://go-review.googlesource.com/c/go/+/34937). +// +// 2. During an ongoing GC, nothing else can stop the world. Therefore, if the +// metrics collection happens to coincide with GC, it will only complete after +// GC has finished. Usually, GC is fast enough to not cause problems. However, +// with a very large heap, GC might take multiple seconds, which is enough to +// cause scrape timeouts in common setups. To avoid this problem, the Go +// collector will use the memstats from a previous collection if +// runtime.ReadMemStats takes more than 1s. However, if there are no previously +// collected memstats, or their collection is more than 5m ago, the collection +// will block until runtime.ReadMemStats succeeds. +// +// NOTE: The problem is solved in Go 1.15, see +// https://github.com/golang/go/issues/19812 for the related Go issue. +func NewGoCollector() prometheus.Collector { + return prometheus.NewGoCollector() +} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/collectors/go_collector_latest.go b/vendor/github.com/prometheus/client_golang/prometheus/collectors/go_collector_latest.go new file mode 100644 index 0000000000..2f5616894e --- /dev/null +++ b/vendor/github.com/prometheus/client_golang/prometheus/collectors/go_collector_latest.go @@ -0,0 +1,162 @@ +// Copyright 2021 The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//go:build go1.17 +// +build go1.17 + +package collectors + +import ( + "regexp" + + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/internal" +) + +var ( + // MetricsAll allows all the metrics to be collected from Go runtime. + MetricsAll = GoRuntimeMetricsRule{regexp.MustCompile("/.*")} + // MetricsGC allows only GC metrics to be collected from Go runtime. + // e.g. go_gc_cycles_automatic_gc_cycles_total + // NOTE: This does not include new class of "/cpu/classes/gc/..." metrics. + // Use custom metric rule to access those. + MetricsGC = GoRuntimeMetricsRule{regexp.MustCompile(`^/gc/.*`)} + // MetricsMemory allows only memory metrics to be collected from Go runtime. + // e.g. go_memory_classes_heap_free_bytes + MetricsMemory = GoRuntimeMetricsRule{regexp.MustCompile(`^/memory/.*`)} + // MetricsScheduler allows only scheduler metrics to be collected from Go runtime. + // e.g. go_sched_goroutines_goroutines + MetricsScheduler = GoRuntimeMetricsRule{regexp.MustCompile(`^/sched/.*`)} +) + +// WithGoCollectorMemStatsMetricsDisabled disables metrics that is gathered in runtime.MemStats structure such as: +// +// go_memstats_alloc_bytes +// go_memstats_alloc_bytes_total +// go_memstats_sys_bytes +// go_memstats_lookups_total +// go_memstats_mallocs_total +// go_memstats_frees_total +// go_memstats_heap_alloc_bytes +// go_memstats_heap_sys_bytes +// go_memstats_heap_idle_bytes +// go_memstats_heap_inuse_bytes +// go_memstats_heap_released_bytes +// go_memstats_heap_objects +// go_memstats_stack_inuse_bytes +// go_memstats_stack_sys_bytes +// go_memstats_mspan_inuse_bytes +// go_memstats_mspan_sys_bytes +// go_memstats_mcache_inuse_bytes +// go_memstats_mcache_sys_bytes +// go_memstats_buck_hash_sys_bytes +// go_memstats_gc_sys_bytes +// go_memstats_other_sys_bytes +// go_memstats_next_gc_bytes +// +// so the metrics known from pre client_golang v1.12.0, +// +// NOTE(bwplotka): The above represents runtime.MemStats statistics, but they are +// actually implemented using new runtime/metrics package. (except skipped go_memstats_gc_cpu_fraction +// -- see https://github.com/prometheus/client_golang/issues/842#issuecomment-861812034 for explanation). +// +// Some users might want to disable this on collector level (although you can use scrape relabelling on Prometheus), +// because similar metrics can be now obtained using WithGoCollectorRuntimeMetrics. Note that the semantics of new +// metrics might be different, plus the names can be change over time with different Go version. +// +// NOTE(bwplotka): Changing metric names can be tedious at times as the alerts, recording rules and dashboards have to be adjusted. +// The old metrics are also very useful, with many guides and books written about how to interpret them. +// +// As a result our recommendation would be to stick with MemStats like metrics and enable other runtime/metrics if you are interested +// in advanced insights Go provides. See ExampleGoCollector_WithAdvancedGoMetrics. +func WithGoCollectorMemStatsMetricsDisabled() func(options *internal.GoCollectorOptions) { + return func(o *internal.GoCollectorOptions) { + o.DisableMemStatsLikeMetrics = true + } +} + +// GoRuntimeMetricsRule allow enabling and configuring particular group of runtime/metrics. +// TODO(bwplotka): Consider adding ability to adjust buckets. +type GoRuntimeMetricsRule struct { + // Matcher represents RE2 expression will match the runtime/metrics from https://golang.bg/src/runtime/metrics/description.go + // Use `regexp.MustCompile` or `regexp.Compile` to create this field. + Matcher *regexp.Regexp +} + +// WithGoCollectorRuntimeMetrics allows enabling and configuring particular group of runtime/metrics. +// See the list of metrics https://golang.bg/src/runtime/metrics/description.go (pick the Go version you use there!). +// You can use this option in repeated manner, which will add new rules. The order of rules is important, the last rule +// that matches particular metrics is applied. +func WithGoCollectorRuntimeMetrics(rules ...GoRuntimeMetricsRule) func(options *internal.GoCollectorOptions) { + rs := make([]internal.GoCollectorRule, len(rules)) + for i, r := range rules { + rs[i] = internal.GoCollectorRule{ + Matcher: r.Matcher, + } + } + + return func(o *internal.GoCollectorOptions) { + o.RuntimeMetricRules = append(o.RuntimeMetricRules, rs...) + } +} + +// WithoutGoCollectorRuntimeMetrics allows disabling group of runtime/metrics that you might have added in WithGoCollectorRuntimeMetrics. +// It behaves similarly to WithGoCollectorRuntimeMetrics just with deny-list semantics. +func WithoutGoCollectorRuntimeMetrics(matchers ...*regexp.Regexp) func(options *internal.GoCollectorOptions) { + rs := make([]internal.GoCollectorRule, len(matchers)) + for i, m := range matchers { + rs[i] = internal.GoCollectorRule{ + Matcher: m, + Deny: true, + } + } + + return func(o *internal.GoCollectorOptions) { + o.RuntimeMetricRules = append(o.RuntimeMetricRules, rs...) + } +} + +// GoCollectionOption represents Go collection option flag. +// Deprecated. +type GoCollectionOption uint32 + +const ( + // GoRuntimeMemStatsCollection represents the metrics represented by runtime.MemStats structure. + // Deprecated. Use WithGoCollectorMemStatsMetricsDisabled() function to disable those metrics in the collector. + GoRuntimeMemStatsCollection GoCollectionOption = 1 << iota + // GoRuntimeMetricsCollection is the new set of metrics represented by runtime/metrics package. + // Deprecated. Use WithGoCollectorRuntimeMetrics(GoRuntimeMetricsRule{Matcher: regexp.MustCompile("/.*")}) + // function to enable those metrics in the collector. + GoRuntimeMetricsCollection +) + +// WithGoCollections allows enabling different collections for Go collector on top of base metrics. +// Deprecated. Use WithGoCollectorRuntimeMetrics() and WithGoCollectorMemStatsMetricsDisabled() instead to control metrics. +func WithGoCollections(flags GoCollectionOption) func(options *internal.GoCollectorOptions) { + return func(options *internal.GoCollectorOptions) { + if flags&GoRuntimeMemStatsCollection == 0 { + WithGoCollectorMemStatsMetricsDisabled()(options) + } + + if flags&GoRuntimeMetricsCollection != 0 { + WithGoCollectorRuntimeMetrics(GoRuntimeMetricsRule{Matcher: regexp.MustCompile("/.*")})(options) + } + } +} + +// NewGoCollector returns a collector that exports metrics about the current Go +// process using debug.GCStats (base metrics) and runtime/metrics (both in MemStats style and new ones). +func NewGoCollector(opts ...func(o *internal.GoCollectorOptions)) prometheus.Collector { + //nolint:staticcheck // Ignore SA1019 until v2. + return prometheus.NewGoCollector(opts...) +} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/collectors/process_collector.go b/vendor/github.com/prometheus/client_golang/prometheus/collectors/process_collector.go new file mode 100644 index 0000000000..24558f50a7 --- /dev/null +++ b/vendor/github.com/prometheus/client_golang/prometheus/collectors/process_collector.go @@ -0,0 +1,56 @@ +// Copyright 2021 The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package collectors + +import "github.com/prometheus/client_golang/prometheus" + +// ProcessCollectorOpts defines the behavior of a process metrics collector +// created with NewProcessCollector. +type ProcessCollectorOpts struct { + // PidFn returns the PID of the process the collector collects metrics + // for. It is called upon each collection. By default, the PID of the + // current process is used, as determined on construction time by + // calling os.Getpid(). + PidFn func() (int, error) + // If non-empty, each of the collected metrics is prefixed by the + // provided string and an underscore ("_"). + Namespace string + // If true, any error encountered during collection is reported as an + // invalid metric (see NewInvalidMetric). Otherwise, errors are ignored + // and the collected metrics will be incomplete. (Possibly, no metrics + // will be collected at all.) While that's usually not desired, it is + // appropriate for the common "mix-in" of process metrics, where process + // metrics are nice to have, but failing to collect them should not + // disrupt the collection of the remaining metrics. + ReportErrors bool +} + +// NewProcessCollector returns a collector which exports the current state of +// process metrics including CPU, memory and file descriptor usage as well as +// the process start time. The detailed behavior is defined by the provided +// ProcessCollectorOpts. The zero value of ProcessCollectorOpts creates a +// collector for the current process with an empty namespace string and no error +// reporting. +// +// The collector only works on operating systems with a Linux-style proc +// filesystem and on Microsoft Windows. On other operating systems, it will not +// collect any metrics. +func NewProcessCollector(opts ProcessCollectorOpts) prometheus.Collector { + //nolint:staticcheck // Ignore SA1019 until v2. + return prometheus.NewProcessCollector(prometheus.ProcessCollectorOpts{ + PidFn: opts.PidFn, + Namespace: opts.Namespace, + ReportErrors: opts.ReportErrors, + }) +} diff --git a/vendor/github.com/santhosh-tekuri/jsonschema/v5/.gitignore b/vendor/github.com/santhosh-tekuri/jsonschema/v5/.gitignore new file mode 100644 index 0000000000..3c0af38259 --- /dev/null +++ b/vendor/github.com/santhosh-tekuri/jsonschema/v5/.gitignore @@ -0,0 +1,4 @@ +.vscode +.idea +*.swp +cmd/jv/jv diff --git a/vendor/github.com/santhosh-tekuri/jsonschema/v5/.gitmodules b/vendor/github.com/santhosh-tekuri/jsonschema/v5/.gitmodules new file mode 100644 index 0000000000..314da31c5e --- /dev/null +++ b/vendor/github.com/santhosh-tekuri/jsonschema/v5/.gitmodules @@ -0,0 +1,3 @@ +[submodule "testdata/JSON-Schema-Test-Suite"] + path = testdata/JSON-Schema-Test-Suite + url = https://github.com/json-schema-org/JSON-Schema-Test-Suite.git diff --git a/vendor/github.com/santhosh-tekuri/jsonschema/v5/LICENSE b/vendor/github.com/santhosh-tekuri/jsonschema/v5/LICENSE new file mode 100644 index 0000000000..19dc35b243 --- /dev/null +++ b/vendor/github.com/santhosh-tekuri/jsonschema/v5/LICENSE @@ -0,0 +1,175 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. \ No newline at end of file diff --git a/vendor/github.com/santhosh-tekuri/jsonschema/v5/README.md b/vendor/github.com/santhosh-tekuri/jsonschema/v5/README.md new file mode 100644 index 0000000000..7e9c66724d --- /dev/null +++ b/vendor/github.com/santhosh-tekuri/jsonschema/v5/README.md @@ -0,0 +1,220 @@ +# jsonschema v5.3.0 + +[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) +[![GoDoc](https://godoc.org/github.com/santhosh-tekuri/jsonschema?status.svg)](https://pkg.go.dev/github.com/santhosh-tekuri/jsonschema/v5) +[![Go Report Card](https://goreportcard.com/badge/github.com/santhosh-tekuri/jsonschema/v5)](https://goreportcard.com/report/github.com/santhosh-tekuri/jsonschema/v5) +[![Build Status](https://github.com/santhosh-tekuri/jsonschema/actions/workflows/go.yaml/badge.svg?branch=master)](https://github.com/santhosh-tekuri/jsonschema/actions/workflows/go.yaml) +[![codecov](https://codecov.io/gh/santhosh-tekuri/jsonschema/branch/master/graph/badge.svg?token=JMVj1pFT2l)](https://codecov.io/gh/santhosh-tekuri/jsonschema) + +Package jsonschema provides json-schema compilation and validation. + +[Benchmarks](https://dev.to/vearutop/benchmarking-correctness-and-performance-of-go-json-schema-validators-3247) + +### Features: + - implements + [draft 2020-12](https://json-schema.org/specification-links.html#2020-12), + [draft 2019-09](https://json-schema.org/specification-links.html#draft-2019-09-formerly-known-as-draft-8), + [draft-7](https://json-schema.org/specification-links.html#draft-7), + [draft-6](https://json-schema.org/specification-links.html#draft-6), + [draft-4](https://json-schema.org/specification-links.html#draft-4) + - fully compliant with [JSON-Schema-Test-Suite](https://github.com/json-schema-org/JSON-Schema-Test-Suite), (excluding some optional) + - list of optional tests that are excluded can be found in schema_test.go(variable [skipTests](https://github.com/santhosh-tekuri/jsonschema/blob/master/schema_test.go#L24)) + - validates schemas against meta-schema + - full support of remote references + - support of recursive references between schemas + - detects infinite loop in schemas + - thread safe validation + - rich, intuitive hierarchial error messages with json-pointers to exact location + - supports output formats flag, basic and detailed + - supports enabling format and content Assertions in draft2019-09 or above + - change `Compiler.AssertFormat`, `Compiler.AssertContent` to `true` + - compiled schema can be introspected. easier to develop tools like generating go structs given schema + - supports user-defined keywords via [extensions](https://pkg.go.dev/github.com/santhosh-tekuri/jsonschema/v5/#example-package-Extension) + - implements following formats (supports [user-defined](https://pkg.go.dev/github.com/santhosh-tekuri/jsonschema/v5/#example-package-UserDefinedFormat)) + - date-time, date, time, duration, period (supports leap-second) + - uuid, hostname, email + - ip-address, ipv4, ipv6 + - uri, uriref, uri-template(limited validation) + - json-pointer, relative-json-pointer + - regex, format + - implements following contentEncoding (supports [user-defined](https://pkg.go.dev/github.com/santhosh-tekuri/jsonschema/v5/#example-package-UserDefinedContent)) + - base64 + - implements following contentMediaType (supports [user-defined](https://pkg.go.dev/github.com/santhosh-tekuri/jsonschema/v5/#example-package-UserDefinedContent)) + - application/json + - can load from files/http/https/[string](https://pkg.go.dev/github.com/santhosh-tekuri/jsonschema/v5/#example-package-FromString)/[]byte/io.Reader (supports [user-defined](https://pkg.go.dev/github.com/santhosh-tekuri/jsonschema/v5/#example-package-UserDefinedLoader)) + + +see examples in [godoc](https://pkg.go.dev/github.com/santhosh-tekuri/jsonschema/v5) + +The schema is compiled against the version specified in `$schema` property. +If "$schema" property is missing, it uses latest draft which currently implemented +by this library. + +You can force to use specific version, when `$schema` is missing, as follows: + +```go +compiler := jsonschema.NewCompiler() +compiler.Draft = jsonschema.Draft4 +``` + +This package supports loading json-schema from filePath and fileURL. + +To load json-schema from HTTPURL, add following import: + +```go +import _ "github.com/santhosh-tekuri/jsonschema/v5/httploader" +``` + +## Rich Errors + +The ValidationError returned by Validate method contains detailed context to understand why and where the error is. + +schema.json: +```json +{ + "$ref": "t.json#/definitions/employee" +} +``` + +t.json: +```json +{ + "definitions": { + "employee": { + "type": "string" + } + } +} +``` + +doc.json: +```json +1 +``` + +assuming `err` is the ValidationError returned when `doc.json` validated with `schema.json`, +```go +fmt.Printf("%#v\n", err) // using %#v prints errors hierarchy +``` +Prints: +``` +[I#] [S#] doesn't validate with file:///Users/santhosh/jsonschema/schema.json# + [I#] [S#/$ref] doesn't validate with 'file:///Users/santhosh/jsonschema/t.json#/definitions/employee' + [I#] [S#/definitions/employee/type] expected string, but got number +``` + +Here `I` stands for instance document and `S` stands for schema document. +The json-fragments that caused error in instance and schema documents are represented using json-pointer notation. +Nested causes are printed with indent. + +To output `err` in `flag` output format: +```go +b, _ := json.MarshalIndent(err.FlagOutput(), "", " ") +fmt.Println(string(b)) +``` +Prints: +```json +{ + "valid": false +} +``` +To output `err` in `basic` output format: +```go +b, _ := json.MarshalIndent(err.BasicOutput(), "", " ") +fmt.Println(string(b)) +``` +Prints: +```json +{ + "valid": false, + "errors": [ + { + "keywordLocation": "", + "absoluteKeywordLocation": "file:///Users/santhosh/jsonschema/schema.json#", + "instanceLocation": "", + "error": "doesn't validate with file:///Users/santhosh/jsonschema/schema.json#" + }, + { + "keywordLocation": "/$ref", + "absoluteKeywordLocation": "file:///Users/santhosh/jsonschema/schema.json#/$ref", + "instanceLocation": "", + "error": "doesn't validate with 'file:///Users/santhosh/jsonschema/t.json#/definitions/employee'" + }, + { + "keywordLocation": "/$ref/type", + "absoluteKeywordLocation": "file:///Users/santhosh/jsonschema/t.json#/definitions/employee/type", + "instanceLocation": "", + "error": "expected string, but got number" + } + ] +} +``` +To output `err` in `detailed` output format: +```go +b, _ := json.MarshalIndent(err.DetailedOutput(), "", " ") +fmt.Println(string(b)) +``` +Prints: +```json +{ + "valid": false, + "keywordLocation": "", + "absoluteKeywordLocation": "file:///Users/santhosh/jsonschema/schema.json#", + "instanceLocation": "", + "errors": [ + { + "valid": false, + "keywordLocation": "/$ref", + "absoluteKeywordLocation": "file:///Users/santhosh/jsonschema/schema.json#/$ref", + "instanceLocation": "", + "errors": [ + { + "valid": false, + "keywordLocation": "/$ref/type", + "absoluteKeywordLocation": "file:///Users/santhosh/jsonschema/t.json#/definitions/employee/type", + "instanceLocation": "", + "error": "expected string, but got number" + } + ] + } + ] +} +``` + +## CLI + +to install `go install github.com/santhosh-tekuri/jsonschema/cmd/jv@latest` + +```bash +jv [-draft INT] [-output FORMAT] [-assertformat] [-assertcontent] []... + -assertcontent + enable content assertions with draft >= 2019 + -assertformat + enable format assertions with draft >= 2019 + -draft int + draft used when '$schema' attribute is missing. valid values 4, 5, 7, 2019, 2020 (default 2020) + -output string + output format. valid values flag, basic, detailed +``` + +if no `` arguments are passed, it simply validates the ``. +if `$schema` attribute is missing in schema, it uses latest version. this can be overridden by passing `-draft` flag + +exit-code is 1, if there are any validation errors + +`jv` can also validate yaml files. It also accepts schema from yaml files. + +## Validating YAML Documents + +since yaml supports non-string keys, such yaml documents are rendered as invalid json documents. + +most yaml parser use `map[interface{}]interface{}` for object, +whereas json parser uses `map[string]interface{}`. + +so we need to manually convert them to `map[string]interface{}`. +below code shows such conversion by `toStringKeys` function. + +https://play.golang.org/p/Hhax3MrtD8r + +NOTE: if you are using `gopkg.in/yaml.v3`, then you do not need such conversion. since this library +returns `map[string]interface{}` if all keys are strings. \ No newline at end of file diff --git a/vendor/github.com/santhosh-tekuri/jsonschema/v5/compiler.go b/vendor/github.com/santhosh-tekuri/jsonschema/v5/compiler.go new file mode 100644 index 0000000000..fdb68e6480 --- /dev/null +++ b/vendor/github.com/santhosh-tekuri/jsonschema/v5/compiler.go @@ -0,0 +1,812 @@ +package jsonschema + +import ( + "encoding/json" + "fmt" + "io" + "math/big" + "regexp" + "strconv" + "strings" +) + +// A Compiler represents a json-schema compiler. +type Compiler struct { + // Draft represents the draft used when '$schema' attribute is missing. + // + // This defaults to latest supported draft (currently 2020-12). + Draft *Draft + resources map[string]*resource + + // Extensions is used to register extensions. + extensions map[string]extension + + // ExtractAnnotations tells whether schema annotations has to be extracted + // in compiled Schema or not. + ExtractAnnotations bool + + // LoadURL loads the document at given absolute URL. + // + // If nil, package global LoadURL is used. + LoadURL func(s string) (io.ReadCloser, error) + + // Formats can be registered by adding to this map. Key is format name, + // value is function that knows how to validate that format. + Formats map[string]func(interface{}) bool + + // AssertFormat for specifications >= draft2019-09. + AssertFormat bool + + // Decoders can be registered by adding to this map. Key is encoding name, + // value is function that knows how to decode string in that format. + Decoders map[string]func(string) ([]byte, error) + + // MediaTypes can be registered by adding to this map. Key is mediaType name, + // value is function that knows how to validate that mediaType. + MediaTypes map[string]func([]byte) error + + // AssertContent for specifications >= draft2019-09. + AssertContent bool +} + +// Compile parses json-schema at given url returns, if successful, +// a Schema object that can be used to match against json. +// +// Returned error can be *SchemaError +func Compile(url string) (*Schema, error) { + return NewCompiler().Compile(url) +} + +// MustCompile is like Compile but panics if the url cannot be compiled to *Schema. +// It simplifies safe initialization of global variables holding compiled Schemas. +func MustCompile(url string) *Schema { + return NewCompiler().MustCompile(url) +} + +// CompileString parses and compiles the given schema with given base url. +func CompileString(url, schema string) (*Schema, error) { + c := NewCompiler() + if err := c.AddResource(url, strings.NewReader(schema)); err != nil { + return nil, err + } + return c.Compile(url) +} + +// MustCompileString is like CompileString but panics on error. +// It simplified safe initialization of global variables holding compiled Schema. +func MustCompileString(url, schema string) *Schema { + c := NewCompiler() + if err := c.AddResource(url, strings.NewReader(schema)); err != nil { + panic(err) + } + return c.MustCompile(url) +} + +// NewCompiler returns a json-schema Compiler object. +// if '$schema' attribute is missing, it is treated as draft7. to change this +// behavior change Compiler.Draft value +func NewCompiler() *Compiler { + return &Compiler{ + Draft: latest, + resources: make(map[string]*resource), + Formats: make(map[string]func(interface{}) bool), + Decoders: make(map[string]func(string) ([]byte, error)), + MediaTypes: make(map[string]func([]byte) error), + extensions: make(map[string]extension), + } +} + +// AddResource adds in-memory resource to the compiler. +// +// Note that url must not have fragment +func (c *Compiler) AddResource(url string, r io.Reader) error { + res, err := newResource(url, r) + if err != nil { + return err + } + c.resources[res.url] = res + return nil +} + +// MustCompile is like Compile but panics if the url cannot be compiled to *Schema. +// It simplifies safe initialization of global variables holding compiled Schemas. +func (c *Compiler) MustCompile(url string) *Schema { + s, err := c.Compile(url) + if err != nil { + panic(fmt.Sprintf("jsonschema: %#v", err)) + } + return s +} + +// Compile parses json-schema at given url returns, if successful, +// a Schema object that can be used to match against json. +// +// error returned will be of type *SchemaError +func (c *Compiler) Compile(url string) (*Schema, error) { + // make url absolute + u, err := toAbs(url) + if err != nil { + return nil, &SchemaError{url, err} + } + url = u + + sch, err := c.compileURL(url, nil, "#") + if err != nil { + err = &SchemaError{url, err} + } + return sch, err +} + +func (c *Compiler) findResource(url string) (*resource, error) { + if _, ok := c.resources[url]; !ok { + // load resource + var rdr io.Reader + if sch, ok := vocabSchemas[url]; ok { + rdr = strings.NewReader(sch) + } else { + loadURL := LoadURL + if c.LoadURL != nil { + loadURL = c.LoadURL + } + r, err := loadURL(url) + if err != nil { + return nil, err + } + defer r.Close() + rdr = r + } + if err := c.AddResource(url, rdr); err != nil { + return nil, err + } + } + + r := c.resources[url] + if r.draft != nil { + return r, nil + } + + // set draft + r.draft = c.Draft + if m, ok := r.doc.(map[string]interface{}); ok { + if sch, ok := m["$schema"]; ok { + sch, ok := sch.(string) + if !ok { + return nil, fmt.Errorf("jsonschema: invalid $schema in %s", url) + } + if !isURI(sch) { + return nil, fmt.Errorf("jsonschema: $schema must be uri in %s", url) + } + r.draft = findDraft(sch) + if r.draft == nil { + sch, _ := split(sch) + if sch == url { + return nil, fmt.Errorf("jsonschema: unsupported draft in %s", url) + } + mr, err := c.findResource(sch) + if err != nil { + return nil, err + } + r.draft = mr.draft + } + } + } + + id, err := r.draft.resolveID(r.url, r.doc) + if err != nil { + return nil, err + } + if id != "" { + r.url = id + } + + if err := r.fillSubschemas(c, r); err != nil { + return nil, err + } + + return r, nil +} + +func (c *Compiler) compileURL(url string, stack []schemaRef, ptr string) (*Schema, error) { + // if url points to a draft, return Draft.meta + if d := findDraft(url); d != nil && d.meta != nil { + return d.meta, nil + } + + b, f := split(url) + r, err := c.findResource(b) + if err != nil { + return nil, err + } + return c.compileRef(r, stack, ptr, r, f) +} + +func (c *Compiler) compileRef(r *resource, stack []schemaRef, refPtr string, res *resource, ref string) (*Schema, error) { + base := r.baseURL(res.floc) + ref, err := resolveURL(base, ref) + if err != nil { + return nil, err + } + + u, f := split(ref) + sr := r.findResource(u) + if sr == nil { + // external resource + return c.compileURL(ref, stack, refPtr) + } + + // ensure root resource is always compiled first. + // this is required to get schema.meta from root resource + if r.schema == nil { + r.schema = newSchema(r.url, r.floc, r.draft, r.doc) + if _, err := c.compile(r, nil, schemaRef{"#", r.schema, false}, r); err != nil { + return nil, err + } + } + + sr, err = r.resolveFragment(c, sr, f) + if err != nil { + return nil, err + } + if sr == nil { + return nil, fmt.Errorf("jsonschema: %s not found", ref) + } + + if sr.schema != nil { + if err := checkLoop(stack, schemaRef{refPtr, sr.schema, false}); err != nil { + return nil, err + } + return sr.schema, nil + } + + sr.schema = newSchema(r.url, sr.floc, r.draft, sr.doc) + return c.compile(r, stack, schemaRef{refPtr, sr.schema, false}, sr) +} + +func (c *Compiler) compileDynamicAnchors(r *resource, res *resource) error { + if r.draft.version < 2020 { + return nil + } + + rr := r.listResources(res) + rr = append(rr, res) + for _, sr := range rr { + if m, ok := sr.doc.(map[string]interface{}); ok { + if _, ok := m["$dynamicAnchor"]; ok { + sch, err := c.compileRef(r, nil, "IGNORED", r, sr.floc) + if err != nil { + return err + } + res.schema.dynamicAnchors = append(res.schema.dynamicAnchors, sch) + } + } + } + return nil +} + +func (c *Compiler) compile(r *resource, stack []schemaRef, sref schemaRef, res *resource) (*Schema, error) { + if err := c.compileDynamicAnchors(r, res); err != nil { + return nil, err + } + + switch v := res.doc.(type) { + case bool: + res.schema.Always = &v + return res.schema, nil + default: + return res.schema, c.compileMap(r, stack, sref, res) + } +} + +func (c *Compiler) compileMap(r *resource, stack []schemaRef, sref schemaRef, res *resource) error { + m := res.doc.(map[string]interface{}) + + if err := checkLoop(stack, sref); err != nil { + return err + } + stack = append(stack, sref) + + var s = res.schema + var err error + + if r == res { // root schema + if sch, ok := m["$schema"]; ok { + sch := sch.(string) + if d := findDraft(sch); d != nil { + s.meta = d.meta + } else { + if s.meta, err = c.compileRef(r, stack, "$schema", res, sch); err != nil { + return err + } + } + } + } + + if ref, ok := m["$ref"]; ok { + s.Ref, err = c.compileRef(r, stack, "$ref", res, ref.(string)) + if err != nil { + return err + } + if r.draft.version < 2019 { + // All other properties in a "$ref" object MUST be ignored + return nil + } + } + + if r.draft.version >= 2019 { + if r == res { // root schema + if vocab, ok := m["$vocabulary"]; ok { + for url, reqd := range vocab.(map[string]interface{}) { + if reqd, ok := reqd.(bool); ok && !reqd { + continue + } + if !r.draft.isVocab(url) { + return fmt.Errorf("jsonschema: unsupported vocab %q in %s", url, res) + } + s.vocab = append(s.vocab, url) + } + } else { + s.vocab = r.draft.defaultVocab + } + } + + if ref, ok := m["$recursiveRef"]; ok { + s.RecursiveRef, err = c.compileRef(r, stack, "$recursiveRef", res, ref.(string)) + if err != nil { + return err + } + } + } + if r.draft.version >= 2020 { + if dref, ok := m["$dynamicRef"]; ok { + s.DynamicRef, err = c.compileRef(r, stack, "$dynamicRef", res, dref.(string)) + if err != nil { + return err + } + if dref, ok := dref.(string); ok { + _, frag := split(dref) + if frag != "#" && !strings.HasPrefix(frag, "#/") { + // frag is anchor + s.dynamicRefAnchor = frag[1:] + } + } + } + } + + loadInt := func(pname string) int { + if num, ok := m[pname]; ok { + i, _ := num.(json.Number).Float64() + return int(i) + } + return -1 + } + + loadRat := func(pname string) *big.Rat { + if num, ok := m[pname]; ok { + r, _ := new(big.Rat).SetString(string(num.(json.Number))) + return r + } + return nil + } + + if r.draft.version < 2019 || r.schema.meta.hasVocab("validation") { + if t, ok := m["type"]; ok { + switch t := t.(type) { + case string: + s.Types = []string{t} + case []interface{}: + s.Types = toStrings(t) + } + } + + if e, ok := m["enum"]; ok { + s.Enum = e.([]interface{}) + allPrimitives := true + for _, item := range s.Enum { + switch jsonType(item) { + case "object", "array": + allPrimitives = false + break + } + } + s.enumError = "enum failed" + if allPrimitives { + if len(s.Enum) == 1 { + s.enumError = fmt.Sprintf("value must be %#v", s.Enum[0]) + } else { + strEnum := make([]string, len(s.Enum)) + for i, item := range s.Enum { + strEnum[i] = fmt.Sprintf("%#v", item) + } + s.enumError = fmt.Sprintf("value must be one of %s", strings.Join(strEnum, ", ")) + } + } + } + + s.Minimum = loadRat("minimum") + if exclusive, ok := m["exclusiveMinimum"]; ok { + if exclusive, ok := exclusive.(bool); ok { + if exclusive { + s.Minimum, s.ExclusiveMinimum = nil, s.Minimum + } + } else { + s.ExclusiveMinimum = loadRat("exclusiveMinimum") + } + } + + s.Maximum = loadRat("maximum") + if exclusive, ok := m["exclusiveMaximum"]; ok { + if exclusive, ok := exclusive.(bool); ok { + if exclusive { + s.Maximum, s.ExclusiveMaximum = nil, s.Maximum + } + } else { + s.ExclusiveMaximum = loadRat("exclusiveMaximum") + } + } + + s.MultipleOf = loadRat("multipleOf") + + s.MinProperties, s.MaxProperties = loadInt("minProperties"), loadInt("maxProperties") + + if req, ok := m["required"]; ok { + s.Required = toStrings(req.([]interface{})) + } + + s.MinItems, s.MaxItems = loadInt("minItems"), loadInt("maxItems") + + if unique, ok := m["uniqueItems"]; ok { + s.UniqueItems = unique.(bool) + } + + s.MinLength, s.MaxLength = loadInt("minLength"), loadInt("maxLength") + + if pattern, ok := m["pattern"]; ok { + s.Pattern = regexp.MustCompile(pattern.(string)) + } + + if r.draft.version >= 2019 { + s.MinContains, s.MaxContains = loadInt("minContains"), loadInt("maxContains") + if s.MinContains == -1 { + s.MinContains = 1 + } + + if deps, ok := m["dependentRequired"]; ok { + deps := deps.(map[string]interface{}) + s.DependentRequired = make(map[string][]string, len(deps)) + for pname, pvalue := range deps { + s.DependentRequired[pname] = toStrings(pvalue.([]interface{})) + } + } + } + } + + compile := func(stack []schemaRef, ptr string) (*Schema, error) { + return c.compileRef(r, stack, ptr, res, r.url+res.floc+"/"+ptr) + } + + loadSchema := func(pname string, stack []schemaRef) (*Schema, error) { + if _, ok := m[pname]; ok { + return compile(stack, escape(pname)) + } + return nil, nil + } + + loadSchemas := func(pname string, stack []schemaRef) ([]*Schema, error) { + if pvalue, ok := m[pname]; ok { + pvalue := pvalue.([]interface{}) + schemas := make([]*Schema, len(pvalue)) + for i := range pvalue { + sch, err := compile(stack, escape(pname)+"/"+strconv.Itoa(i)) + if err != nil { + return nil, err + } + schemas[i] = sch + } + return schemas, nil + } + return nil, nil + } + + if r.draft.version < 2019 || r.schema.meta.hasVocab("applicator") { + if s.Not, err = loadSchema("not", stack); err != nil { + return err + } + if s.AllOf, err = loadSchemas("allOf", stack); err != nil { + return err + } + if s.AnyOf, err = loadSchemas("anyOf", stack); err != nil { + return err + } + if s.OneOf, err = loadSchemas("oneOf", stack); err != nil { + return err + } + + if props, ok := m["properties"]; ok { + props := props.(map[string]interface{}) + s.Properties = make(map[string]*Schema, len(props)) + for pname := range props { + s.Properties[pname], err = compile(nil, "properties/"+escape(pname)) + if err != nil { + return err + } + } + } + + if regexProps, ok := m["regexProperties"]; ok { + s.RegexProperties = regexProps.(bool) + } + + if patternProps, ok := m["patternProperties"]; ok { + patternProps := patternProps.(map[string]interface{}) + s.PatternProperties = make(map[*regexp.Regexp]*Schema, len(patternProps)) + for pattern := range patternProps { + s.PatternProperties[regexp.MustCompile(pattern)], err = compile(nil, "patternProperties/"+escape(pattern)) + if err != nil { + return err + } + } + } + + if additionalProps, ok := m["additionalProperties"]; ok { + switch additionalProps := additionalProps.(type) { + case bool: + s.AdditionalProperties = additionalProps + case map[string]interface{}: + s.AdditionalProperties, err = compile(nil, "additionalProperties") + if err != nil { + return err + } + } + } + + if deps, ok := m["dependencies"]; ok { + deps := deps.(map[string]interface{}) + s.Dependencies = make(map[string]interface{}, len(deps)) + for pname, pvalue := range deps { + switch pvalue := pvalue.(type) { + case []interface{}: + s.Dependencies[pname] = toStrings(pvalue) + default: + s.Dependencies[pname], err = compile(stack, "dependencies/"+escape(pname)) + if err != nil { + return err + } + } + } + } + + if r.draft.version >= 6 { + if s.PropertyNames, err = loadSchema("propertyNames", nil); err != nil { + return err + } + if s.Contains, err = loadSchema("contains", nil); err != nil { + return err + } + } + + if r.draft.version >= 7 { + if m["if"] != nil { + if s.If, err = loadSchema("if", stack); err != nil { + return err + } + if s.Then, err = loadSchema("then", stack); err != nil { + return err + } + if s.Else, err = loadSchema("else", stack); err != nil { + return err + } + } + } + if r.draft.version >= 2019 { + if deps, ok := m["dependentSchemas"]; ok { + deps := deps.(map[string]interface{}) + s.DependentSchemas = make(map[string]*Schema, len(deps)) + for pname := range deps { + s.DependentSchemas[pname], err = compile(stack, "dependentSchemas/"+escape(pname)) + if err != nil { + return err + } + } + } + } + + if r.draft.version >= 2020 { + if s.PrefixItems, err = loadSchemas("prefixItems", nil); err != nil { + return err + } + if s.Items2020, err = loadSchema("items", nil); err != nil { + return err + } + } else { + if items, ok := m["items"]; ok { + switch items.(type) { + case []interface{}: + s.Items, err = loadSchemas("items", nil) + if err != nil { + return err + } + if additionalItems, ok := m["additionalItems"]; ok { + switch additionalItems := additionalItems.(type) { + case bool: + s.AdditionalItems = additionalItems + case map[string]interface{}: + s.AdditionalItems, err = compile(nil, "additionalItems") + if err != nil { + return err + } + } + } + default: + s.Items, err = compile(nil, "items") + if err != nil { + return err + } + } + } + } + + } + + // unevaluatedXXX keywords were in "applicator" vocab in 2019, but moved to new vocab "unevaluated" in 2020 + if (r.draft.version == 2019 && r.schema.meta.hasVocab("applicator")) || (r.draft.version >= 2020 && r.schema.meta.hasVocab("unevaluated")) { + if s.UnevaluatedProperties, err = loadSchema("unevaluatedProperties", nil); err != nil { + return err + } + if s.UnevaluatedItems, err = loadSchema("unevaluatedItems", nil); err != nil { + return err + } + if r.draft.version >= 2020 { + // any item in an array that passes validation of the contains schema is considered "evaluated" + s.ContainsEval = true + } + } + + if format, ok := m["format"]; ok { + s.Format = format.(string) + if r.draft.version < 2019 || c.AssertFormat || r.schema.meta.hasVocab("format-assertion") { + if format, ok := c.Formats[s.Format]; ok { + s.format = format + } else { + s.format, _ = Formats[s.Format] + } + } + } + + if c.ExtractAnnotations { + if title, ok := m["title"]; ok { + s.Title = title.(string) + } + if description, ok := m["description"]; ok { + s.Description = description.(string) + } + s.Default = m["default"] + } + + if r.draft.version >= 6 { + if c, ok := m["const"]; ok { + s.Constant = []interface{}{c} + } + } + + if r.draft.version >= 7 { + if encoding, ok := m["contentEncoding"]; ok { + s.ContentEncoding = encoding.(string) + if decoder, ok := c.Decoders[s.ContentEncoding]; ok { + s.decoder = decoder + } else { + s.decoder, _ = Decoders[s.ContentEncoding] + } + } + if mediaType, ok := m["contentMediaType"]; ok { + s.ContentMediaType = mediaType.(string) + if mediaType, ok := c.MediaTypes[s.ContentMediaType]; ok { + s.mediaType = mediaType + } else { + s.mediaType, _ = MediaTypes[s.ContentMediaType] + } + if s.ContentSchema, err = loadSchema("contentSchema", stack); err != nil { + return err + } + } + if c.ExtractAnnotations { + if comment, ok := m["$comment"]; ok { + s.Comment = comment.(string) + } + if readOnly, ok := m["readOnly"]; ok { + s.ReadOnly = readOnly.(bool) + } + if writeOnly, ok := m["writeOnly"]; ok { + s.WriteOnly = writeOnly.(bool) + } + if examples, ok := m["examples"]; ok { + s.Examples = examples.([]interface{}) + } + } + } + + if r.draft.version >= 2019 { + if !c.AssertContent { + s.decoder = nil + s.mediaType = nil + s.ContentSchema = nil + } + if c.ExtractAnnotations { + if deprecated, ok := m["deprecated"]; ok { + s.Deprecated = deprecated.(bool) + } + } + } + + for name, ext := range c.extensions { + es, err := ext.compiler.Compile(CompilerContext{c, r, stack, res}, m) + if err != nil { + return err + } + if es != nil { + if s.Extensions == nil { + s.Extensions = make(map[string]ExtSchema) + } + s.Extensions[name] = es + } + } + + return nil +} + +func (c *Compiler) validateSchema(r *resource, v interface{}, vloc string) error { + validate := func(meta *Schema) error { + if meta == nil { + return nil + } + return meta.validateValue(v, vloc) + } + + if err := validate(r.draft.meta); err != nil { + return err + } + for _, ext := range c.extensions { + if err := validate(ext.meta); err != nil { + return err + } + } + return nil +} + +func toStrings(arr []interface{}) []string { + s := make([]string, len(arr)) + for i, v := range arr { + s[i] = v.(string) + } + return s +} + +// SchemaRef captures schema and the path referring to it. +type schemaRef struct { + path string // relative-json-pointer to schema + schema *Schema // target schema + discard bool // true when scope left +} + +func (sr schemaRef) String() string { + return fmt.Sprintf("(%s)%v", sr.path, sr.schema) +} + +func checkLoop(stack []schemaRef, sref schemaRef) error { + for _, ref := range stack { + if ref.schema == sref.schema { + return infiniteLoopError(stack, sref) + } + } + return nil +} + +func keywordLocation(stack []schemaRef, path string) string { + var loc string + for _, ref := range stack[1:] { + loc += "/" + ref.path + } + if path != "" { + loc = loc + "/" + path + } + return loc +} diff --git a/vendor/github.com/santhosh-tekuri/jsonschema/v5/content.go b/vendor/github.com/santhosh-tekuri/jsonschema/v5/content.go new file mode 100644 index 0000000000..7570b8b5a9 --- /dev/null +++ b/vendor/github.com/santhosh-tekuri/jsonschema/v5/content.go @@ -0,0 +1,29 @@ +package jsonschema + +import ( + "encoding/base64" + "encoding/json" +) + +// Decoders is a registry of functions, which know how to decode +// string encoded in specific format. +// +// New Decoders can be registered by adding to this map. Key is encoding name, +// value is function that knows how to decode string in that format. +var Decoders = map[string]func(string) ([]byte, error){ + "base64": base64.StdEncoding.DecodeString, +} + +// MediaTypes is a registry of functions, which know how to validate +// whether the bytes represent data of that mediaType. +// +// New mediaTypes can be registered by adding to this map. Key is mediaType name, +// value is function that knows how to validate that mediaType. +var MediaTypes = map[string]func([]byte) error{ + "application/json": validateJSON, +} + +func validateJSON(b []byte) error { + var v interface{} + return json.Unmarshal(b, &v) +} diff --git a/vendor/github.com/santhosh-tekuri/jsonschema/v5/doc.go b/vendor/github.com/santhosh-tekuri/jsonschema/v5/doc.go new file mode 100644 index 0000000000..a124262a51 --- /dev/null +++ b/vendor/github.com/santhosh-tekuri/jsonschema/v5/doc.go @@ -0,0 +1,49 @@ +/* +Package jsonschema provides json-schema compilation and validation. + +Features: + - implements draft 2020-12, 2019-09, draft-7, draft-6, draft-4 + - fully compliant with JSON-Schema-Test-Suite, (excluding some optional) + - list of optional tests that are excluded can be found in schema_test.go(variable skipTests) + - validates schemas against meta-schema + - full support of remote references + - support of recursive references between schemas + - detects infinite loop in schemas + - thread safe validation + - rich, intuitive hierarchial error messages with json-pointers to exact location + - supports output formats flag, basic and detailed + - supports enabling format and content Assertions in draft2019-09 or above + - change Compiler.AssertFormat, Compiler.AssertContent to true + - compiled schema can be introspected. easier to develop tools like generating go structs given schema + - supports user-defined keywords via extensions + - implements following formats (supports user-defined) + - date-time, date, time, duration (supports leap-second) + - uuid, hostname, email + - ip-address, ipv4, ipv6 + - uri, uriref, uri-template(limited validation) + - json-pointer, relative-json-pointer + - regex, format + - implements following contentEncoding (supports user-defined) + - base64 + - implements following contentMediaType (supports user-defined) + - application/json + - can load from files/http/https/string/[]byte/io.Reader (supports user-defined) + +The schema is compiled against the version specified in "$schema" property. +If "$schema" property is missing, it uses latest draft which currently implemented +by this library. + +You can force to use specific draft, when "$schema" is missing, as follows: + + compiler := jsonschema.NewCompiler() + compiler.Draft = jsonschema.Draft4 + +This package supports loading json-schema from filePath and fileURL. + +To load json-schema from HTTPURL, add following import: + + import _ "github.com/santhosh-tekuri/jsonschema/v5/httploader" + +you can validate yaml documents. see https://play.golang.org/p/sJy1qY7dXgA +*/ +package jsonschema diff --git a/vendor/github.com/santhosh-tekuri/jsonschema/v5/draft.go b/vendor/github.com/santhosh-tekuri/jsonschema/v5/draft.go new file mode 100644 index 0000000000..3ee412db9f --- /dev/null +++ b/vendor/github.com/santhosh-tekuri/jsonschema/v5/draft.go @@ -0,0 +1,1453 @@ +package jsonschema + +import ( + "fmt" + "strconv" + "strings" +) + +// A Draft represents json-schema draft +type Draft struct { + version int + meta *Schema + id string // property name used to represent schema id. + boolSchema bool // is boolean valid schema + vocab []string // built-in vocab + defaultVocab []string // vocabs when $vocabulary is not used + subschemas map[string]position +} + +func (d *Draft) URL() string { + switch d.version { + case 2020: + return "https://json-schema.org/draft/2020-12/schema" + case 2019: + return "https://json-schema.org/draft/2019-09/schema" + case 7: + return "https://json-schema.org/draft-07/schema" + case 6: + return "https://json-schema.org/draft-06/schema" + case 4: + return "https://json-schema.org/draft-04/schema" + } + return "" +} + +func (d *Draft) String() string { + return fmt.Sprintf("Draft%d", d.version) +} + +func (d *Draft) loadMeta(url, schema string) { + c := NewCompiler() + c.AssertFormat = true + if err := c.AddResource(url, strings.NewReader(schema)); err != nil { + panic(err) + } + d.meta = c.MustCompile(url) + d.meta.meta = d.meta +} + +func (d *Draft) getID(sch interface{}) string { + m, ok := sch.(map[string]interface{}) + if !ok { + return "" + } + if _, ok := m["$ref"]; ok && d.version <= 7 { + // $ref prevents a sibling id from changing the base uri + return "" + } + v, ok := m[d.id] + if !ok { + return "" + } + id, ok := v.(string) + if !ok { + return "" + } + return id +} + +func (d *Draft) resolveID(base string, sch interface{}) (string, error) { + id, _ := split(d.getID(sch)) // strip fragment + if id == "" { + return "", nil + } + url, err := resolveURL(base, id) + url, _ = split(url) // strip fragment + return url, err +} + +func (d *Draft) anchors(sch interface{}) []string { + m, ok := sch.(map[string]interface{}) + if !ok { + return nil + } + + var anchors []string + + // before draft2019, anchor is specified in id + _, f := split(d.getID(m)) + if f != "#" { + anchors = append(anchors, f[1:]) + } + + if v, ok := m["$anchor"]; ok && d.version >= 2019 { + anchors = append(anchors, v.(string)) + } + if v, ok := m["$dynamicAnchor"]; ok && d.version >= 2020 { + anchors = append(anchors, v.(string)) + } + return anchors +} + +// listSubschemas collects subschemas in r into rr. +func (d *Draft) listSubschemas(r *resource, base string, rr map[string]*resource) error { + add := func(loc string, sch interface{}) error { + url, err := d.resolveID(base, sch) + if err != nil { + return err + } + floc := r.floc + "/" + loc + sr := &resource{url: url, floc: floc, doc: sch} + rr[floc] = sr + + base := base + if url != "" { + base = url + } + return d.listSubschemas(sr, base, rr) + } + + sch, ok := r.doc.(map[string]interface{}) + if !ok { + return nil + } + for kw, pos := range d.subschemas { + v, ok := sch[kw] + if !ok { + continue + } + if pos&self != 0 { + switch v := v.(type) { + case map[string]interface{}: + if err := add(kw, v); err != nil { + return err + } + case bool: + if d.boolSchema { + if err := add(kw, v); err != nil { + return err + } + } + } + } + if pos&item != 0 { + if v, ok := v.([]interface{}); ok { + for i, item := range v { + if err := add(kw+"/"+strconv.Itoa(i), item); err != nil { + return err + } + } + } + } + if pos&prop != 0 { + if v, ok := v.(map[string]interface{}); ok { + for pname, pval := range v { + if err := add(kw+"/"+escape(pname), pval); err != nil { + return err + } + } + } + } + } + return nil +} + +// isVocab tells whether url is built-in vocab. +func (d *Draft) isVocab(url string) bool { + for _, v := range d.vocab { + if url == v { + return true + } + } + return false +} + +type position uint + +const ( + self position = 1 << iota + prop + item +) + +// supported drafts +var ( + Draft4 = &Draft{version: 4, id: "id", boolSchema: false} + Draft6 = &Draft{version: 6, id: "$id", boolSchema: true} + Draft7 = &Draft{version: 7, id: "$id", boolSchema: true} + Draft2019 = &Draft{ + version: 2019, + id: "$id", + boolSchema: true, + vocab: []string{ + "https://json-schema.org/draft/2019-09/vocab/core", + "https://json-schema.org/draft/2019-09/vocab/applicator", + "https://json-schema.org/draft/2019-09/vocab/validation", + "https://json-schema.org/draft/2019-09/vocab/meta-data", + "https://json-schema.org/draft/2019-09/vocab/format", + "https://json-schema.org/draft/2019-09/vocab/content", + }, + defaultVocab: []string{ + "https://json-schema.org/draft/2019-09/vocab/core", + "https://json-schema.org/draft/2019-09/vocab/applicator", + "https://json-schema.org/draft/2019-09/vocab/validation", + }, + } + Draft2020 = &Draft{ + version: 2020, + id: "$id", + boolSchema: true, + vocab: []string{ + "https://json-schema.org/draft/2020-12/vocab/core", + "https://json-schema.org/draft/2020-12/vocab/applicator", + "https://json-schema.org/draft/2020-12/vocab/unevaluated", + "https://json-schema.org/draft/2020-12/vocab/validation", + "https://json-schema.org/draft/2020-12/vocab/meta-data", + "https://json-schema.org/draft/2020-12/vocab/format-annotation", + "https://json-schema.org/draft/2020-12/vocab/format-assertion", + "https://json-schema.org/draft/2020-12/vocab/content", + }, + defaultVocab: []string{ + "https://json-schema.org/draft/2020-12/vocab/core", + "https://json-schema.org/draft/2020-12/vocab/applicator", + "https://json-schema.org/draft/2020-12/vocab/unevaluated", + "https://json-schema.org/draft/2020-12/vocab/validation", + }, + } + + latest = Draft2020 +) + +func findDraft(url string) *Draft { + if strings.HasPrefix(url, "http://") { + url = "https://" + strings.TrimPrefix(url, "http://") + } + if strings.HasSuffix(url, "#") || strings.HasSuffix(url, "#/") { + url = url[:strings.IndexByte(url, '#')] + } + switch url { + case "https://json-schema.org/schema": + return latest + case "https://json-schema.org/draft/2020-12/schema": + return Draft2020 + case "https://json-schema.org/draft/2019-09/schema": + return Draft2019 + case "https://json-schema.org/draft-07/schema": + return Draft7 + case "https://json-schema.org/draft-06/schema": + return Draft6 + case "https://json-schema.org/draft-04/schema": + return Draft4 + } + return nil +} + +func init() { + subschemas := map[string]position{ + // type agnostic + "definitions": prop, + "not": self, + "allOf": item, + "anyOf": item, + "oneOf": item, + // object + "properties": prop, + "additionalProperties": self, + "patternProperties": prop, + // array + "items": self | item, + "additionalItems": self, + "dependencies": prop, + } + Draft4.subschemas = clone(subschemas) + + subschemas["propertyNames"] = self + subschemas["contains"] = self + Draft6.subschemas = clone(subschemas) + + subschemas["if"] = self + subschemas["then"] = self + subschemas["else"] = self + Draft7.subschemas = clone(subschemas) + + subschemas["$defs"] = prop + subschemas["dependentSchemas"] = prop + subschemas["unevaluatedProperties"] = self + subschemas["unevaluatedItems"] = self + Draft2019.subschemas = clone(subschemas) + + subschemas["prefixItems"] = item + Draft2020.subschemas = clone(subschemas) + + Draft4.loadMeta("http://json-schema.org/draft-04/schema", `{ + "$schema": "http://json-schema.org/draft-04/schema#", + "description": "Core schema meta-schema", + "definitions": { + "schemaArray": { + "type": "array", + "minItems": 1, + "items": { "$ref": "#" } + }, + "positiveInteger": { + "type": "integer", + "minimum": 0 + }, + "positiveIntegerDefault0": { + "allOf": [ { "$ref": "#/definitions/positiveInteger" }, { "default": 0 } ] + }, + "simpleTypes": { + "enum": [ "array", "boolean", "integer", "null", "number", "object", "string" ] + }, + "stringArray": { + "type": "array", + "items": { "type": "string" }, + "minItems": 1, + "uniqueItems": true + } + }, + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uriref" + }, + "$schema": { + "type": "string", + "format": "uri" + }, + "title": { + "type": "string" + }, + "description": { + "type": "string" + }, + "default": {}, + "multipleOf": { + "type": "number", + "minimum": 0, + "exclusiveMinimum": true + }, + "maximum": { + "type": "number" + }, + "exclusiveMaximum": { + "type": "boolean", + "default": false + }, + "minimum": { + "type": "number" + }, + "exclusiveMinimum": { + "type": "boolean", + "default": false + }, + "maxLength": { "$ref": "#/definitions/positiveInteger" }, + "minLength": { "$ref": "#/definitions/positiveIntegerDefault0" }, + "pattern": { + "type": "string", + "format": "regex" + }, + "additionalItems": { + "anyOf": [ + { "type": "boolean" }, + { "$ref": "#" } + ], + "default": {} + }, + "items": { + "anyOf": [ + { "$ref": "#" }, + { "$ref": "#/definitions/schemaArray" } + ], + "default": {} + }, + "maxItems": { "$ref": "#/definitions/positiveInteger" }, + "minItems": { "$ref": "#/definitions/positiveIntegerDefault0" }, + "uniqueItems": { + "type": "boolean", + "default": false + }, + "maxProperties": { "$ref": "#/definitions/positiveInteger" }, + "minProperties": { "$ref": "#/definitions/positiveIntegerDefault0" }, + "required": { "$ref": "#/definitions/stringArray" }, + "additionalProperties": { + "anyOf": [ + { "type": "boolean" }, + { "$ref": "#" } + ], + "default": {} + }, + "definitions": { + "type": "object", + "additionalProperties": { "$ref": "#" }, + "default": {} + }, + "properties": { + "type": "object", + "additionalProperties": { "$ref": "#" }, + "default": {} + }, + "patternProperties": { + "type": "object", + "regexProperties": true, + "additionalProperties": { "$ref": "#" }, + "default": {} + }, + "regexProperties": { "type": "boolean" }, + "dependencies": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { "$ref": "#" }, + { "$ref": "#/definitions/stringArray" } + ] + } + }, + "enum": { + "type": "array", + "minItems": 1, + "uniqueItems": true + }, + "type": { + "anyOf": [ + { "$ref": "#/definitions/simpleTypes" }, + { + "type": "array", + "items": { "$ref": "#/definitions/simpleTypes" }, + "minItems": 1, + "uniqueItems": true + } + ] + }, + "allOf": { "$ref": "#/definitions/schemaArray" }, + "anyOf": { "$ref": "#/definitions/schemaArray" }, + "oneOf": { "$ref": "#/definitions/schemaArray" }, + "not": { "$ref": "#" }, + "format": { "type": "string" }, + "$ref": { "type": "string" } + }, + "dependencies": { + "exclusiveMaximum": [ "maximum" ], + "exclusiveMinimum": [ "minimum" ] + }, + "default": {} + }`) + Draft6.loadMeta("http://json-schema.org/draft-06/schema", `{ + "$schema": "http://json-schema.org/draft-06/schema#", + "$id": "http://json-schema.org/draft-06/schema#", + "title": "Core schema meta-schema", + "definitions": { + "schemaArray": { + "type": "array", + "minItems": 1, + "items": { "$ref": "#" } + }, + "nonNegativeInteger": { + "type": "integer", + "minimum": 0 + }, + "nonNegativeIntegerDefault0": { + "allOf": [ + { "$ref": "#/definitions/nonNegativeInteger" }, + { "default": 0 } + ] + }, + "simpleTypes": { + "enum": [ + "array", + "boolean", + "integer", + "null", + "number", + "object", + "string" + ] + }, + "stringArray": { + "type": "array", + "items": { "type": "string" }, + "uniqueItems": true, + "default": [] + } + }, + "type": ["object", "boolean"], + "properties": { + "$id": { + "type": "string", + "format": "uri-reference" + }, + "$schema": { + "type": "string", + "format": "uri" + }, + "$ref": { + "type": "string", + "format": "uri-reference" + }, + "title": { + "type": "string" + }, + "description": { + "type": "string" + }, + "default": {}, + "multipleOf": { + "type": "number", + "exclusiveMinimum": 0 + }, + "maximum": { + "type": "number" + }, + "exclusiveMaximum": { + "type": "number" + }, + "minimum": { + "type": "number" + }, + "exclusiveMinimum": { + "type": "number" + }, + "maxLength": { "$ref": "#/definitions/nonNegativeInteger" }, + "minLength": { "$ref": "#/definitions/nonNegativeIntegerDefault0" }, + "pattern": { + "type": "string", + "format": "regex" + }, + "additionalItems": { "$ref": "#" }, + "items": { + "anyOf": [ + { "$ref": "#" }, + { "$ref": "#/definitions/schemaArray" } + ], + "default": {} + }, + "maxItems": { "$ref": "#/definitions/nonNegativeInteger" }, + "minItems": { "$ref": "#/definitions/nonNegativeIntegerDefault0" }, + "uniqueItems": { + "type": "boolean", + "default": false + }, + "contains": { "$ref": "#" }, + "maxProperties": { "$ref": "#/definitions/nonNegativeInteger" }, + "minProperties": { "$ref": "#/definitions/nonNegativeIntegerDefault0" }, + "required": { "$ref": "#/definitions/stringArray" }, + "additionalProperties": { "$ref": "#" }, + "definitions": { + "type": "object", + "additionalProperties": { "$ref": "#" }, + "default": {} + }, + "properties": { + "type": "object", + "additionalProperties": { "$ref": "#" }, + "default": {} + }, + "patternProperties": { + "type": "object", + "regexProperties": true, + "additionalProperties": { "$ref": "#" }, + "default": {} + }, + "dependencies": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { "$ref": "#" }, + { "$ref": "#/definitions/stringArray" } + ] + } + }, + "propertyNames": { "$ref": "#" }, + "const": {}, + "enum": { + "type": "array", + "minItems": 1, + "uniqueItems": true + }, + "type": { + "anyOf": [ + { "$ref": "#/definitions/simpleTypes" }, + { + "type": "array", + "items": { "$ref": "#/definitions/simpleTypes" }, + "minItems": 1, + "uniqueItems": true + } + ] + }, + "format": { "type": "string" }, + "allOf": { "$ref": "#/definitions/schemaArray" }, + "anyOf": { "$ref": "#/definitions/schemaArray" }, + "oneOf": { "$ref": "#/definitions/schemaArray" }, + "not": { "$ref": "#" } + }, + "default": {} + }`) + Draft7.loadMeta("http://json-schema.org/draft-07/schema", `{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "http://json-schema.org/draft-07/schema#", + "title": "Core schema meta-schema", + "definitions": { + "schemaArray": { + "type": "array", + "minItems": 1, + "items": { "$ref": "#" } + }, + "nonNegativeInteger": { + "type": "integer", + "minimum": 0 + }, + "nonNegativeIntegerDefault0": { + "allOf": [ + { "$ref": "#/definitions/nonNegativeInteger" }, + { "default": 0 } + ] + }, + "simpleTypes": { + "enum": [ + "array", + "boolean", + "integer", + "null", + "number", + "object", + "string" + ] + }, + "stringArray": { + "type": "array", + "items": { "type": "string" }, + "uniqueItems": true, + "default": [] + } + }, + "type": ["object", "boolean"], + "properties": { + "$id": { + "type": "string", + "format": "uri-reference" + }, + "$schema": { + "type": "string", + "format": "uri" + }, + "$ref": { + "type": "string", + "format": "uri-reference" + }, + "$comment": { + "type": "string" + }, + "title": { + "type": "string" + }, + "description": { + "type": "string" + }, + "default": true, + "readOnly": { + "type": "boolean", + "default": false + }, + "writeOnly": { + "type": "boolean", + "default": false + }, + "examples": { + "type": "array", + "items": true + }, + "multipleOf": { + "type": "number", + "exclusiveMinimum": 0 + }, + "maximum": { + "type": "number" + }, + "exclusiveMaximum": { + "type": "number" + }, + "minimum": { + "type": "number" + }, + "exclusiveMinimum": { + "type": "number" + }, + "maxLength": { "$ref": "#/definitions/nonNegativeInteger" }, + "minLength": { "$ref": "#/definitions/nonNegativeIntegerDefault0" }, + "pattern": { + "type": "string", + "format": "regex" + }, + "additionalItems": { "$ref": "#" }, + "items": { + "anyOf": [ + { "$ref": "#" }, + { "$ref": "#/definitions/schemaArray" } + ], + "default": true + }, + "maxItems": { "$ref": "#/definitions/nonNegativeInteger" }, + "minItems": { "$ref": "#/definitions/nonNegativeIntegerDefault0" }, + "uniqueItems": { + "type": "boolean", + "default": false + }, + "contains": { "$ref": "#" }, + "maxProperties": { "$ref": "#/definitions/nonNegativeInteger" }, + "minProperties": { "$ref": "#/definitions/nonNegativeIntegerDefault0" }, + "required": { "$ref": "#/definitions/stringArray" }, + "additionalProperties": { "$ref": "#" }, + "definitions": { + "type": "object", + "additionalProperties": { "$ref": "#" }, + "default": {} + }, + "properties": { + "type": "object", + "additionalProperties": { "$ref": "#" }, + "default": {} + }, + "patternProperties": { + "type": "object", + "additionalProperties": { "$ref": "#" }, + "propertyNames": { "format": "regex" }, + "default": {} + }, + "dependencies": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { "$ref": "#" }, + { "$ref": "#/definitions/stringArray" } + ] + } + }, + "propertyNames": { "$ref": "#" }, + "const": true, + "enum": { + "type": "array", + "items": true, + "minItems": 1, + "uniqueItems": true + }, + "type": { + "anyOf": [ + { "$ref": "#/definitions/simpleTypes" }, + { + "type": "array", + "items": { "$ref": "#/definitions/simpleTypes" }, + "minItems": 1, + "uniqueItems": true + } + ] + }, + "format": { "type": "string" }, + "contentMediaType": { "type": "string" }, + "contentEncoding": { "type": "string" }, + "if": { "$ref": "#" }, + "then": { "$ref": "#" }, + "else": { "$ref": "#" }, + "allOf": { "$ref": "#/definitions/schemaArray" }, + "anyOf": { "$ref": "#/definitions/schemaArray" }, + "oneOf": { "$ref": "#/definitions/schemaArray" }, + "not": { "$ref": "#" } + }, + "default": true + }`) + Draft2019.loadMeta("https://json-schema.org/draft/2019-09/schema", `{ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "$id": "https://json-schema.org/draft/2019-09/schema", + "$vocabulary": { + "https://json-schema.org/draft/2019-09/vocab/core": true, + "https://json-schema.org/draft/2019-09/vocab/applicator": true, + "https://json-schema.org/draft/2019-09/vocab/validation": true, + "https://json-schema.org/draft/2019-09/vocab/meta-data": true, + "https://json-schema.org/draft/2019-09/vocab/format": false, + "https://json-schema.org/draft/2019-09/vocab/content": true + }, + "$recursiveAnchor": true, + + "title": "Core and Validation specifications meta-schema", + "allOf": [ + {"$ref": "meta/core"}, + {"$ref": "meta/applicator"}, + {"$ref": "meta/validation"}, + {"$ref": "meta/meta-data"}, + {"$ref": "meta/format"}, + {"$ref": "meta/content"} + ], + "type": ["object", "boolean"], + "properties": { + "definitions": { + "$comment": "While no longer an official keyword as it is replaced by $defs, this keyword is retained in the meta-schema to prevent incompatible extensions as it remains in common use.", + "type": "object", + "additionalProperties": { "$recursiveRef": "#" }, + "default": {} + }, + "dependencies": { + "$comment": "\"dependencies\" is no longer a keyword, but schema authors should avoid redefining it to facilitate a smooth transition to \"dependentSchemas\" and \"dependentRequired\"", + "type": "object", + "additionalProperties": { + "anyOf": [ + { "$recursiveRef": "#" }, + { "$ref": "meta/validation#/$defs/stringArray" } + ] + } + } + } + }`) + Draft2020.loadMeta("https://json-schema.org/draft/2020-12/schema", `{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://json-schema.org/draft/2020-12/schema", + "$vocabulary": { + "https://json-schema.org/draft/2020-12/vocab/core": true, + "https://json-schema.org/draft/2020-12/vocab/applicator": true, + "https://json-schema.org/draft/2020-12/vocab/unevaluated": true, + "https://json-schema.org/draft/2020-12/vocab/validation": true, + "https://json-schema.org/draft/2020-12/vocab/meta-data": true, + "https://json-schema.org/draft/2020-12/vocab/format-annotation": true, + "https://json-schema.org/draft/2020-12/vocab/content": true + }, + "$dynamicAnchor": "meta", + + "title": "Core and Validation specifications meta-schema", + "allOf": [ + {"$ref": "meta/core"}, + {"$ref": "meta/applicator"}, + {"$ref": "meta/unevaluated"}, + {"$ref": "meta/validation"}, + {"$ref": "meta/meta-data"}, + {"$ref": "meta/format-annotation"}, + {"$ref": "meta/content"} + ], + "type": ["object", "boolean"], + "$comment": "This meta-schema also defines keywords that have appeared in previous drafts in order to prevent incompatible extensions as they remain in common use.", + "properties": { + "definitions": { + "$comment": "\"definitions\" has been replaced by \"$defs\".", + "type": "object", + "additionalProperties": { "$dynamicRef": "#meta" }, + "deprecated": true, + "default": {} + }, + "dependencies": { + "$comment": "\"dependencies\" has been split and replaced by \"dependentSchemas\" and \"dependentRequired\" in order to serve their differing semantics.", + "type": "object", + "additionalProperties": { + "anyOf": [ + { "$dynamicRef": "#meta" }, + { "$ref": "meta/validation#/$defs/stringArray" } + ] + }, + "deprecated": true, + "default": {} + }, + "$recursiveAnchor": { + "$comment": "\"$recursiveAnchor\" has been replaced by \"$dynamicAnchor\".", + "$ref": "meta/core#/$defs/anchorString", + "deprecated": true + }, + "$recursiveRef": { + "$comment": "\"$recursiveRef\" has been replaced by \"$dynamicRef\".", + "$ref": "meta/core#/$defs/uriReferenceString", + "deprecated": true + } + } + }`) +} + +var vocabSchemas = map[string]string{ + "https://json-schema.org/draft/2019-09/meta/core": `{ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "$id": "https://json-schema.org/draft/2019-09/meta/core", + "$vocabulary": { + "https://json-schema.org/draft/2019-09/vocab/core": true + }, + "$recursiveAnchor": true, + + "title": "Core vocabulary meta-schema", + "type": ["object", "boolean"], + "properties": { + "$id": { + "type": "string", + "format": "uri-reference", + "$comment": "Non-empty fragments not allowed.", + "pattern": "^[^#]*#?$" + }, + "$schema": { + "type": "string", + "format": "uri" + }, + "$anchor": { + "type": "string", + "pattern": "^[A-Za-z][-A-Za-z0-9.:_]*$" + }, + "$ref": { + "type": "string", + "format": "uri-reference" + }, + "$recursiveRef": { + "type": "string", + "format": "uri-reference" + }, + "$recursiveAnchor": { + "type": "boolean", + "default": false + }, + "$vocabulary": { + "type": "object", + "propertyNames": { + "type": "string", + "format": "uri" + }, + "additionalProperties": { + "type": "boolean" + } + }, + "$comment": { + "type": "string" + }, + "$defs": { + "type": "object", + "additionalProperties": { "$recursiveRef": "#" }, + "default": {} + } + } + }`, + "https://json-schema.org/draft/2019-09/meta/applicator": `{ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "$id": "https://json-schema.org/draft/2019-09/meta/applicator", + "$vocabulary": { + "https://json-schema.org/draft/2019-09/vocab/applicator": true + }, + "$recursiveAnchor": true, + + "title": "Applicator vocabulary meta-schema", + "type": ["object", "boolean"], + "properties": { + "additionalItems": { "$recursiveRef": "#" }, + "unevaluatedItems": { "$recursiveRef": "#" }, + "items": { + "anyOf": [ + { "$recursiveRef": "#" }, + { "$ref": "#/$defs/schemaArray" } + ] + }, + "contains": { "$recursiveRef": "#" }, + "additionalProperties": { "$recursiveRef": "#" }, + "unevaluatedProperties": { "$recursiveRef": "#" }, + "properties": { + "type": "object", + "additionalProperties": { "$recursiveRef": "#" }, + "default": {} + }, + "patternProperties": { + "type": "object", + "additionalProperties": { "$recursiveRef": "#" }, + "propertyNames": { "format": "regex" }, + "default": {} + }, + "dependentSchemas": { + "type": "object", + "additionalProperties": { + "$recursiveRef": "#" + } + }, + "propertyNames": { "$recursiveRef": "#" }, + "if": { "$recursiveRef": "#" }, + "then": { "$recursiveRef": "#" }, + "else": { "$recursiveRef": "#" }, + "allOf": { "$ref": "#/$defs/schemaArray" }, + "anyOf": { "$ref": "#/$defs/schemaArray" }, + "oneOf": { "$ref": "#/$defs/schemaArray" }, + "not": { "$recursiveRef": "#" } + }, + "$defs": { + "schemaArray": { + "type": "array", + "minItems": 1, + "items": { "$recursiveRef": "#" } + } + } + }`, + "https://json-schema.org/draft/2019-09/meta/validation": `{ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "$id": "https://json-schema.org/draft/2019-09/meta/validation", + "$vocabulary": { + "https://json-schema.org/draft/2019-09/vocab/validation": true + }, + "$recursiveAnchor": true, + + "title": "Validation vocabulary meta-schema", + "type": ["object", "boolean"], + "properties": { + "multipleOf": { + "type": "number", + "exclusiveMinimum": 0 + }, + "maximum": { + "type": "number" + }, + "exclusiveMaximum": { + "type": "number" + }, + "minimum": { + "type": "number" + }, + "exclusiveMinimum": { + "type": "number" + }, + "maxLength": { "$ref": "#/$defs/nonNegativeInteger" }, + "minLength": { "$ref": "#/$defs/nonNegativeIntegerDefault0" }, + "pattern": { + "type": "string", + "format": "regex" + }, + "maxItems": { "$ref": "#/$defs/nonNegativeInteger" }, + "minItems": { "$ref": "#/$defs/nonNegativeIntegerDefault0" }, + "uniqueItems": { + "type": "boolean", + "default": false + }, + "maxContains": { "$ref": "#/$defs/nonNegativeInteger" }, + "minContains": { + "$ref": "#/$defs/nonNegativeInteger", + "default": 1 + }, + "maxProperties": { "$ref": "#/$defs/nonNegativeInteger" }, + "minProperties": { "$ref": "#/$defs/nonNegativeIntegerDefault0" }, + "required": { "$ref": "#/$defs/stringArray" }, + "dependentRequired": { + "type": "object", + "additionalProperties": { + "$ref": "#/$defs/stringArray" + } + }, + "const": true, + "enum": { + "type": "array", + "items": true + }, + "type": { + "anyOf": [ + { "$ref": "#/$defs/simpleTypes" }, + { + "type": "array", + "items": { "$ref": "#/$defs/simpleTypes" }, + "minItems": 1, + "uniqueItems": true + } + ] + } + }, + "$defs": { + "nonNegativeInteger": { + "type": "integer", + "minimum": 0 + }, + "nonNegativeIntegerDefault0": { + "$ref": "#/$defs/nonNegativeInteger", + "default": 0 + }, + "simpleTypes": { + "enum": [ + "array", + "boolean", + "integer", + "null", + "number", + "object", + "string" + ] + }, + "stringArray": { + "type": "array", + "items": { "type": "string" }, + "uniqueItems": true, + "default": [] + } + } + }`, + "https://json-schema.org/draft/2019-09/meta/meta-data": `{ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "$id": "https://json-schema.org/draft/2019-09/meta/meta-data", + "$vocabulary": { + "https://json-schema.org/draft/2019-09/vocab/meta-data": true + }, + "$recursiveAnchor": true, + + "title": "Meta-data vocabulary meta-schema", + + "type": ["object", "boolean"], + "properties": { + "title": { + "type": "string" + }, + "description": { + "type": "string" + }, + "default": true, + "deprecated": { + "type": "boolean", + "default": false + }, + "readOnly": { + "type": "boolean", + "default": false + }, + "writeOnly": { + "type": "boolean", + "default": false + }, + "examples": { + "type": "array", + "items": true + } + } + }`, + "https://json-schema.org/draft/2019-09/meta/format": `{ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "$id": "https://json-schema.org/draft/2019-09/meta/format", + "$vocabulary": { + "https://json-schema.org/draft/2019-09/vocab/format": true + }, + "$recursiveAnchor": true, + + "title": "Format vocabulary meta-schema", + "type": ["object", "boolean"], + "properties": { + "format": { "type": "string" } + } + }`, + "https://json-schema.org/draft/2019-09/meta/content": `{ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "$id": "https://json-schema.org/draft/2019-09/meta/content", + "$vocabulary": { + "https://json-schema.org/draft/2019-09/vocab/content": true + }, + "$recursiveAnchor": true, + + "title": "Content vocabulary meta-schema", + + "type": ["object", "boolean"], + "properties": { + "contentMediaType": { "type": "string" }, + "contentEncoding": { "type": "string" }, + "contentSchema": { "$recursiveRef": "#" } + } + }`, + "https://json-schema.org/draft/2020-12/meta/core": `{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://json-schema.org/draft/2020-12/meta/core", + "$vocabulary": { + "https://json-schema.org/draft/2020-12/vocab/core": true + }, + "$dynamicAnchor": "meta", + + "title": "Core vocabulary meta-schema", + "type": ["object", "boolean"], + "properties": { + "$id": { + "$ref": "#/$defs/uriReferenceString", + "$comment": "Non-empty fragments not allowed.", + "pattern": "^[^#]*#?$" + }, + "$schema": { "$ref": "#/$defs/uriString" }, + "$ref": { "$ref": "#/$defs/uriReferenceString" }, + "$anchor": { "$ref": "#/$defs/anchorString" }, + "$dynamicRef": { "$ref": "#/$defs/uriReferenceString" }, + "$dynamicAnchor": { "$ref": "#/$defs/anchorString" }, + "$vocabulary": { + "type": "object", + "propertyNames": { "$ref": "#/$defs/uriString" }, + "additionalProperties": { + "type": "boolean" + } + }, + "$comment": { + "type": "string" + }, + "$defs": { + "type": "object", + "additionalProperties": { "$dynamicRef": "#meta" } + } + }, + "$defs": { + "anchorString": { + "type": "string", + "pattern": "^[A-Za-z_][-A-Za-z0-9._]*$" + }, + "uriString": { + "type": "string", + "format": "uri" + }, + "uriReferenceString": { + "type": "string", + "format": "uri-reference" + } + } + }`, + "https://json-schema.org/draft/2020-12/meta/applicator": `{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://json-schema.org/draft/2020-12/meta/applicator", + "$vocabulary": { + "https://json-schema.org/draft/2020-12/vocab/applicator": true + }, + "$dynamicAnchor": "meta", + + "title": "Applicator vocabulary meta-schema", + "type": ["object", "boolean"], + "properties": { + "prefixItems": { "$ref": "#/$defs/schemaArray" }, + "items": { "$dynamicRef": "#meta" }, + "contains": { "$dynamicRef": "#meta" }, + "additionalProperties": { "$dynamicRef": "#meta" }, + "properties": { + "type": "object", + "additionalProperties": { "$dynamicRef": "#meta" }, + "default": {} + }, + "patternProperties": { + "type": "object", + "additionalProperties": { "$dynamicRef": "#meta" }, + "propertyNames": { "format": "regex" }, + "default": {} + }, + "dependentSchemas": { + "type": "object", + "additionalProperties": { "$dynamicRef": "#meta" }, + "default": {} + }, + "propertyNames": { "$dynamicRef": "#meta" }, + "if": { "$dynamicRef": "#meta" }, + "then": { "$dynamicRef": "#meta" }, + "else": { "$dynamicRef": "#meta" }, + "allOf": { "$ref": "#/$defs/schemaArray" }, + "anyOf": { "$ref": "#/$defs/schemaArray" }, + "oneOf": { "$ref": "#/$defs/schemaArray" }, + "not": { "$dynamicRef": "#meta" } + }, + "$defs": { + "schemaArray": { + "type": "array", + "minItems": 1, + "items": { "$dynamicRef": "#meta" } + } + } + }`, + "https://json-schema.org/draft/2020-12/meta/unevaluated": `{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://json-schema.org/draft/2020-12/meta/unevaluated", + "$vocabulary": { + "https://json-schema.org/draft/2020-12/vocab/unevaluated": true + }, + "$dynamicAnchor": "meta", + + "title": "Unevaluated applicator vocabulary meta-schema", + "type": ["object", "boolean"], + "properties": { + "unevaluatedItems": { "$dynamicRef": "#meta" }, + "unevaluatedProperties": { "$dynamicRef": "#meta" } + } + }`, + "https://json-schema.org/draft/2020-12/meta/validation": `{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://json-schema.org/draft/2020-12/meta/validation", + "$vocabulary": { + "https://json-schema.org/draft/2020-12/vocab/validation": true + }, + "$dynamicAnchor": "meta", + + "title": "Validation vocabulary meta-schema", + "type": ["object", "boolean"], + "properties": { + "type": { + "anyOf": [ + { "$ref": "#/$defs/simpleTypes" }, + { + "type": "array", + "items": { "$ref": "#/$defs/simpleTypes" }, + "minItems": 1, + "uniqueItems": true + } + ] + }, + "const": true, + "enum": { + "type": "array", + "items": true + }, + "multipleOf": { + "type": "number", + "exclusiveMinimum": 0 + }, + "maximum": { + "type": "number" + }, + "exclusiveMaximum": { + "type": "number" + }, + "minimum": { + "type": "number" + }, + "exclusiveMinimum": { + "type": "number" + }, + "maxLength": { "$ref": "#/$defs/nonNegativeInteger" }, + "minLength": { "$ref": "#/$defs/nonNegativeIntegerDefault0" }, + "pattern": { + "type": "string", + "format": "regex" + }, + "maxItems": { "$ref": "#/$defs/nonNegativeInteger" }, + "minItems": { "$ref": "#/$defs/nonNegativeIntegerDefault0" }, + "uniqueItems": { + "type": "boolean", + "default": false + }, + "maxContains": { "$ref": "#/$defs/nonNegativeInteger" }, + "minContains": { + "$ref": "#/$defs/nonNegativeInteger", + "default": 1 + }, + "maxProperties": { "$ref": "#/$defs/nonNegativeInteger" }, + "minProperties": { "$ref": "#/$defs/nonNegativeIntegerDefault0" }, + "required": { "$ref": "#/$defs/stringArray" }, + "dependentRequired": { + "type": "object", + "additionalProperties": { + "$ref": "#/$defs/stringArray" + } + } + }, + "$defs": { + "nonNegativeInteger": { + "type": "integer", + "minimum": 0 + }, + "nonNegativeIntegerDefault0": { + "$ref": "#/$defs/nonNegativeInteger", + "default": 0 + }, + "simpleTypes": { + "enum": [ + "array", + "boolean", + "integer", + "null", + "number", + "object", + "string" + ] + }, + "stringArray": { + "type": "array", + "items": { "type": "string" }, + "uniqueItems": true, + "default": [] + } + } + }`, + "https://json-schema.org/draft/2020-12/meta/meta-data": `{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://json-schema.org/draft/2020-12/meta/meta-data", + "$vocabulary": { + "https://json-schema.org/draft/2020-12/vocab/meta-data": true + }, + "$dynamicAnchor": "meta", + + "title": "Meta-data vocabulary meta-schema", + + "type": ["object", "boolean"], + "properties": { + "title": { + "type": "string" + }, + "description": { + "type": "string" + }, + "default": true, + "deprecated": { + "type": "boolean", + "default": false + }, + "readOnly": { + "type": "boolean", + "default": false + }, + "writeOnly": { + "type": "boolean", + "default": false + }, + "examples": { + "type": "array", + "items": true + } + } + }`, + "https://json-schema.org/draft/2020-12/meta/format-annotation": `{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://json-schema.org/draft/2020-12/meta/format-annotation", + "$vocabulary": { + "https://json-schema.org/draft/2020-12/vocab/format-annotation": true + }, + "$dynamicAnchor": "meta", + + "title": "Format vocabulary meta-schema for annotation results", + "type": ["object", "boolean"], + "properties": { + "format": { "type": "string" } + } + }`, + "https://json-schema.org/draft/2020-12/meta/format-assertion": `{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://json-schema.org/draft/2020-12/meta/format-assertion", + "$vocabulary": { + "https://json-schema.org/draft/2020-12/vocab/format-assertion": true + }, + "$dynamicAnchor": "meta", + + "title": "Format vocabulary meta-schema for assertion results", + "type": ["object", "boolean"], + "properties": { + "format": { "type": "string" } + } + }`, + "https://json-schema.org/draft/2020-12/meta/content": `{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://json-schema.org/draft/2020-12/meta/content", + "$vocabulary": { + "https://json-schema.org/draft/2020-12/vocab/content": true + }, + "$dynamicAnchor": "meta", + + "title": "Content vocabulary meta-schema", + + "type": ["object", "boolean"], + "properties": { + "contentEncoding": { "type": "string" }, + "contentMediaType": { "type": "string" }, + "contentSchema": { "$dynamicRef": "#meta" } + } + }`, +} + +func clone(m map[string]position) map[string]position { + mm := make(map[string]position) + for k, v := range m { + mm[k] = v + } + return mm +} diff --git a/vendor/github.com/santhosh-tekuri/jsonschema/v5/errors.go b/vendor/github.com/santhosh-tekuri/jsonschema/v5/errors.go new file mode 100644 index 0000000000..deaded89f7 --- /dev/null +++ b/vendor/github.com/santhosh-tekuri/jsonschema/v5/errors.go @@ -0,0 +1,129 @@ +package jsonschema + +import ( + "fmt" + "strings" +) + +// InvalidJSONTypeError is the error type returned by ValidateInterface. +// this tells that specified go object is not valid jsonType. +type InvalidJSONTypeError string + +func (e InvalidJSONTypeError) Error() string { + return fmt.Sprintf("jsonschema: invalid jsonType: %s", string(e)) +} + +// InfiniteLoopError is returned by Compile/Validate. +// this gives url#keywordLocation that lead to infinity loop. +type InfiniteLoopError string + +func (e InfiniteLoopError) Error() string { + return "jsonschema: infinite loop " + string(e) +} + +func infiniteLoopError(stack []schemaRef, sref schemaRef) InfiniteLoopError { + var path string + for _, ref := range stack { + if path == "" { + path += ref.schema.Location + } else { + path += "/" + ref.path + } + } + return InfiniteLoopError(path + "/" + sref.path) +} + +// SchemaError is the error type returned by Compile. +type SchemaError struct { + // SchemaURL is the url to json-schema that filed to compile. + // This is helpful, if your schema refers to external schemas + SchemaURL string + + // Err is the error that occurred during compilation. + // It could be ValidationError, because compilation validates + // given schema against the json meta-schema + Err error +} + +func (se *SchemaError) Unwrap() error { + return se.Err +} + +func (se *SchemaError) Error() string { + s := fmt.Sprintf("jsonschema %s compilation failed", se.SchemaURL) + if se.Err != nil { + return fmt.Sprintf("%s: %v", s, strings.TrimPrefix(se.Err.Error(), "jsonschema: ")) + } + return s +} + +func (se *SchemaError) GoString() string { + if _, ok := se.Err.(*ValidationError); ok { + return fmt.Sprintf("jsonschema %s compilation failed\n%#v", se.SchemaURL, se.Err) + } + return se.Error() +} + +// ValidationError is the error type returned by Validate. +type ValidationError struct { + KeywordLocation string // validation path of validating keyword or schema + AbsoluteKeywordLocation string // absolute location of validating keyword or schema + InstanceLocation string // location of the json value within the instance being validated + Message string // describes error + Causes []*ValidationError // nested validation errors +} + +func (ve *ValidationError) add(causes ...error) error { + for _, cause := range causes { + ve.Causes = append(ve.Causes, cause.(*ValidationError)) + } + return ve +} + +func (ve *ValidationError) causes(err error) error { + if err := err.(*ValidationError); err.Message == "" { + ve.Causes = err.Causes + } else { + ve.add(err) + } + return ve +} + +func (ve *ValidationError) Error() string { + leaf := ve + for len(leaf.Causes) > 0 { + leaf = leaf.Causes[0] + } + u, _ := split(ve.AbsoluteKeywordLocation) + return fmt.Sprintf("jsonschema: %s does not validate with %s: %s", quote(leaf.InstanceLocation), u+"#"+leaf.KeywordLocation, leaf.Message) +} + +func (ve *ValidationError) GoString() string { + sloc := ve.AbsoluteKeywordLocation + sloc = sloc[strings.IndexByte(sloc, '#')+1:] + msg := fmt.Sprintf("[I#%s] [S#%s] %s", ve.InstanceLocation, sloc, ve.Message) + for _, c := range ve.Causes { + for _, line := range strings.Split(c.GoString(), "\n") { + msg += "\n " + line + } + } + return msg +} + +func joinPtr(ptr1, ptr2 string) string { + if len(ptr1) == 0 { + return ptr2 + } + if len(ptr2) == 0 { + return ptr1 + } + return ptr1 + "/" + ptr2 +} + +// quote returns single-quoted string +func quote(s string) string { + s = fmt.Sprintf("%q", s) + s = strings.ReplaceAll(s, `\"`, `"`) + s = strings.ReplaceAll(s, `'`, `\'`) + return "'" + s[1:len(s)-1] + "'" +} diff --git a/vendor/github.com/santhosh-tekuri/jsonschema/v5/extension.go b/vendor/github.com/santhosh-tekuri/jsonschema/v5/extension.go new file mode 100644 index 0000000000..452ba118c5 --- /dev/null +++ b/vendor/github.com/santhosh-tekuri/jsonschema/v5/extension.go @@ -0,0 +1,116 @@ +package jsonschema + +// ExtCompiler compiles custom keyword(s) into ExtSchema. +type ExtCompiler interface { + // Compile compiles the custom keywords in schema m and returns its compiled representation. + // if the schema m does not contain the keywords defined by this extension, + // compiled representation nil should be returned. + Compile(ctx CompilerContext, m map[string]interface{}) (ExtSchema, error) +} + +// ExtSchema is schema representation of custom keyword(s) +type ExtSchema interface { + // Validate validates the json value v with this ExtSchema. + // Returned error must be *ValidationError. + Validate(ctx ValidationContext, v interface{}) error +} + +type extension struct { + meta *Schema + compiler ExtCompiler +} + +// RegisterExtension registers custom keyword(s) into this compiler. +// +// name is extension name, used only to avoid name collisions. +// meta captures the metaschema for the new keywords. +// This is used to validate the schema before calling ext.Compile. +func (c *Compiler) RegisterExtension(name string, meta *Schema, ext ExtCompiler) { + c.extensions[name] = extension{meta, ext} +} + +// CompilerContext --- + +// CompilerContext provides additional context required in compiling for extension. +type CompilerContext struct { + c *Compiler + r *resource + stack []schemaRef + res *resource +} + +// Compile compiles given value at ptr into *Schema. This is useful in implementing +// keyword like allOf/not/patternProperties. +// +// schPath is the relative-json-pointer to the schema to be compiled from parent schema. +// +// applicableOnSameInstance tells whether current schema and the given schema +// are applied on same instance value. this is used to detect infinite loop in schema. +func (ctx CompilerContext) Compile(schPath string, applicableOnSameInstance bool) (*Schema, error) { + var stack []schemaRef + if applicableOnSameInstance { + stack = ctx.stack + } + return ctx.c.compileRef(ctx.r, stack, schPath, ctx.res, ctx.r.url+ctx.res.floc+"/"+schPath) +} + +// CompileRef compiles the schema referenced by ref uri +// +// refPath is the relative-json-pointer to ref. +// +// applicableOnSameInstance tells whether current schema and the given schema +// are applied on same instance value. this is used to detect infinite loop in schema. +func (ctx CompilerContext) CompileRef(ref string, refPath string, applicableOnSameInstance bool) (*Schema, error) { + var stack []schemaRef + if applicableOnSameInstance { + stack = ctx.stack + } + return ctx.c.compileRef(ctx.r, stack, refPath, ctx.res, ref) +} + +// ValidationContext --- + +// ValidationContext provides additional context required in validating for extension. +type ValidationContext struct { + result validationResult + validate func(sch *Schema, schPath string, v interface{}, vpath string) error + validateInplace func(sch *Schema, schPath string) error + validationError func(keywordPath string, format string, a ...interface{}) *ValidationError +} + +// EvaluatedProp marks given property of object as evaluated. +func (ctx ValidationContext) EvaluatedProp(prop string) { + delete(ctx.result.unevalProps, prop) +} + +// EvaluatedItem marks given index of array as evaluated. +func (ctx ValidationContext) EvaluatedItem(index int) { + delete(ctx.result.unevalItems, index) +} + +// Validate validates schema s with value v. Extension must use this method instead of +// *Schema.ValidateInterface method. This will be useful in implementing keywords like +// allOf/oneOf +// +// spath is relative-json-pointer to s +// vpath is relative-json-pointer to v. +func (ctx ValidationContext) Validate(s *Schema, spath string, v interface{}, vpath string) error { + if vpath == "" { + return ctx.validateInplace(s, spath) + } + return ctx.validate(s, spath, v, vpath) +} + +// Error used to construct validation error by extensions. +// +// keywordPath is relative-json-pointer to keyword. +func (ctx ValidationContext) Error(keywordPath string, format string, a ...interface{}) *ValidationError { + return ctx.validationError(keywordPath, format, a...) +} + +// Group is used by extensions to group multiple errors as causes to parent error. +// This is useful in implementing keywords like allOf where each schema specified +// in allOf can result a validationError. +func (ValidationError) Group(parent *ValidationError, causes ...error) error { + return parent.add(causes...) +} diff --git a/vendor/github.com/santhosh-tekuri/jsonschema/v5/format.go b/vendor/github.com/santhosh-tekuri/jsonschema/v5/format.go new file mode 100644 index 0000000000..05686073f0 --- /dev/null +++ b/vendor/github.com/santhosh-tekuri/jsonschema/v5/format.go @@ -0,0 +1,567 @@ +package jsonschema + +import ( + "errors" + "net" + "net/mail" + "net/url" + "regexp" + "strconv" + "strings" + "time" +) + +// Formats is a registry of functions, which know how to validate +// a specific format. +// +// New Formats can be registered by adding to this map. Key is format name, +// value is function that knows how to validate that format. +var Formats = map[string]func(interface{}) bool{ + "date-time": isDateTime, + "date": isDate, + "time": isTime, + "duration": isDuration, + "period": isPeriod, + "hostname": isHostname, + "email": isEmail, + "ip-address": isIPV4, + "ipv4": isIPV4, + "ipv6": isIPV6, + "uri": isURI, + "iri": isURI, + "uri-reference": isURIReference, + "uriref": isURIReference, + "iri-reference": isURIReference, + "uri-template": isURITemplate, + "regex": isRegex, + "json-pointer": isJSONPointer, + "relative-json-pointer": isRelativeJSONPointer, + "uuid": isUUID, +} + +// isDateTime tells whether given string is a valid date representation +// as defined by RFC 3339, section 5.6. +// +// see https://datatracker.ietf.org/doc/html/rfc3339#section-5.6, for details +func isDateTime(v interface{}) bool { + s, ok := v.(string) + if !ok { + return true + } + if len(s) < 20 { // yyyy-mm-ddThh:mm:ssZ + return false + } + if s[10] != 'T' && s[10] != 't' { + return false + } + return isDate(s[:10]) && isTime(s[11:]) +} + +// isDate tells whether given string is a valid full-date production +// as defined by RFC 3339, section 5.6. +// +// see https://datatracker.ietf.org/doc/html/rfc3339#section-5.6, for details +func isDate(v interface{}) bool { + s, ok := v.(string) + if !ok { + return true + } + _, err := time.Parse("2006-01-02", s) + return err == nil +} + +// isTime tells whether given string is a valid full-time production +// as defined by RFC 3339, section 5.6. +// +// see https://datatracker.ietf.org/doc/html/rfc3339#section-5.6, for details +func isTime(v interface{}) bool { + str, ok := v.(string) + if !ok { + return true + } + + // golang time package does not support leap seconds. + // so we are parsing it manually here. + + // hh:mm:ss + // 01234567 + if len(str) < 9 || str[2] != ':' || str[5] != ':' { + return false + } + isInRange := func(str string, min, max int) (int, bool) { + n, err := strconv.Atoi(str) + if err != nil { + return 0, false + } + if n < min || n > max { + return 0, false + } + return n, true + } + var h, m, s int + if h, ok = isInRange(str[0:2], 0, 23); !ok { + return false + } + if m, ok = isInRange(str[3:5], 0, 59); !ok { + return false + } + if s, ok = isInRange(str[6:8], 0, 60); !ok { + return false + } + str = str[8:] + + // parse secfrac if present + if str[0] == '.' { + // dot following more than one digit + str = str[1:] + var numDigits int + for str != "" { + if str[0] < '0' || str[0] > '9' { + break + } + numDigits++ + str = str[1:] + } + if numDigits == 0 { + return false + } + } + + if len(str) == 0 { + return false + } + + if str[0] == 'z' || str[0] == 'Z' { + if len(str) != 1 { + return false + } + } else { + // time-numoffset + // +hh:mm + // 012345 + if len(str) != 6 || str[3] != ':' { + return false + } + + var sign int + if str[0] == '+' { + sign = -1 + } else if str[0] == '-' { + sign = +1 + } else { + return false + } + + var zh, zm int + if zh, ok = isInRange(str[1:3], 0, 23); !ok { + return false + } + if zm, ok = isInRange(str[4:6], 0, 59); !ok { + return false + } + + // apply timezone offset + hm := (h*60 + m) + sign*(zh*60+zm) + if hm < 0 { + hm += 24 * 60 + } + h, m = hm/60, hm%60 + } + + // check leapsecond + if s == 60 { // leap second + if h != 23 || m != 59 { + return false + } + } + + return true +} + +// isDuration tells whether given string is a valid duration format +// from the ISO 8601 ABNF as given in Appendix A of RFC 3339. +// +// see https://datatracker.ietf.org/doc/html/rfc3339#appendix-A, for details +func isDuration(v interface{}) bool { + s, ok := v.(string) + if !ok { + return true + } + if len(s) == 0 || s[0] != 'P' { + return false + } + s = s[1:] + parseUnits := func() (units string, ok bool) { + for len(s) > 0 && s[0] != 'T' { + digits := false + for { + if len(s) == 0 { + break + } + if s[0] < '0' || s[0] > '9' { + break + } + digits = true + s = s[1:] + } + if !digits || len(s) == 0 { + return units, false + } + units += s[:1] + s = s[1:] + } + return units, true + } + units, ok := parseUnits() + if !ok { + return false + } + if units == "W" { + return len(s) == 0 // P_W + } + if len(units) > 0 { + if strings.Index("YMD", units) == -1 { + return false + } + if len(s) == 0 { + return true // "P" dur-date + } + } + if len(s) == 0 || s[0] != 'T' { + return false + } + s = s[1:] + units, ok = parseUnits() + return ok && len(s) == 0 && len(units) > 0 && strings.Index("HMS", units) != -1 +} + +// isPeriod tells whether given string is a valid period format +// from the ISO 8601 ABNF as given in Appendix A of RFC 3339. +// +// see https://datatracker.ietf.org/doc/html/rfc3339#appendix-A, for details +func isPeriod(v interface{}) bool { + s, ok := v.(string) + if !ok { + return true + } + slash := strings.IndexByte(s, '/') + if slash == -1 { + return false + } + start, end := s[:slash], s[slash+1:] + if isDateTime(start) { + return isDateTime(end) || isDuration(end) + } + return isDuration(start) && isDateTime(end) +} + +// isHostname tells whether given string is a valid representation +// for an Internet host name, as defined by RFC 1034 section 3.1 and +// RFC 1123 section 2.1. +// +// See https://en.wikipedia.org/wiki/Hostname#Restrictions_on_valid_host_names, for details. +func isHostname(v interface{}) bool { + s, ok := v.(string) + if !ok { + return true + } + // entire hostname (including the delimiting dots but not a trailing dot) has a maximum of 253 ASCII characters + s = strings.TrimSuffix(s, ".") + if len(s) > 253 { + return false + } + + // Hostnames are composed of series of labels concatenated with dots, as are all domain names + for _, label := range strings.Split(s, ".") { + // Each label must be from 1 to 63 characters long + if labelLen := len(label); labelLen < 1 || labelLen > 63 { + return false + } + + // labels must not start with a hyphen + // RFC 1123 section 2.1: restriction on the first character + // is relaxed to allow either a letter or a digit + if first := s[0]; first == '-' { + return false + } + + // must not end with a hyphen + if label[len(label)-1] == '-' { + return false + } + + // labels may contain only the ASCII letters 'a' through 'z' (in a case-insensitive manner), + // the digits '0' through '9', and the hyphen ('-') + for _, c := range label { + if valid := (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || (c == '-'); !valid { + return false + } + } + } + + return true +} + +// isEmail tells whether given string is a valid Internet email address +// as defined by RFC 5322, section 3.4.1. +// +// See https://en.wikipedia.org/wiki/Email_address, for details. +func isEmail(v interface{}) bool { + s, ok := v.(string) + if !ok { + return true + } + // entire email address to be no more than 254 characters long + if len(s) > 254 { + return false + } + + // email address is generally recognized as having two parts joined with an at-sign + at := strings.LastIndexByte(s, '@') + if at == -1 { + return false + } + local := s[0:at] + domain := s[at+1:] + + // local part may be up to 64 characters long + if len(local) > 64 { + return false + } + + // domain if enclosed in brackets, must match an IP address + if len(domain) >= 2 && domain[0] == '[' && domain[len(domain)-1] == ']' { + ip := domain[1 : len(domain)-1] + if strings.HasPrefix(ip, "IPv6:") { + return isIPV6(strings.TrimPrefix(ip, "IPv6:")) + } + return isIPV4(ip) + } + + // domain must match the requirements for a hostname + if !isHostname(domain) { + return false + } + + _, err := mail.ParseAddress(s) + return err == nil +} + +// isIPV4 tells whether given string is a valid representation of an IPv4 address +// according to the "dotted-quad" ABNF syntax as defined in RFC 2673, section 3.2. +func isIPV4(v interface{}) bool { + s, ok := v.(string) + if !ok { + return true + } + groups := strings.Split(s, ".") + if len(groups) != 4 { + return false + } + for _, group := range groups { + n, err := strconv.Atoi(group) + if err != nil { + return false + } + if n < 0 || n > 255 { + return false + } + if n != 0 && group[0] == '0' { + return false // leading zeroes should be rejected, as they are treated as octals + } + } + return true +} + +// isIPV6 tells whether given string is a valid representation of an IPv6 address +// as defined in RFC 2373, section 2.2. +func isIPV6(v interface{}) bool { + s, ok := v.(string) + if !ok { + return true + } + if !strings.Contains(s, ":") { + return false + } + return net.ParseIP(s) != nil +} + +// isURI tells whether given string is valid URI, according to RFC 3986. +func isURI(v interface{}) bool { + s, ok := v.(string) + if !ok { + return true + } + u, err := urlParse(s) + return err == nil && u.IsAbs() +} + +func urlParse(s string) (*url.URL, error) { + u, err := url.Parse(s) + if err != nil { + return nil, err + } + + // if hostname is ipv6, validate it + hostname := u.Hostname() + if strings.IndexByte(hostname, ':') != -1 { + if strings.IndexByte(u.Host, '[') == -1 || strings.IndexByte(u.Host, ']') == -1 { + return nil, errors.New("ipv6 address is not enclosed in brackets") + } + if !isIPV6(hostname) { + return nil, errors.New("invalid ipv6 address") + } + } + return u, nil +} + +// isURIReference tells whether given string is a valid URI Reference +// (either a URI or a relative-reference), according to RFC 3986. +func isURIReference(v interface{}) bool { + s, ok := v.(string) + if !ok { + return true + } + _, err := urlParse(s) + return err == nil && !strings.Contains(s, `\`) +} + +// isURITemplate tells whether given string is a valid URI Template +// according to RFC6570. +// +// Current implementation does minimal validation. +func isURITemplate(v interface{}) bool { + s, ok := v.(string) + if !ok { + return true + } + u, err := urlParse(s) + if err != nil { + return false + } + for _, item := range strings.Split(u.RawPath, "/") { + depth := 0 + for _, ch := range item { + switch ch { + case '{': + depth++ + if depth != 1 { + return false + } + case '}': + depth-- + if depth != 0 { + return false + } + } + } + if depth != 0 { + return false + } + } + return true +} + +// isRegex tells whether given string is a valid regular expression, +// according to the ECMA 262 regular expression dialect. +// +// The implementation uses go-lang regexp package. +func isRegex(v interface{}) bool { + s, ok := v.(string) + if !ok { + return true + } + _, err := regexp.Compile(s) + return err == nil +} + +// isJSONPointer tells whether given string is a valid JSON Pointer. +// +// Note: It returns false for JSON Pointer URI fragments. +func isJSONPointer(v interface{}) bool { + s, ok := v.(string) + if !ok { + return true + } + if s != "" && !strings.HasPrefix(s, "/") { + return false + } + for _, item := range strings.Split(s, "/") { + for i := 0; i < len(item); i++ { + if item[i] == '~' { + if i == len(item)-1 { + return false + } + switch item[i+1] { + case '0', '1': + // valid + default: + return false + } + } + } + } + return true +} + +// isRelativeJSONPointer tells whether given string is a valid Relative JSON Pointer. +// +// see https://tools.ietf.org/html/draft-handrews-relative-json-pointer-01#section-3 +func isRelativeJSONPointer(v interface{}) bool { + s, ok := v.(string) + if !ok { + return true + } + if s == "" { + return false + } + if s[0] == '0' { + s = s[1:] + } else if s[0] >= '0' && s[0] <= '9' { + for s != "" && s[0] >= '0' && s[0] <= '9' { + s = s[1:] + } + } else { + return false + } + return s == "#" || isJSONPointer(s) +} + +// isUUID tells whether given string is a valid uuid format +// as specified in RFC4122. +// +// see https://datatracker.ietf.org/doc/html/rfc4122#page-4, for details +func isUUID(v interface{}) bool { + s, ok := v.(string) + if !ok { + return true + } + parseHex := func(n int) bool { + for n > 0 { + if len(s) == 0 { + return false + } + hex := (s[0] >= '0' && s[0] <= '9') || (s[0] >= 'a' && s[0] <= 'f') || (s[0] >= 'A' && s[0] <= 'F') + if !hex { + return false + } + s = s[1:] + n-- + } + return true + } + groups := []int{8, 4, 4, 4, 12} + for i, numDigits := range groups { + if !parseHex(numDigits) { + return false + } + if i == len(groups)-1 { + break + } + if len(s) == 0 || s[0] != '-' { + return false + } + s = s[1:] + } + return len(s) == 0 +} diff --git a/vendor/github.com/santhosh-tekuri/jsonschema/v5/loader.go b/vendor/github.com/santhosh-tekuri/jsonschema/v5/loader.go new file mode 100644 index 0000000000..c94195c335 --- /dev/null +++ b/vendor/github.com/santhosh-tekuri/jsonschema/v5/loader.go @@ -0,0 +1,60 @@ +package jsonschema + +import ( + "fmt" + "io" + "net/url" + "os" + "path/filepath" + "runtime" + "strings" +) + +func loadFileURL(s string) (io.ReadCloser, error) { + u, err := url.Parse(s) + if err != nil { + return nil, err + } + f := u.Path + if runtime.GOOS == "windows" { + f = strings.TrimPrefix(f, "/") + f = filepath.FromSlash(f) + } + return os.Open(f) +} + +// Loaders is a registry of functions, which know how to load +// absolute url of specific schema. +// +// New loaders can be registered by adding to this map. Key is schema, +// value is function that knows how to load url of that schema +var Loaders = map[string]func(url string) (io.ReadCloser, error){ + "file": loadFileURL, +} + +// LoaderNotFoundError is the error type returned by Load function. +// It tells that no Loader is registered for that URL Scheme. +type LoaderNotFoundError string + +func (e LoaderNotFoundError) Error() string { + return fmt.Sprintf("jsonschema: no Loader found for %s", string(e)) +} + +// LoadURL loads document at given absolute URL. The default implementation +// uses Loaders registry to lookup by schema and uses that loader. +// +// Users can change this variable, if they would like to take complete +// responsibility of loading given URL. Used by Compiler if its LoadURL +// field is nil. +var LoadURL = func(s string) (io.ReadCloser, error) { + u, err := url.Parse(s) + if err != nil { + return nil, err + } + loader, ok := Loaders[u.Scheme] + if !ok { + return nil, LoaderNotFoundError(s) + + } + return loader(s) +} diff --git a/vendor/github.com/santhosh-tekuri/jsonschema/v5/output.go b/vendor/github.com/santhosh-tekuri/jsonschema/v5/output.go new file mode 100644 index 0000000000..d65ae2a929 --- /dev/null +++ b/vendor/github.com/santhosh-tekuri/jsonschema/v5/output.go @@ -0,0 +1,77 @@ +package jsonschema + +// Flag is output format with simple boolean property valid. +type Flag struct { + Valid bool `json:"valid"` +} + +// FlagOutput returns output in flag format +func (ve *ValidationError) FlagOutput() Flag { + return Flag{} +} + +// Basic --- + +// Basic is output format with flat list of output units. +type Basic struct { + Valid bool `json:"valid"` + Errors []BasicError `json:"errors"` +} + +// BasicError is output unit in basic format. +type BasicError struct { + KeywordLocation string `json:"keywordLocation"` + AbsoluteKeywordLocation string `json:"absoluteKeywordLocation"` + InstanceLocation string `json:"instanceLocation"` + Error string `json:"error"` +} + +// BasicOutput returns output in basic format +func (ve *ValidationError) BasicOutput() Basic { + var errors []BasicError + var flatten func(*ValidationError) + flatten = func(ve *ValidationError) { + errors = append(errors, BasicError{ + KeywordLocation: ve.KeywordLocation, + AbsoluteKeywordLocation: ve.AbsoluteKeywordLocation, + InstanceLocation: ve.InstanceLocation, + Error: ve.Message, + }) + for _, cause := range ve.Causes { + flatten(cause) + } + } + flatten(ve) + return Basic{Errors: errors} +} + +// Detailed --- + +// Detailed is output format based on structure of schema. +type Detailed struct { + Valid bool `json:"valid"` + KeywordLocation string `json:"keywordLocation"` + AbsoluteKeywordLocation string `json:"absoluteKeywordLocation"` + InstanceLocation string `json:"instanceLocation"` + Error string `json:"error,omitempty"` + Errors []Detailed `json:"errors,omitempty"` +} + +// DetailedOutput returns output in detailed format +func (ve *ValidationError) DetailedOutput() Detailed { + var errors []Detailed + for _, cause := range ve.Causes { + errors = append(errors, cause.DetailedOutput()) + } + var message = ve.Message + if len(ve.Causes) > 0 { + message = "" + } + return Detailed{ + KeywordLocation: ve.KeywordLocation, + AbsoluteKeywordLocation: ve.AbsoluteKeywordLocation, + InstanceLocation: ve.InstanceLocation, + Error: message, + Errors: errors, + } +} diff --git a/vendor/github.com/santhosh-tekuri/jsonschema/v5/resource.go b/vendor/github.com/santhosh-tekuri/jsonschema/v5/resource.go new file mode 100644 index 0000000000..18349daac7 --- /dev/null +++ b/vendor/github.com/santhosh-tekuri/jsonschema/v5/resource.go @@ -0,0 +1,280 @@ +package jsonschema + +import ( + "encoding/json" + "fmt" + "io" + "net/url" + "path/filepath" + "runtime" + "strconv" + "strings" +) + +type resource struct { + url string // base url of resource. can be empty + floc string // fragment with json-pointer from root resource + doc interface{} + draft *Draft + subresources map[string]*resource // key is floc. only applicable for root resource + schema *Schema +} + +func (r *resource) String() string { + return r.url + r.floc +} + +func newResource(url string, r io.Reader) (*resource, error) { + if strings.IndexByte(url, '#') != -1 { + panic(fmt.Sprintf("BUG: newResource(%q)", url)) + } + doc, err := unmarshal(r) + if err != nil { + return nil, fmt.Errorf("jsonschema: invalid json %s: %v", url, err) + } + url, err = toAbs(url) + if err != nil { + return nil, err + } + return &resource{ + url: url, + floc: "#", + doc: doc, + }, nil +} + +// fillSubschemas fills subschemas in res into r.subresources +func (r *resource) fillSubschemas(c *Compiler, res *resource) error { + if err := c.validateSchema(r, res.doc, res.floc[1:]); err != nil { + return err + } + + if r.subresources == nil { + r.subresources = make(map[string]*resource) + } + if err := r.draft.listSubschemas(res, r.baseURL(res.floc), r.subresources); err != nil { + return err + } + + // ensure subresource.url uniqueness + url2floc := make(map[string]string) + for _, sr := range r.subresources { + if sr.url != "" { + if floc, ok := url2floc[sr.url]; ok { + return fmt.Errorf("jsonschema: %q and %q in %s have same canonical-uri", floc[1:], sr.floc[1:], r.url) + } + url2floc[sr.url] = sr.floc + } + } + + return nil +} + +// listResources lists all subresources in res +func (r *resource) listResources(res *resource) []*resource { + var result []*resource + prefix := res.floc + "/" + for _, sr := range r.subresources { + if strings.HasPrefix(sr.floc, prefix) { + result = append(result, sr) + } + } + return result +} + +func (r *resource) findResource(url string) *resource { + if r.url == url { + return r + } + for _, res := range r.subresources { + if res.url == url { + return res + } + } + return nil +} + +// resolve fragment f with sr as base +func (r *resource) resolveFragment(c *Compiler, sr *resource, f string) (*resource, error) { + if f == "#" || f == "#/" { + return sr, nil + } + + // resolve by anchor + if !strings.HasPrefix(f, "#/") { + // check in given resource + for _, anchor := range r.draft.anchors(sr.doc) { + if anchor == f[1:] { + return sr, nil + } + } + + // check in subresources that has same base url + prefix := sr.floc + "/" + for _, res := range r.subresources { + if strings.HasPrefix(res.floc, prefix) && r.baseURL(res.floc) == sr.url { + for _, anchor := range r.draft.anchors(res.doc) { + if anchor == f[1:] { + return res, nil + } + } + } + } + return nil, nil + } + + // resolve by ptr + floc := sr.floc + f[1:] + if res, ok := r.subresources[floc]; ok { + return res, nil + } + + // non-standrad location + doc := r.doc + for _, item := range strings.Split(floc[2:], "/") { + item = strings.Replace(item, "~1", "/", -1) + item = strings.Replace(item, "~0", "~", -1) + item, err := url.PathUnescape(item) + if err != nil { + return nil, err + } + switch d := doc.(type) { + case map[string]interface{}: + if _, ok := d[item]; !ok { + return nil, nil + } + doc = d[item] + case []interface{}: + index, err := strconv.Atoi(item) + if err != nil { + return nil, err + } + if index < 0 || index >= len(d) { + return nil, nil + } + doc = d[index] + default: + return nil, nil + } + } + + id, err := r.draft.resolveID(r.baseURL(floc), doc) + if err != nil { + return nil, err + } + res := &resource{url: id, floc: floc, doc: doc} + r.subresources[floc] = res + if err := r.fillSubschemas(c, res); err != nil { + return nil, err + } + return res, nil +} + +func (r *resource) baseURL(floc string) string { + for { + if sr, ok := r.subresources[floc]; ok { + if sr.url != "" { + return sr.url + } + } + slash := strings.LastIndexByte(floc, '/') + if slash == -1 { + break + } + floc = floc[:slash] + } + return r.url +} + +// url helpers --- + +func toAbs(s string) (string, error) { + // if windows absolute file path, convert to file url + // because: net/url parses driver name as scheme + if runtime.GOOS == "windows" && len(s) >= 3 && s[1:3] == `:\` { + s = "file:///" + filepath.ToSlash(s) + } + + u, err := url.Parse(s) + if err != nil { + return "", err + } + if u.IsAbs() { + return s, nil + } + + // s is filepath + if s, err = filepath.Abs(s); err != nil { + return "", err + } + if runtime.GOOS == "windows" { + s = "file:///" + filepath.ToSlash(s) + } else { + s = "file://" + s + } + u, err = url.Parse(s) // to fix spaces in filepath + return u.String(), err +} + +func resolveURL(base, ref string) (string, error) { + if ref == "" { + return base, nil + } + if strings.HasPrefix(ref, "urn:") { + return ref, nil + } + + refURL, err := url.Parse(ref) + if err != nil { + return "", err + } + if refURL.IsAbs() { + return ref, nil + } + + if strings.HasPrefix(base, "urn:") { + base, _ = split(base) + return base + ref, nil + } + + baseURL, err := url.Parse(base) + if err != nil { + return "", err + } + return baseURL.ResolveReference(refURL).String(), nil +} + +func split(uri string) (string, string) { + hash := strings.IndexByte(uri, '#') + if hash == -1 { + return uri, "#" + } + f := uri[hash:] + if f == "#/" { + f = "#" + } + return uri[0:hash], f +} + +func (s *Schema) url() string { + u, _ := split(s.Location) + return u +} + +func (s *Schema) loc() string { + _, f := split(s.Location) + return f[1:] +} + +func unmarshal(r io.Reader) (interface{}, error) { + decoder := json.NewDecoder(r) + decoder.UseNumber() + var doc interface{} + if err := decoder.Decode(&doc); err != nil { + return nil, err + } + if t, _ := decoder.Token(); t != nil { + return nil, fmt.Errorf("invalid character %v after top-level value", t) + } + return doc, nil +} diff --git a/vendor/github.com/santhosh-tekuri/jsonschema/v5/schema.go b/vendor/github.com/santhosh-tekuri/jsonschema/v5/schema.go new file mode 100644 index 0000000000..ff51aeb350 --- /dev/null +++ b/vendor/github.com/santhosh-tekuri/jsonschema/v5/schema.go @@ -0,0 +1,829 @@ +package jsonschema + +import ( + "bytes" + "encoding/json" + "fmt" + "math/big" + "net/url" + "regexp" + "strconv" + "strings" + "unicode/utf8" +) + +// A Schema represents compiled version of json-schema. +type Schema struct { + Location string // absolute location + + Draft *Draft // draft used by schema. + meta *Schema + vocab []string + dynamicAnchors []*Schema + + // type agnostic validations + Format string + format func(interface{}) bool + Always *bool // always pass/fail. used when booleans are used as schemas in draft-07. + Ref *Schema + RecursiveAnchor bool + RecursiveRef *Schema + DynamicAnchor string + DynamicRef *Schema + dynamicRefAnchor string + Types []string // allowed types. + Constant []interface{} // first element in slice is constant value. note: slice is used to capture nil constant. + Enum []interface{} // allowed values. + enumError string // error message for enum fail. captured here to avoid constructing error message every time. + Not *Schema + AllOf []*Schema + AnyOf []*Schema + OneOf []*Schema + If *Schema + Then *Schema // nil, when If is nil. + Else *Schema // nil, when If is nil. + + // object validations + MinProperties int // -1 if not specified. + MaxProperties int // -1 if not specified. + Required []string // list of required properties. + Properties map[string]*Schema + PropertyNames *Schema + RegexProperties bool // property names must be valid regex. used only in draft4 as workaround in metaschema. + PatternProperties map[*regexp.Regexp]*Schema + AdditionalProperties interface{} // nil or bool or *Schema. + Dependencies map[string]interface{} // map value is *Schema or []string. + DependentRequired map[string][]string + DependentSchemas map[string]*Schema + UnevaluatedProperties *Schema + + // array validations + MinItems int // -1 if not specified. + MaxItems int // -1 if not specified. + UniqueItems bool + Items interface{} // nil or *Schema or []*Schema + AdditionalItems interface{} // nil or bool or *Schema. + PrefixItems []*Schema + Items2020 *Schema // items keyword reintroduced in draft 2020-12 + Contains *Schema + ContainsEval bool // whether any item in an array that passes validation of the contains schema is considered "evaluated" + MinContains int // 1 if not specified + MaxContains int // -1 if not specified + UnevaluatedItems *Schema + + // string validations + MinLength int // -1 if not specified. + MaxLength int // -1 if not specified. + Pattern *regexp.Regexp + ContentEncoding string + decoder func(string) ([]byte, error) + ContentMediaType string + mediaType func([]byte) error + ContentSchema *Schema + + // number validators + Minimum *big.Rat + ExclusiveMinimum *big.Rat + Maximum *big.Rat + ExclusiveMaximum *big.Rat + MultipleOf *big.Rat + + // annotations. captured only when Compiler.ExtractAnnotations is true. + Title string + Description string + Default interface{} + Comment string + ReadOnly bool + WriteOnly bool + Examples []interface{} + Deprecated bool + + // user defined extensions + Extensions map[string]ExtSchema +} + +func (s *Schema) String() string { + return s.Location +} + +func newSchema(url, floc string, draft *Draft, doc interface{}) *Schema { + // fill with default values + s := &Schema{ + Location: url + floc, + Draft: draft, + MinProperties: -1, + MaxProperties: -1, + MinItems: -1, + MaxItems: -1, + MinContains: 1, + MaxContains: -1, + MinLength: -1, + MaxLength: -1, + } + + if doc, ok := doc.(map[string]interface{}); ok { + if ra, ok := doc["$recursiveAnchor"]; ok { + if ra, ok := ra.(bool); ok { + s.RecursiveAnchor = ra + } + } + if da, ok := doc["$dynamicAnchor"]; ok { + if da, ok := da.(string); ok { + s.DynamicAnchor = da + } + } + } + return s +} + +func (s *Schema) hasVocab(name string) bool { + if s == nil { // during bootstrap + return true + } + if name == "core" { + return true + } + for _, url := range s.vocab { + if url == "https://json-schema.org/draft/2019-09/vocab/"+name { + return true + } + if url == "https://json-schema.org/draft/2020-12/vocab/"+name { + return true + } + } + return false +} + +// Validate validates given doc, against the json-schema s. +// +// the v must be the raw json value. for number precision +// unmarshal with json.UseNumber(). +// +// returns *ValidationError if v does not confirm with schema s. +// returns InfiniteLoopError if it detects loop during validation. +// returns InvalidJSONTypeError if it detects any non json value in v. +func (s *Schema) Validate(v interface{}) (err error) { + return s.validateValue(v, "") +} + +func (s *Schema) validateValue(v interface{}, vloc string) (err error) { + defer func() { + if r := recover(); r != nil { + switch r := r.(type) { + case InfiniteLoopError, InvalidJSONTypeError: + err = r.(error) + default: + panic(r) + } + } + }() + if _, err := s.validate(nil, 0, "", v, vloc); err != nil { + ve := ValidationError{ + KeywordLocation: "", + AbsoluteKeywordLocation: s.Location, + InstanceLocation: vloc, + Message: fmt.Sprintf("doesn't validate with %s", s.Location), + } + return ve.causes(err) + } + return nil +} + +// validate validates given value v with this schema. +func (s *Schema) validate(scope []schemaRef, vscope int, spath string, v interface{}, vloc string) (result validationResult, err error) { + validationError := func(keywordPath string, format string, a ...interface{}) *ValidationError { + return &ValidationError{ + KeywordLocation: keywordLocation(scope, keywordPath), + AbsoluteKeywordLocation: joinPtr(s.Location, keywordPath), + InstanceLocation: vloc, + Message: fmt.Sprintf(format, a...), + } + } + + sref := schemaRef{spath, s, false} + if err := checkLoop(scope[len(scope)-vscope:], sref); err != nil { + panic(err) + } + scope = append(scope, sref) + vscope++ + + // populate result + switch v := v.(type) { + case map[string]interface{}: + result.unevalProps = make(map[string]struct{}) + for pname := range v { + result.unevalProps[pname] = struct{}{} + } + case []interface{}: + result.unevalItems = make(map[int]struct{}) + for i := range v { + result.unevalItems[i] = struct{}{} + } + } + + validate := func(sch *Schema, schPath string, v interface{}, vpath string) error { + vloc := vloc + if vpath != "" { + vloc += "/" + vpath + } + _, err := sch.validate(scope, 0, schPath, v, vloc) + return err + } + + validateInplace := func(sch *Schema, schPath string) error { + vr, err := sch.validate(scope, vscope, schPath, v, vloc) + if err == nil { + // update result + for pname := range result.unevalProps { + if _, ok := vr.unevalProps[pname]; !ok { + delete(result.unevalProps, pname) + } + } + for i := range result.unevalItems { + if _, ok := vr.unevalItems[i]; !ok { + delete(result.unevalItems, i) + } + } + } + return err + } + + if s.Always != nil { + if !*s.Always { + return result, validationError("", "not allowed") + } + return result, nil + } + + if len(s.Types) > 0 { + vType := jsonType(v) + matched := false + for _, t := range s.Types { + if vType == t { + matched = true + break + } else if t == "integer" && vType == "number" { + num, _ := new(big.Rat).SetString(fmt.Sprint(v)) + if num.IsInt() { + matched = true + break + } + } + } + if !matched { + return result, validationError("type", "expected %s, but got %s", strings.Join(s.Types, " or "), vType) + } + } + + var errors []error + + if len(s.Constant) > 0 { + if !equals(v, s.Constant[0]) { + switch jsonType(s.Constant[0]) { + case "object", "array": + errors = append(errors, validationError("const", "const failed")) + default: + errors = append(errors, validationError("const", "value must be %#v", s.Constant[0])) + } + } + } + + if len(s.Enum) > 0 { + matched := false + for _, item := range s.Enum { + if equals(v, item) { + matched = true + break + } + } + if !matched { + errors = append(errors, validationError("enum", s.enumError)) + } + } + + if s.format != nil && !s.format(v) { + var val = v + if v, ok := v.(string); ok { + val = quote(v) + } + errors = append(errors, validationError("format", "%v is not valid %s", val, quote(s.Format))) + } + + switch v := v.(type) { + case map[string]interface{}: + if s.MinProperties != -1 && len(v) < s.MinProperties { + errors = append(errors, validationError("minProperties", "minimum %d properties allowed, but found %d properties", s.MinProperties, len(v))) + } + if s.MaxProperties != -1 && len(v) > s.MaxProperties { + errors = append(errors, validationError("maxProperties", "maximum %d properties allowed, but found %d properties", s.MaxProperties, len(v))) + } + if len(s.Required) > 0 { + var missing []string + for _, pname := range s.Required { + if _, ok := v[pname]; !ok { + missing = append(missing, quote(pname)) + } + } + if len(missing) > 0 { + errors = append(errors, validationError("required", "missing properties: %s", strings.Join(missing, ", "))) + } + } + + for pname, sch := range s.Properties { + if pvalue, ok := v[pname]; ok { + delete(result.unevalProps, pname) + if err := validate(sch, "properties/"+escape(pname), pvalue, escape(pname)); err != nil { + errors = append(errors, err) + } + } + } + + if s.PropertyNames != nil { + for pname := range v { + if err := validate(s.PropertyNames, "propertyNames", pname, escape(pname)); err != nil { + errors = append(errors, err) + } + } + } + + if s.RegexProperties { + for pname := range v { + if !isRegex(pname) { + errors = append(errors, validationError("", "patternProperty %s is not valid regex", quote(pname))) + } + } + } + for pattern, sch := range s.PatternProperties { + for pname, pvalue := range v { + if pattern.MatchString(pname) { + delete(result.unevalProps, pname) + if err := validate(sch, "patternProperties/"+escape(pattern.String()), pvalue, escape(pname)); err != nil { + errors = append(errors, err) + } + } + } + } + if s.AdditionalProperties != nil { + if allowed, ok := s.AdditionalProperties.(bool); ok { + if !allowed && len(result.unevalProps) > 0 { + errors = append(errors, validationError("additionalProperties", "additionalProperties %s not allowed", result.unevalPnames())) + } + } else { + schema := s.AdditionalProperties.(*Schema) + for pname := range result.unevalProps { + if pvalue, ok := v[pname]; ok { + if err := validate(schema, "additionalProperties", pvalue, escape(pname)); err != nil { + errors = append(errors, err) + } + } + } + } + result.unevalProps = nil + } + for dname, dvalue := range s.Dependencies { + if _, ok := v[dname]; ok { + switch dvalue := dvalue.(type) { + case *Schema: + if err := validateInplace(dvalue, "dependencies/"+escape(dname)); err != nil { + errors = append(errors, err) + } + case []string: + for i, pname := range dvalue { + if _, ok := v[pname]; !ok { + errors = append(errors, validationError("dependencies/"+escape(dname)+"/"+strconv.Itoa(i), "property %s is required, if %s property exists", quote(pname), quote(dname))) + } + } + } + } + } + for dname, dvalue := range s.DependentRequired { + if _, ok := v[dname]; ok { + for i, pname := range dvalue { + if _, ok := v[pname]; !ok { + errors = append(errors, validationError("dependentRequired/"+escape(dname)+"/"+strconv.Itoa(i), "property %s is required, if %s property exists", quote(pname), quote(dname))) + } + } + } + } + for dname, sch := range s.DependentSchemas { + if _, ok := v[dname]; ok { + if err := validateInplace(sch, "dependentSchemas/"+escape(dname)); err != nil { + errors = append(errors, err) + } + } + } + + case []interface{}: + if s.MinItems != -1 && len(v) < s.MinItems { + errors = append(errors, validationError("minItems", "minimum %d items required, but found %d items", s.MinItems, len(v))) + } + if s.MaxItems != -1 && len(v) > s.MaxItems { + errors = append(errors, validationError("maxItems", "maximum %d items required, but found %d items", s.MaxItems, len(v))) + } + if s.UniqueItems { + for i := 1; i < len(v); i++ { + for j := 0; j < i; j++ { + if equals(v[i], v[j]) { + errors = append(errors, validationError("uniqueItems", "items at index %d and %d are equal", j, i)) + } + } + } + } + + // items + additionalItems + switch items := s.Items.(type) { + case *Schema: + for i, item := range v { + if err := validate(items, "items", item, strconv.Itoa(i)); err != nil { + errors = append(errors, err) + } + } + result.unevalItems = nil + case []*Schema: + for i, item := range v { + if i < len(items) { + delete(result.unevalItems, i) + if err := validate(items[i], "items/"+strconv.Itoa(i), item, strconv.Itoa(i)); err != nil { + errors = append(errors, err) + } + } else if sch, ok := s.AdditionalItems.(*Schema); ok { + delete(result.unevalItems, i) + if err := validate(sch, "additionalItems", item, strconv.Itoa(i)); err != nil { + errors = append(errors, err) + } + } else { + break + } + } + if additionalItems, ok := s.AdditionalItems.(bool); ok { + if additionalItems { + result.unevalItems = nil + } else if len(v) > len(items) { + errors = append(errors, validationError("additionalItems", "only %d items are allowed, but found %d items", len(items), len(v))) + } + } + } + + // prefixItems + items + for i, item := range v { + if i < len(s.PrefixItems) { + delete(result.unevalItems, i) + if err := validate(s.PrefixItems[i], "prefixItems/"+strconv.Itoa(i), item, strconv.Itoa(i)); err != nil { + errors = append(errors, err) + } + } else if s.Items2020 != nil { + delete(result.unevalItems, i) + if err := validate(s.Items2020, "items", item, strconv.Itoa(i)); err != nil { + errors = append(errors, err) + } + } else { + break + } + } + + // contains + minContains + maxContains + if s.Contains != nil && (s.MinContains != -1 || s.MaxContains != -1) { + matched := 0 + var causes []error + for i, item := range v { + if err := validate(s.Contains, "contains", item, strconv.Itoa(i)); err != nil { + causes = append(causes, err) + } else { + matched++ + if s.ContainsEval { + delete(result.unevalItems, i) + } + } + } + if s.MinContains != -1 && matched < s.MinContains { + errors = append(errors, validationError("minContains", "valid must be >= %d, but got %d", s.MinContains, matched).add(causes...)) + } + if s.MaxContains != -1 && matched > s.MaxContains { + errors = append(errors, validationError("maxContains", "valid must be <= %d, but got %d", s.MaxContains, matched)) + } + } + + case string: + // minLength + maxLength + if s.MinLength != -1 || s.MaxLength != -1 { + length := utf8.RuneCount([]byte(v)) + if s.MinLength != -1 && length < s.MinLength { + errors = append(errors, validationError("minLength", "length must be >= %d, but got %d", s.MinLength, length)) + } + if s.MaxLength != -1 && length > s.MaxLength { + errors = append(errors, validationError("maxLength", "length must be <= %d, but got %d", s.MaxLength, length)) + } + } + + if s.Pattern != nil && !s.Pattern.MatchString(v) { + errors = append(errors, validationError("pattern", "does not match pattern %s", quote(s.Pattern.String()))) + } + + // contentEncoding + contentMediaType + if s.decoder != nil || s.mediaType != nil { + decoded := s.ContentEncoding == "" + var content []byte + if s.decoder != nil { + b, err := s.decoder(v) + if err != nil { + errors = append(errors, validationError("contentEncoding", "value is not %s encoded", s.ContentEncoding)) + } else { + content, decoded = b, true + } + } + if decoded && s.mediaType != nil { + if s.decoder == nil { + content = []byte(v) + } + if err := s.mediaType(content); err != nil { + errors = append(errors, validationError("contentMediaType", "value is not of mediatype %s", quote(s.ContentMediaType))) + } + } + if decoded && s.ContentSchema != nil { + contentJSON, err := unmarshal(bytes.NewReader(content)) + if err != nil { + errors = append(errors, validationError("contentSchema", "value is not valid json")) + } else { + err := validate(s.ContentSchema, "contentSchema", contentJSON, "") + if err != nil { + errors = append(errors, err) + } + } + } + } + + case json.Number, float32, float64, int, int8, int32, int64, uint, uint8, uint32, uint64: + // lazy convert to *big.Rat to avoid allocation + var numVal *big.Rat + num := func() *big.Rat { + if numVal == nil { + numVal, _ = new(big.Rat).SetString(fmt.Sprint(v)) + } + return numVal + } + f64 := func(r *big.Rat) float64 { + f, _ := r.Float64() + return f + } + if s.Minimum != nil && num().Cmp(s.Minimum) < 0 { + errors = append(errors, validationError("minimum", "must be >= %v but found %v", f64(s.Minimum), v)) + } + if s.ExclusiveMinimum != nil && num().Cmp(s.ExclusiveMinimum) <= 0 { + errors = append(errors, validationError("exclusiveMinimum", "must be > %v but found %v", f64(s.ExclusiveMinimum), v)) + } + if s.Maximum != nil && num().Cmp(s.Maximum) > 0 { + errors = append(errors, validationError("maximum", "must be <= %v but found %v", f64(s.Maximum), v)) + } + if s.ExclusiveMaximum != nil && num().Cmp(s.ExclusiveMaximum) >= 0 { + errors = append(errors, validationError("exclusiveMaximum", "must be < %v but found %v", f64(s.ExclusiveMaximum), v)) + } + if s.MultipleOf != nil { + if q := new(big.Rat).Quo(num(), s.MultipleOf); !q.IsInt() { + errors = append(errors, validationError("multipleOf", "%v not multipleOf %v", v, f64(s.MultipleOf))) + } + } + } + + // $ref + $recursiveRef + $dynamicRef + validateRef := func(sch *Schema, refPath string) error { + if sch != nil { + if err := validateInplace(sch, refPath); err != nil { + var url = sch.Location + if s.url() == sch.url() { + url = sch.loc() + } + return validationError(refPath, "doesn't validate with %s", quote(url)).causes(err) + } + } + return nil + } + if err := validateRef(s.Ref, "$ref"); err != nil { + errors = append(errors, err) + } + if s.RecursiveRef != nil { + sch := s.RecursiveRef + if sch.RecursiveAnchor { + // recursiveRef based on scope + for _, e := range scope { + if e.schema.RecursiveAnchor { + sch = e.schema + break + } + } + } + if err := validateRef(sch, "$recursiveRef"); err != nil { + errors = append(errors, err) + } + } + if s.DynamicRef != nil { + sch := s.DynamicRef + if s.dynamicRefAnchor != "" && sch.DynamicAnchor == s.dynamicRefAnchor { + // dynamicRef based on scope + for i := len(scope) - 1; i >= 0; i-- { + sr := scope[i] + if sr.discard { + break + } + for _, da := range sr.schema.dynamicAnchors { + if da.DynamicAnchor == s.DynamicRef.DynamicAnchor && da != s.DynamicRef { + sch = da + break + } + } + } + } + if err := validateRef(sch, "$dynamicRef"); err != nil { + errors = append(errors, err) + } + } + + if s.Not != nil && validateInplace(s.Not, "not") == nil { + errors = append(errors, validationError("not", "not failed")) + } + + for i, sch := range s.AllOf { + schPath := "allOf/" + strconv.Itoa(i) + if err := validateInplace(sch, schPath); err != nil { + errors = append(errors, validationError(schPath, "allOf failed").add(err)) + } + } + + if len(s.AnyOf) > 0 { + matched := false + var causes []error + for i, sch := range s.AnyOf { + if err := validateInplace(sch, "anyOf/"+strconv.Itoa(i)); err == nil { + matched = true + } else { + causes = append(causes, err) + } + } + if !matched { + errors = append(errors, validationError("anyOf", "anyOf failed").add(causes...)) + } + } + + if len(s.OneOf) > 0 { + matched := -1 + var causes []error + for i, sch := range s.OneOf { + if err := validateInplace(sch, "oneOf/"+strconv.Itoa(i)); err == nil { + if matched == -1 { + matched = i + } else { + errors = append(errors, validationError("oneOf", "valid against schemas at indexes %d and %d", matched, i)) + break + } + } else { + causes = append(causes, err) + } + } + if matched == -1 { + errors = append(errors, validationError("oneOf", "oneOf failed").add(causes...)) + } + } + + // if + then + else + if s.If != nil { + err := validateInplace(s.If, "if") + // "if" leaves dynamic scope + scope[len(scope)-1].discard = true + if err == nil { + if s.Then != nil { + if err := validateInplace(s.Then, "then"); err != nil { + errors = append(errors, validationError("then", "if-then failed").add(err)) + } + } + } else { + if s.Else != nil { + if err := validateInplace(s.Else, "else"); err != nil { + errors = append(errors, validationError("else", "if-else failed").add(err)) + } + } + } + // restore dynamic scope + scope[len(scope)-1].discard = false + } + + for _, ext := range s.Extensions { + if err := ext.Validate(ValidationContext{result, validate, validateInplace, validationError}, v); err != nil { + errors = append(errors, err) + } + } + + // unevaluatedProperties + unevaluatedItems + switch v := v.(type) { + case map[string]interface{}: + if s.UnevaluatedProperties != nil { + for pname := range result.unevalProps { + if pvalue, ok := v[pname]; ok { + if err := validate(s.UnevaluatedProperties, "unevaluatedProperties", pvalue, escape(pname)); err != nil { + errors = append(errors, err) + } + } + } + result.unevalProps = nil + } + case []interface{}: + if s.UnevaluatedItems != nil { + for i := range result.unevalItems { + if err := validate(s.UnevaluatedItems, "unevaluatedItems", v[i], strconv.Itoa(i)); err != nil { + errors = append(errors, err) + } + } + result.unevalItems = nil + } + } + + switch len(errors) { + case 0: + return result, nil + case 1: + return result, errors[0] + default: + return result, validationError("", "").add(errors...) // empty message, used just for wrapping + } +} + +type validationResult struct { + unevalProps map[string]struct{} + unevalItems map[int]struct{} +} + +func (vr validationResult) unevalPnames() string { + pnames := make([]string, 0, len(vr.unevalProps)) + for pname := range vr.unevalProps { + pnames = append(pnames, quote(pname)) + } + return strings.Join(pnames, ", ") +} + +// jsonType returns the json type of given value v. +// +// It panics if the given value is not valid json value +func jsonType(v interface{}) string { + switch v.(type) { + case nil: + return "null" + case bool: + return "boolean" + case json.Number, float32, float64, int, int8, int32, int64, uint, uint8, uint32, uint64: + return "number" + case string: + return "string" + case []interface{}: + return "array" + case map[string]interface{}: + return "object" + } + panic(InvalidJSONTypeError(fmt.Sprintf("%T", v))) +} + +// equals tells if given two json values are equal or not. +func equals(v1, v2 interface{}) bool { + v1Type := jsonType(v1) + if v1Type != jsonType(v2) { + return false + } + switch v1Type { + case "array": + arr1, arr2 := v1.([]interface{}), v2.([]interface{}) + if len(arr1) != len(arr2) { + return false + } + for i := range arr1 { + if !equals(arr1[i], arr2[i]) { + return false + } + } + return true + case "object": + obj1, obj2 := v1.(map[string]interface{}), v2.(map[string]interface{}) + if len(obj1) != len(obj2) { + return false + } + for k, v1 := range obj1 { + if v2, ok := obj2[k]; ok { + if !equals(v1, v2) { + return false + } + } else { + return false + } + } + return true + case "number": + num1, _ := new(big.Rat).SetString(fmt.Sprint(v1)) + num2, _ := new(big.Rat).SetString(fmt.Sprint(v2)) + return num1.Cmp(num2) == 0 + default: + return v1 == v2 + } +} + +// escape converts given token to valid json-pointer token +func escape(token string) string { + token = strings.ReplaceAll(token, "~", "~0") + token = strings.ReplaceAll(token, "/", "~1") + return url.PathEscape(token) +} diff --git a/vendor/github.com/senseyeio/duration/.travis.yml b/vendor/github.com/senseyeio/duration/.travis.yml new file mode 100644 index 0000000000..be839df16e --- /dev/null +++ b/vendor/github.com/senseyeio/duration/.travis.yml @@ -0,0 +1,14 @@ +language: go + +before_install: + - go get github.com/mattn/goveralls + - go get github.com/modocache/gover + +script: + - go test -race -v ./... + - ./coveralls.bash + +go: + - 1.9.x + - 1.10.x + - tip diff --git a/vendor/github.com/senseyeio/duration/LICENSE b/vendor/github.com/senseyeio/duration/LICENSE new file mode 100644 index 0000000000..8d01738760 --- /dev/null +++ b/vendor/github.com/senseyeio/duration/LICENSE @@ -0,0 +1,22 @@ +MIT License + +Copyright (c) 2018 Senseye +Adapted from https://github.com/ChannelMeter/iso8601duration, Copyright (c) 2014 ChannelMeter + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/senseyeio/duration/README.md b/vendor/github.com/senseyeio/duration/README.md new file mode 100644 index 0000000000..b802bbb2a8 --- /dev/null +++ b/vendor/github.com/senseyeio/duration/README.md @@ -0,0 +1,84 @@ +Duration [![Build](https://travis-ci.org/senseyeio/duration.svg?branch=master)](https://travis-ci.org/senseyeio/duration) [![Coverage](https://coveralls.io/repos/github/senseyeio/duration/badge.svg?branch=master)](https://coveralls.io/github/senseyeio/duration?branch=master) [![Go Report Card](https://goreportcard.com/badge/senseyeio/duration)](https://goreportcard.com/report/senseyeio/duration) [![GoDoc](https://godoc.org/github.com/senseyeio/duration?status.svg)](https://godoc.org/github.com/senseyeio/duration) +======= +Parse ISO8601 duration strings, and use to shift dates/times. + +Basic Example +------------- + +```go +package main + +import ( + "fmt" + "time" + + "github.com/senseyeio/duration" +) + +func main() { + d, _ := iso8601.ParseISO8601("P1D") + today := time.Now() + tomorrow := d.Shift(today) + fmt.Println(today.Format("Jan _2")) + fmt.Println(tomorrow.Format("Jan _2")) +} +``` + +Why Does This Package Exist +--------------------------- +> Why can't we just use a `time.Duration` and `time.Add`? + +A very reasonable question. + +The code below repeatedly adds 24 hours to a `time.Time`. You might expect the time on that date to stay the same, but [_there are not always 24 hours in a day_](http://infiniteundo.com/post/25326999628/falsehoods-programmers-believe-about-time). When the clocks change in New York, the time will skew by an hour. As you can see from the output, duration.Duration.Shift() can increment the date without shifting the time. + +```go +package main + +import ( + "fmt" + "time" + + "github.com/senseyeio/duration" +) + +func main() { + loc, _ := time.LoadLocation("America/New_York") + d, _ := iso8601.ParseISO8601("P1D") + t1, _ := time.ParseInLocation("Jan 2, 2006 at 3:04pm", "Jan 1, 2006 at 3:04pm", loc) + t2 := t1 + for i := 0; i < 365; i++ { + t1 = t1.Add(24 * time.Hour) + t2 = d.Shift(t2) + fmt.Printf("time.Add:%d Duration.Shift:%d\n", t1.Hour(), t2.Hour()) + } +} + +// Outputs +// time.Add:15 Duration.Shift:15 +// time.Add:15 Duration.Shift:15 +// time.Add:15 Duration.Shift:15 +// ... +// time.Add:16 Duration.Shift:15 +// time.Add:16 Duration.Shift:15 +// time.Add:16 Duration.Shift:15 +// ... +``` + +------- +Months are tricky. Shifting by months uses `time.AddDate()`, which is great. However, be aware of how differing days in the month are accommodated. Dates will 'roll over' if the month you're shifting to has fewer days. e.g. if you start on Jan 30th and repeat every "P1M", you'll get this: + +``` +Jan 30, 2006 +Mar 2, 2006 +Apr 2, 2006 +May 2, 2006 +Jun 2, 2006 +Jul 2, 2006 +Aug 2, 2006 +Sep 2, 2006 +Oct 2, 2006 +Nov 2, 2006 +Dec 2, 2006 +Jan 2, 2007 +``` diff --git a/vendor/github.com/senseyeio/duration/coveralls.bash b/vendor/github.com/senseyeio/duration/coveralls.bash new file mode 100644 index 0000000000..ac5b5716ad --- /dev/null +++ b/vendor/github.com/senseyeio/duration/coveralls.bash @@ -0,0 +1,25 @@ +#!/usr/bin/env bash + +if ! type -P gover +then + echo gover missing: go get github.com/modocache/gover + exit 1 +fi + +if ! type -P goveralls +then + echo goveralls missing: go get github.com/mattn/goveralls + exit 1 +fi + +if [[ "$COVERALLS_TOKEN" == "" ]] +then + echo COVERALLS_TOKEN not set + exit 1 +fi + +go test -covermode count -coverprofile coverage.coverprofile + +gover +goveralls -coverprofile gover.coverprofile -service travis-ci -repotoken $COVERALLS_TOKEN +find . -name '*.coverprofile' -delete diff --git a/vendor/github.com/senseyeio/duration/duration.go b/vendor/github.com/senseyeio/duration/duration.go new file mode 100644 index 0000000000..7163e3df9b --- /dev/null +++ b/vendor/github.com/senseyeio/duration/duration.go @@ -0,0 +1,146 @@ +// Package duration handles ISO8601-formatted durations. +package duration + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" + "html/template" + "regexp" + "strconv" + "time" +) + +// Duration represents an ISO8601 Duration +// https://en.wikipedia.org/wiki/ISO_8601#Durations +type Duration struct { + Y int + M int + W int + D int + // Time Component + TH int + TM int + TS int +} + +var pattern = regexp.MustCompile(`^P((?P\d+)Y)?((?P\d+)M)?((?P\d+)W)?((?P\d+)D)?(T((?P\d+)H)?((?P\d+)M)?((?P\d+)S)?)?$`) + +// ParseISO8601 parses an ISO8601 duration string. +func ParseISO8601(from string) (Duration, error) { + var match []string + var d Duration + + if pattern.MatchString(from) { + match = pattern.FindStringSubmatch(from) + } else { + return d, errors.New("could not parse duration string") + } + + for i, name := range pattern.SubexpNames() { + part := match[i] + if i == 0 || name == "" || part == "" { + continue + } + + val, err := strconv.Atoi(part) + if err != nil { + return d, err + } + switch name { + case "year": + d.Y = val + case "month": + d.M = val + case "week": + d.W = val + case "day": + d.D = val + case "hour": + d.TH = val + case "minute": + d.TM = val + case "second": + d.TS = val + default: + return d, fmt.Errorf("unknown field %s", name) + } + } + + return d, nil +} + +// IsZero reports whether d represents the zero duration, P0D. +func (d Duration) IsZero() bool { + return d.Y == 0 && d.M == 0 && d.W == 0 && d.D == 0 && d.TH == 0 && d.TM == 0 && d.TS == 0 +} + +// HasTimePart returns true if the time part of the duration is non-zero. +func (d Duration) HasTimePart() bool { + return d.TH > 0 || d.TM > 0 || d.TS > 0 +} + +// Shift returns a time.Time, shifted by the duration from the given start. +// +// NB: Shift uses time.AddDate for years, months, weeks, and days, and so +// shares its limitations. In particular, shifting by months is not recommended +// unless the start date is before the 28th of the month. Otherwise, dates will +// roll over, e.g. Aug 31 + P1M = Oct 1. +// +// Week and Day values will be combined as W*7 + D. +func (d Duration) Shift(t time.Time) time.Time { + if d.Y != 0 || d.M != 0 || d.W != 0 || d.D != 0 { + days := d.W*7 + d.D + t = t.AddDate(d.Y, d.M, days) + } + t = t.Add(d.timeDuration()) + return t +} + +func (d Duration) timeDuration() time.Duration { + var dur time.Duration + dur = dur + (time.Duration(d.TH) * time.Hour) + dur = dur + (time.Duration(d.TM) * time.Minute) + dur = dur + (time.Duration(d.TS) * time.Second) + return dur +} + +var tmpl = template.Must(template.New("duration").Parse(`P{{if .Y}}{{.Y}}Y{{end}}{{if .M}}{{.M}}M{{end}}{{if .W}}{{.W}}W{{end}}{{if .D}}{{.D}}D{{end}}{{if .HasTimePart}}T{{end }}{{if .TH}}{{.TH}}H{{end}}{{if .TM}}{{.TM}}M{{end}}{{if .TS}}{{.TS}}S{{end}}`)) + +// String returns an ISO8601-ish representation of the duration. +func (d Duration) String() string { + var s bytes.Buffer + + if d.IsZero() { + return "P0D" + } + + err := tmpl.Execute(&s, d) + if err != nil { + panic(err) + } + + return s.String() +} + +// MarshalJSON satisfies json.Marshaler. +func (d Duration) MarshalJSON() ([]byte, error) { + return json.Marshal(d.String()) +} + +// UnmarshalJSON satisfies json.Unmarshaler. +func (d *Duration) UnmarshalJSON(b []byte) error { + var s string + if err := json.Unmarshal(b, &s); err != nil { + return err + } + + tmp, err := ParseISO8601(s) + if err != nil { + return err + } + *d = tmp + + return nil +} diff --git a/vendor/github.com/serverlessworkflow/sdk-go/v2/LICENSE b/vendor/github.com/serverlessworkflow/sdk-go/v2/LICENSE new file mode 100644 index 0000000000..261eeb9e9f --- /dev/null +++ b/vendor/github.com/serverlessworkflow/sdk-go/v2/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/serverlessworkflow/sdk-go/v2/model/action.go b/vendor/github.com/serverlessworkflow/sdk-go/v2/model/action.go new file mode 100644 index 0000000000..5037ed13e0 --- /dev/null +++ b/vendor/github.com/serverlessworkflow/sdk-go/v2/model/action.go @@ -0,0 +1,121 @@ +// Copyright 2022 The Serverless Workflow Specification Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package model + +// Action specify invocations of services or other workflows during workflow execution. +type Action struct { + // Defines Unique action identifier. + // +optional + ID string `json:"id,omitempty"` + // Defines Unique action name. + // +optional + Name string `json:"name,omitempty"` + // References a reusable function definition. + // +optional + FunctionRef *FunctionRef `json:"functionRef,omitempty"` + // References a 'trigger' and 'result' reusable event definitions. + // +optional + EventRef *EventRef `json:"eventRef,omitempty"` + // References a workflow to be invoked. + // +optional + SubFlowRef *WorkflowRef `json:"subFlowRef,omitempty"` + // Defines time period workflow execution should sleep before / after function execution. + // +optional + Sleep *Sleep `json:"sleep,omitempty"` + // References a defined workflow retry definition. If not defined uses the default runtime retry definition. + // +optional + RetryRef string `json:"retryRef,omitempty"` + // List of unique references to defined workflow errors for which the action should not be retried. + // Used only when `autoRetries` is set to `true` + // +optional + NonRetryableErrors []string `json:"nonRetryableErrors,omitempty" validate:"omitempty,min=1"` + // List of unique references to defined workflow errors for which the action should be retried. + // Used only when `autoRetries` is set to `false` + // +optional + RetryableErrors []string `json:"retryableErrors,omitempty" validate:"omitempty,min=1"` + // Filter the state data to select only the data that can be used within function definition arguments + // using its fromStateData property. Filter the action results to select only the result data that should + // be added/merged back into the state data using its results property. Select the part of state data which + // the action data results should be added/merged to using the toStateData property. + // +optional + ActionDataFilter ActionDataFilter `json:"actionDataFilter,omitempty"` + // Expression, if defined, must evaluate to true for this action to be performed. If false, action is disregarded. + // +optional + Condition string `json:"condition,omitempty"` +} + +type actionUnmarshal Action + +// UnmarshalJSON implements json.Unmarshaler +func (a *Action) UnmarshalJSON(data []byte) error { + a.ApplyDefault() + return unmarshalObject("action", data, (*actionUnmarshal)(a)) +} + +// ApplyDefault set the default values for Action +func (a *Action) ApplyDefault() { + a.ActionDataFilter.ApplyDefault() +} + +// FunctionRef defines the reference to a reusable function definition +type FunctionRef struct { + // Name of the referenced function. + // +kubebuilder:validation:Required + RefName string `json:"refName" validate:"required"` + // Arguments (inputs) to be passed to the referenced function + // +optional + // TODO: validate it as required if function type is graphql + Arguments map[string]Object `json:"arguments,omitempty"` + // Used if function type is graphql. String containing a valid GraphQL selection set. + // TODO: validate it as required if function type is graphql + // +optional + SelectionSet string `json:"selectionSet,omitempty"` + // Specifies if the function should be invoked sync or async. Default is sync. + // +kubebuilder:validation:Enum=async;sync + // +kubebuilder:default=sync + Invoke InvokeKind `json:"invoke,omitempty" validate:"required,oneofkind"` +} + +type functionRefUnmarshal FunctionRef + +// UnmarshalJSON implements json.Unmarshaler +func (f *FunctionRef) UnmarshalJSON(data []byte) error { + f.ApplyDefault() + return unmarshalPrimitiveOrObject("functionRef", data, &f.RefName, (*functionRefUnmarshal)(f)) +} + +// ApplyDefault set the default values for Function Ref +func (f *FunctionRef) ApplyDefault() { + f.Invoke = InvokeKindSync +} + +// Sleep defines time periods workflow execution should sleep before & after function execution +type Sleep struct { + // Defines amount of time (ISO 8601 duration format) to sleep before function/subflow invocation. + // Does not apply if 'eventRef' is defined. + // +optional + Before string `json:"before,omitempty" validate:"omitempty,iso8601duration"` + // Defines amount of time (ISO 8601 duration format) to sleep after function/subflow invocation. + // Does not apply if 'eventRef' is defined. + // +optional + After string `json:"after,omitempty" validate:"omitempty,iso8601duration"` +} + +type sleepUnmarshal Sleep + +// UnmarshalJSON implements json.Unmarshaler +func (s *Sleep) UnmarshalJSON(data []byte) error { + return unmarshalObject("sleep", data, (*sleepUnmarshal)(s)) +} diff --git a/vendor/github.com/serverlessworkflow/sdk-go/v2/model/action_data_filter.go b/vendor/github.com/serverlessworkflow/sdk-go/v2/model/action_data_filter.go new file mode 100644 index 0000000000..16f161525d --- /dev/null +++ b/vendor/github.com/serverlessworkflow/sdk-go/v2/model/action_data_filter.go @@ -0,0 +1,49 @@ +// Copyright 2022 The Serverless Workflow Specification Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package model + +// ActionDataFilter used to filter action data results. +// +optional +// +optional +type ActionDataFilter struct { + // Workflow expression that filters state data that can be used by the action. + // +optional + // +optional + FromStateData string `json:"fromStateData,omitempty"` + // If set to false, action data results are not added/merged to state data. In this case 'results' + // and 'toStateData' should be ignored. Default is true. + // +optional + UseResults bool `json:"useResults,omitempty"` + // Workflow expression that filters the actions data results. + // +optional + Results string `json:"results,omitempty"` + // Workflow expression that selects a state data element to which the action results should be + // added/merged into. If not specified denotes the top-level state data element. + // +optional + ToStateData string `json:"toStateData,omitempty"` +} + +type actionDataFilterUnmarshal ActionDataFilter + +// UnmarshalJSON implements json.Unmarshaler +func (a *ActionDataFilter) UnmarshalJSON(data []byte) error { + a.ApplyDefault() + return unmarshalObject("actionDataFilter", data, (*actionDataFilterUnmarshal)(a)) +} + +// ApplyDefault set the default values for Action Data Filter +func (a *ActionDataFilter) ApplyDefault() { + a.UseResults = true +} diff --git a/vendor/github.com/serverlessworkflow/sdk-go/v2/model/auth.go b/vendor/github.com/serverlessworkflow/sdk-go/v2/model/auth.go new file mode 100644 index 0000000000..9646633bf8 --- /dev/null +++ b/vendor/github.com/serverlessworkflow/sdk-go/v2/model/auth.go @@ -0,0 +1,195 @@ +// Copyright 2021 The Serverless Workflow Specification Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package model + +import ( + "encoding/json" + "fmt" + "strings" +) + +// AuthType can be "basic", "bearer", or "oauth2". Default is "basic" +type AuthType string + +const ( + // AuthTypeBasic ... + AuthTypeBasic AuthType = "basic" + // AuthTypeBearer ... + AuthTypeBearer AuthType = "bearer" + // AuthTypeOAuth2 ... + AuthTypeOAuth2 AuthType = "oauth2" +) + +// GrantType ... +type GrantType string + +const ( + // GrantTypePassword ... + GrantTypePassword GrantType = "password" + // GrantTypeClientCredentials ... + GrantTypeClientCredentials GrantType = "clientCredentials" + // GrantTypeTokenExchange ... + GrantTypeTokenExchange GrantType = "tokenExchange" +) + +// Auth definitions can be used to define authentication information that should be applied to resources +// defined in the operation property of function definitions. It is not used as authentication information +// for the function invocation, but just to access the resource containing the function invocation information. +type Auth struct { + // Unique auth definition name. + // +kubebuilder:validation:Required + Name string `json:"name" validate:"required"` + // Auth scheme, can be "basic", "bearer", or "oauth2". Default is "basic" + // +kubebuilder:validation:Enum=basic;bearer;oauth2 + // +kubebuilder:default=basic + // +kubebuilder:validation:Required + Scheme AuthType `json:"scheme" validate:"min=1"` + // Auth scheme properties. Can be one of "Basic properties definition", "Bearer properties definition", + // or "OAuth2 properties definition" + // +kubebuilder:validation:Required + Properties AuthProperties `json:"properties" validate:"required"` +} + +type authUnmarshal Auth + +// UnmarshalJSON Auth definition +func (a *Auth) UnmarshalJSON(data []byte) error { + authTmp := struct { + authUnmarshal + PropertiesRaw json.RawMessage `json:"properties"` + }{} + + err := unmarshalObjectOrFile("auth", data, &authTmp) + if err != nil { + return err + } + + *a = Auth(authTmp.authUnmarshal) + if len(a.Scheme) == 0 { + a.Scheme = AuthTypeBasic + } + + switch a.Scheme { + case AuthTypeBasic: + a.Properties.Basic = &BasicAuthProperties{} + return unmarshalObject("properties", authTmp.PropertiesRaw, a.Properties.Basic) + case AuthTypeBearer: + a.Properties.Bearer = &BearerAuthProperties{} + return unmarshalObject("properties", authTmp.PropertiesRaw, a.Properties.Bearer) + case AuthTypeOAuth2: + a.Properties.OAuth2 = &OAuth2AuthProperties{} + return unmarshalObject("properties", authTmp.PropertiesRaw, a.Properties.OAuth2) + default: + return fmt.Errorf("failed to parse auth properties") + } +} + +func (a *Auth) MarshalJSON() ([]byte, error) { + custom, err := json.Marshal(&struct { + Name string `json:"name" validate:"required"` + Scheme AuthType `json:"scheme,omitempty" validate:"omitempty,min=1"` + Properties AuthProperties `json:"properties" validate:"required"` + }{ + Name: a.Name, + Scheme: a.Scheme, + Properties: a.Properties, + }) + if err != nil { + fmt.Println(err) + } + st := strings.Replace(string(custom), "null,", "", 1) + st = strings.Replace(st, "\"Basic\":", "", 1) + st = strings.Replace(st, "\"Oauth2\":", "", 1) + st = strings.Replace(st, "\"Bearer\":", "", 1) + st = strings.Replace(st, "{{", "{", 1) + st = strings.TrimSuffix(st, "}") + return []byte(st), nil +} + +// AuthProperties ... +type AuthProperties struct { + Basic *BasicAuthProperties `json:",omitempty"` + Bearer *BearerAuthProperties `json:",omitempty"` + OAuth2 *OAuth2AuthProperties `json:",omitempty"` +} + +// BasicAuthProperties Basic Auth Info +type BasicAuthProperties struct { + Common `json:",inline"` + // Secret Expression referencing a workflow secret that contains all needed auth info + // +optional + Secret string `json:"secret,omitempty"` + // Username String or a workflow expression. Contains the username + // +kubebuilder:validation:Required + Username string `json:"username" validate:"required"` + // Password String or a workflow expression. Contains the user password + // +kubebuilder:validation:Required + Password string `json:"password" validate:"required"` +} + +// BearerAuthProperties Bearer auth information +type BearerAuthProperties struct { + Common `json:",inline"` + // Secret Expression referencing a workflow secret that contains all needed auth info + // +optional + Secret string `json:"secret,omitempty"` + // Token String or a workflow expression. Contains the token + // +kubebuilder:validation:Required + Token string `json:"token" validate:"required"` +} + +// OAuth2AuthProperties OAuth2 information +type OAuth2AuthProperties struct { + Common `json:",inline"` + // Expression referencing a workflow secret that contains all needed auth info. + // +optional + Secret string `json:"secret,omitempty"` + // String or a workflow expression. Contains the authority information. + // +optional + Authority string `json:"authority,omitempty" validate:"omitempty,min=1"` + // Defines the grant type. Can be "password", "clientCredentials", or "tokenExchange" + // +kubebuilder:validation:Enum=password;clientCredentials;tokenExchange + // +kubebuilder:validation:Required + GrantType GrantType `json:"grantType" validate:"required"` + // String or a workflow expression. Contains the client identifier. + // +kubebuilder:validation:Required + ClientID string `json:"clientId" validate:"required"` + // Workflow secret or a workflow expression. Contains the client secret. + // +optional + ClientSecret string `json:"clientSecret,omitempty" validate:"omitempty,min=1"` + // Array containing strings or workflow expressions. Contains the OAuth2 scopes. + // +optional + Scopes []string `json:"scopes,omitempty" validate:"omitempty,min=1"` + // String or a workflow expression. Contains the username. Used only if grantType is 'resourceOwner'. + // +optional + Username string `json:"username,omitempty" validate:"omitempty,min=1"` + // String or a workflow expression. Contains the user password. Used only if grantType is 'resourceOwner'. + // +optional + Password string `json:"password,omitempty" validate:"omitempty,min=1"` + // Array containing strings or workflow expressions. Contains the OAuth2 audiences. + // +optional + Audiences []string `json:"audiences,omitempty" validate:"omitempty,min=1"` + // String or a workflow expression. Contains the subject token. + // +optional + SubjectToken string `json:"subjectToken,omitempty" validate:"omitempty,min=1"` + // String or a workflow expression. Contains the requested subject. + // +optional + RequestedSubject string `json:"requestedSubject,omitempty" validate:"omitempty,min=1"` + // String or a workflow expression. Contains the requested issuer. + // +optional + RequestedIssuer string `json:"requestedIssuer,omitempty" validate:"omitempty,min=1"` +} + +// TODO: use reflection to unmarshal the keys and think on a generic approach to handle them diff --git a/vendor/github.com/serverlessworkflow/sdk-go/v2/model/callback_state.go b/vendor/github.com/serverlessworkflow/sdk-go/v2/model/callback_state.go new file mode 100644 index 0000000000..f35ec3871f --- /dev/null +++ b/vendor/github.com/serverlessworkflow/sdk-go/v2/model/callback_state.go @@ -0,0 +1,60 @@ +// Copyright 2022 The Serverless Workflow Specification Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package model + +import ( + "encoding/json" +) + +// CallbackState executes a function and waits for callback event that indicates completion of the task. +type CallbackState struct { + // Defines the action to be executed. + // +kubebuilder:validation:Required + Action Action `json:"action" validate:"required"` + // References a unique callback event name in the defined workflow events. + // +kubebuilder:validation:Required + EventRef string `json:"eventRef" validate:"required"` + // Time period to wait for incoming events (ISO 8601 format) + // +optional + Timeouts *CallbackStateTimeout `json:"timeouts,omitempty"` + // Event data filter definition. + // +optional + EventDataFilter *EventDataFilter `json:"eventDataFilter,omitempty"` +} + +func (c *CallbackState) MarshalJSON() ([]byte, error) { + type Alias CallbackState + custom, err := json.Marshal(&struct { + *Alias + Timeouts *CallbackStateTimeout `json:"timeouts,omitempty"` + }{ + Alias: (*Alias)(c), + Timeouts: c.Timeouts, + }) + return custom, err +} + +// CallbackStateTimeout defines timeout settings for callback state +type CallbackStateTimeout struct { + // Default workflow state execution timeout (ISO 8601 duration format) + // +optional + StateExecTimeout *StateExecTimeout `json:"stateExecTimeout,omitempty"` + // Default single actions definition execution timeout (ISO 8601 duration format) + // +optional + ActionExecTimeout string `json:"actionExecTimeout,omitempty" validate:"omitempty,iso8601duration"` + // Default timeout for consuming defined events (ISO 8601 duration format) + // +optional + EventTimeout string `json:"eventTimeout,omitempty" validate:"omitempty,iso8601duration"` +} diff --git a/vendor/github.com/serverlessworkflow/sdk-go/v2/model/common.go b/vendor/github.com/serverlessworkflow/sdk-go/v2/model/common.go new file mode 100644 index 0000000000..6a9be3b2ca --- /dev/null +++ b/vendor/github.com/serverlessworkflow/sdk-go/v2/model/common.go @@ -0,0 +1,25 @@ +// Copyright 2021 The Serverless Workflow Specification Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package model + +// Common schema for Serverless Workflow specification +type Common struct { + // Metadata information + // +optional + Metadata Metadata `json:"metadata,omitempty"` +} + +// Metadata information +type Metadata map[string]Object diff --git a/vendor/github.com/serverlessworkflow/sdk-go/v2/model/delay_state.go b/vendor/github.com/serverlessworkflow/sdk-go/v2/model/delay_state.go new file mode 100644 index 0000000000..3227e740a0 --- /dev/null +++ b/vendor/github.com/serverlessworkflow/sdk-go/v2/model/delay_state.go @@ -0,0 +1,33 @@ +// Copyright 2022 The Serverless Workflow Specification Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package model + +import "encoding/json" + +// DelayState Causes the workflow execution to delay for a specified duration +type DelayState struct { + // Amount of time (ISO 8601 format) to delay + // +kubebuilder:validation:Required + TimeDelay string `json:"timeDelay" validate:"required,iso8601duration"` +} + +func (a *DelayState) MarshalJSON() ([]byte, error) { + custom, err := json.Marshal(&struct { + TimeDelay string `json:"timeDelay" validate:"required,iso8601duration"` + }{ + TimeDelay: a.TimeDelay, + }) + return custom, err +} diff --git a/vendor/github.com/serverlessworkflow/sdk-go/v2/model/doc.go b/vendor/github.com/serverlessworkflow/sdk-go/v2/model/doc.go new file mode 100644 index 0000000000..1508354aa9 --- /dev/null +++ b/vendor/github.com/serverlessworkflow/sdk-go/v2/model/doc.go @@ -0,0 +1,18 @@ +// Copyright 2022 The Serverless Workflow Specification Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package model + +// +k8s:deepcopy-gen=package +// +k8s:deepcopy-gen:nonpointer-interfaces=true diff --git a/vendor/github.com/serverlessworkflow/sdk-go/v2/model/event.go b/vendor/github.com/serverlessworkflow/sdk-go/v2/model/event.go new file mode 100644 index 0000000000..08545c5877 --- /dev/null +++ b/vendor/github.com/serverlessworkflow/sdk-go/v2/model/event.go @@ -0,0 +1,114 @@ +// Copyright 2021 The Serverless Workflow Specification Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package model + +// EventKind defines this event as either `consumed` or `produced` +type EventKind string + +const ( + // EventKindConsumed means the event continuation of workflow instance execution + EventKindConsumed EventKind = "consumed" + + // EventKindProduced means the event was created during workflow instance execution + EventKindProduced EventKind = "produced" +) + +// Event used to define events and their correlations +type Event struct { + Common `json:",inline"` + // Unique event name. + // +kubebuilder:validation:Required + Name string `json:"name" validate:"required"` + // CloudEvent source. + // +optional + Source string `json:"source,omitempty"` + // CloudEvent type. + // +kubebuilder:validation:Required + Type string `json:"type" validate:"required"` + // Defines the CloudEvent as either 'consumed' or 'produced' by the workflow. Defaults to `consumed`. + // +kubebuilder:validation:Enum=consumed;produced + // +kubebuilder:default=consumed + Kind EventKind `json:"kind,omitempty"` + // If `true`, only the Event payload is accessible to consuming Workflow states. If `false`, both event payload + // and context attributes should be accessible. Defaults to true. + // +optional + DataOnly bool `json:"dataOnly,omitempty"` + // Define event correlation rules for this event. Only used for consumed events. + // +optional + Correlation []Correlation `json:"correlation,omitempty" validate:"omitempty,dive"` +} + +type eventUnmarshal Event + +// UnmarshalJSON unmarshal Event object from json bytes +func (e *Event) UnmarshalJSON(data []byte) error { + e.ApplyDefault() + return unmarshalObject("event", data, (*eventUnmarshal)(e)) +} + +// ApplyDefault set the default values for Event +func (e *Event) ApplyDefault() { + e.DataOnly = true + e.Kind = EventKindConsumed +} + +// Correlation define event correlation rules for an event. Only used for `consumed` events +type Correlation struct { + // CloudEvent Extension Context Attribute name + // +kubebuilder:validation:Required + ContextAttributeName string `json:"contextAttributeName" validate:"required"` + // CloudEvent Extension Context Attribute value + // +optional + ContextAttributeValue string `json:"contextAttributeValue,omitempty"` +} + +// EventRef defining invocation of a function via event +type EventRef struct { + // Reference to the unique name of a 'produced' event definition, + // +kubebuilder:validation:Required + TriggerEventRef string `json:"triggerEventRef" validate:"required"` + // Reference to the unique name of a 'consumed' event definition + // +kubebuilder:validation:Required + ResultEventRef string `json:"resultEventRef" validate:"required"` + // Maximum amount of time (ISO 8601 format) to wait for the result event. If not defined it be set to the + // actionExecutionTimeout + // +optional + ResultEventTimeout string `json:"resultEventTimeout,omitempty" validate:"omitempty,iso8601duration"` + // If string type, an expression which selects parts of the states data output to become the data (payload) + // of the event referenced by triggerEventRef. If object type, a custom object to become the data (payload) + // of the event referenced by triggerEventRef. + // +optional + Data *Object `json:"data,omitempty"` + // Add additional extension context attributes to the produced event. + // +optional + ContextAttributes map[string]Object `json:"contextAttributes,omitempty"` + // Specifies if the function should be invoked sync or async. Default is sync. + // +kubebuilder:validation:Enum=async;sync + // +kubebuilder:default=sync + Invoke InvokeKind `json:"invoke,omitempty" validate:"required,oneofkind"` +} + +type eventRefUnmarshal EventRef + +// UnmarshalJSON implements json.Unmarshaler +func (e *EventRef) UnmarshalJSON(data []byte) error { + e.ApplyDefault() + return unmarshalObject("eventRef", data, (*eventRefUnmarshal)(e)) +} + +// ApplyDefault set the default values for Event Ref +func (e *EventRef) ApplyDefault() { + e.Invoke = InvokeKindSync +} diff --git a/vendor/github.com/serverlessworkflow/sdk-go/v2/model/event_data_filter.go b/vendor/github.com/serverlessworkflow/sdk-go/v2/model/event_data_filter.go new file mode 100644 index 0000000000..a69c7d35ca --- /dev/null +++ b/vendor/github.com/serverlessworkflow/sdk-go/v2/model/event_data_filter.go @@ -0,0 +1,43 @@ +// Copyright 2022 The Serverless Workflow Specification Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package model + +// EventDataFilter used to filter consumed event payloads. +type EventDataFilter struct { + // If set to false, event payload is not added/merged to state data. In this case 'data' and 'toStateData' + // should be ignored. Default is true. + // +optional + UseData bool `json:"useData,omitempty"` + // Workflow expression that filters of the event data (payload). + // +optional + Data string `json:"data,omitempty"` + // Workflow expression that selects a state data element to which the action results should be added/merged into. + // If not specified denotes the top-level state data element + // +optional + ToStateData string `json:"toStateData,omitempty"` +} + +type eventDataFilterUnmarshal EventDataFilter + +// UnmarshalJSON implements json.Unmarshaler +func (f *EventDataFilter) UnmarshalJSON(data []byte) error { + f.ApplyDefault() + return unmarshalObject("eventDataFilter", data, (*eventDataFilterUnmarshal)(f)) +} + +// ApplyDefault set the default values for Event Data Filter +func (f *EventDataFilter) ApplyDefault() { + f.UseData = true +} diff --git a/vendor/github.com/serverlessworkflow/sdk-go/v2/model/event_state.go b/vendor/github.com/serverlessworkflow/sdk-go/v2/model/event_state.go new file mode 100644 index 0000000000..1d6235a49c --- /dev/null +++ b/vendor/github.com/serverlessworkflow/sdk-go/v2/model/event_state.go @@ -0,0 +1,105 @@ +// Copyright 2022 The Serverless Workflow Specification Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package model + +import ( + "encoding/json" +) + +// EventState await one or more events and perform actions when they are received. If defined as the +// workflow starting state, the event state definition controls when the workflow instances should be created. +type EventState struct { + // TODO: EventState doesn't have usedForCompensation field. + + // If true consuming one of the defined events causes its associated actions to be performed. If false all + // the defined events must be consumed in order for actions to be performed. Defaults to true. + // +kubebuilder:default=true + // +optional + Exclusive bool `json:"exclusive,omitempty"` + // Define the events to be consumed and optional actions to be performed. + // +kubebuilder:validation:MinItems=1 + OnEvents []OnEvents `json:"onEvents" validate:"required,min=1,dive"` + // State specific timeouts. + // +optional + Timeouts *EventStateTimeout `json:"timeouts,omitempty"` +} + +func (e *EventState) MarshalJSON() ([]byte, error) { + type Alias EventState + custom, err := json.Marshal(&struct { + *Alias + Timeouts *EventStateTimeout `json:"timeouts,omitempty"` + }{ + Alias: (*Alias)(e), + Timeouts: e.Timeouts, + }) + return custom, err +} + +type eventStateUnmarshal EventState + +// UnmarshalJSON unmarshal EventState object from json bytes +func (e *EventState) UnmarshalJSON(data []byte) error { + e.ApplyDefault() + return unmarshalObject("eventState", data, (*eventStateUnmarshal)(e)) +} + +// ApplyDefault set the default values for Event State +func (e *EventState) ApplyDefault() { + e.Exclusive = true +} + +// OnEvents define which actions are be performed for the one or more events. +type OnEvents struct { + // References one or more unique event names in the defined workflow events. + // +kubebuilder:validation:MinItems=1 + EventRefs []string `json:"eventRefs" validate:"required,min=1"` + // Should actions be performed sequentially or in parallel. Default is sequential. + // +kubebuilder:validation:Enum=sequential;parallel + // +kubebuilder:default=sequential + ActionMode ActionMode `json:"actionMode,omitempty" validate:"required,oneof=sequential parallel"` + // Actions to be performed if expression matches + // +optional + Actions []Action `json:"actions,omitempty" validate:"omitempty,dive"` + // eventDataFilter defines the callback event data filter definition + // +optional + EventDataFilter EventDataFilter `json:"eventDataFilter,omitempty"` +} + +type onEventsUnmarshal OnEvents + +// UnmarshalJSON unmarshal OnEvents object from json bytes +func (o *OnEvents) UnmarshalJSON(data []byte) error { + o.ApplyDefault() + return unmarshalObject("onEvents", data, (*onEventsUnmarshal)(o)) +} + +// ApplyDefault set the default values for On Events +func (o *OnEvents) ApplyDefault() { + o.ActionMode = ActionModeSequential +} + +// EventStateTimeout defines timeout settings for event state +type EventStateTimeout struct { + // Default workflow state execution timeout (ISO 8601 duration format) + // +optional + StateExecTimeout *StateExecTimeout `json:"stateExecTimeout,omitempty"` + // Default single actions definition execution timeout (ISO 8601 duration format) + // +optional + ActionExecTimeout string `json:"actionExecTimeout,omitempty" validate:"omitempty,iso8601duration"` + // Default timeout for consuming defined events (ISO 8601 duration format) + // +optional + EventTimeout string `json:"eventTimeout,omitempty" validate:"omitempty,iso8601duration"` +} diff --git a/vendor/github.com/serverlessworkflow/sdk-go/v2/model/event_validator.go b/vendor/github.com/serverlessworkflow/sdk-go/v2/model/event_validator.go new file mode 100644 index 0000000000..8d134afd6a --- /dev/null +++ b/vendor/github.com/serverlessworkflow/sdk-go/v2/model/event_validator.go @@ -0,0 +1,34 @@ +// Copyright 2021 The Serverless Workflow Specification Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package model + +import ( + "reflect" + + validator "github.com/go-playground/validator/v10" + val "github.com/serverlessworkflow/sdk-go/v2/validator" +) + +func init() { + val.GetValidator().RegisterStructValidation(eventStructLevelValidation, Event{}) +} + +// eventStructLevelValidation custom validator for event kind consumed +func eventStructLevelValidation(structLevel validator.StructLevel) { + event := structLevel.Current().Interface().(Event) + if event.Kind == EventKindConsumed && len(event.Type) == 0 { + structLevel.ReportError(reflect.ValueOf(event.Type), "Type", "type", "reqtypeconsumed", "") + } +} diff --git a/vendor/github.com/serverlessworkflow/sdk-go/v2/model/foreach_state.go b/vendor/github.com/serverlessworkflow/sdk-go/v2/model/foreach_state.go new file mode 100644 index 0000000000..ad25b89c55 --- /dev/null +++ b/vendor/github.com/serverlessworkflow/sdk-go/v2/model/foreach_state.go @@ -0,0 +1,105 @@ +// Copyright 2022 The Serverless Workflow Specification Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package model + +import ( + "encoding/json" + + "k8s.io/apimachinery/pkg/util/intstr" +) + +// ForEachModeType Specifies how iterations are to be performed (sequentially or in parallel) +type ForEachModeType string + +func (f ForEachModeType) KindValues() []string { + return []string{ + string(ForEachModeTypeSequential), + string(ForEachModeTypeParallel), + } +} + +func (f ForEachModeType) String() string { + return string(f) +} + +const ( + // ForEachModeTypeSequential specifies iterations should be done sequentially. + ForEachModeTypeSequential ForEachModeType = "sequential" + // ForEachModeTypeParallel specifies iterations should be done parallel. + ForEachModeTypeParallel ForEachModeType = "parallel" +) + +// ForEachState used to execute actions for each element of a data set. +type ForEachState struct { + // Workflow expression selecting an array element of the states' data. + // +kubebuilder:validation:Required + InputCollection string `json:"inputCollection" validate:"required"` + // Workflow expression specifying an array element of the states data to add the results of each iteration. + // +optional + OutputCollection string `json:"outputCollection,omitempty"` + // Name of the iteration parameter that can be referenced in actions/workflow. For each parallel iteration, + // this param should contain a unique element of the inputCollection array. + // +optional + IterationParam string `json:"iterationParam,omitempty"` + // Specifies how many iterations may run in parallel at the same time. Used if mode property is set to + // parallel (default). If not specified, its value should be the size of the inputCollection. + // +optional + BatchSize *intstr.IntOrString `json:"batchSize,omitempty"` + // Actions to be executed for each of the elements of inputCollection. + // +kubebuilder:validation:MinItems=1 + Actions []Action `json:"actions,omitempty" validate:"required,min=1,dive"` + // State specific timeout. + // +optional + Timeouts *ForEachStateTimeout `json:"timeouts,omitempty"` + // Specifies how iterations are to be performed (sequential or in parallel), defaults to parallel. + // +kubebuilder:validation:Enum=sequential;parallel + // +kubebuilder:default=parallel + Mode ForEachModeType `json:"mode,omitempty" validate:"required,oneofkind"` +} + +func (f *ForEachState) MarshalJSON() ([]byte, error) { + type Alias ForEachState + custom, err := json.Marshal(&struct { + *Alias + Timeouts *ForEachStateTimeout `json:"timeouts,omitempty"` + }{ + Alias: (*Alias)(f), + Timeouts: f.Timeouts, + }) + return custom, err +} + +type forEachStateUnmarshal ForEachState + +// UnmarshalJSON implements json.Unmarshaler +func (f *ForEachState) UnmarshalJSON(data []byte) error { + f.ApplyDefault() + return unmarshalObject("forEachState", data, (*forEachStateUnmarshal)(f)) +} + +// ApplyDefault set the default values for ForEach State +func (f *ForEachState) ApplyDefault() { + f.Mode = ForEachModeTypeParallel +} + +// ForEachStateTimeout defines timeout settings for foreach state +type ForEachStateTimeout struct { + // Default workflow state execution timeout (ISO 8601 duration format) + // +optional + StateExecTimeout *StateExecTimeout `json:"stateExecTimeout,omitempty"` + // Default single actions definition execution timeout (ISO 8601 duration format) + // +optional + ActionExecTimeout string `json:"actionExecTimeout,omitempty" validate:"omitempty,iso8601duration"` +} diff --git a/vendor/github.com/serverlessworkflow/sdk-go/v2/model/foreach_state_validator.go b/vendor/github.com/serverlessworkflow/sdk-go/v2/model/foreach_state_validator.go new file mode 100644 index 0000000000..6543dede2d --- /dev/null +++ b/vendor/github.com/serverlessworkflow/sdk-go/v2/model/foreach_state_validator.go @@ -0,0 +1,59 @@ +// Copyright 2022 The Serverless Workflow Specification Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package model + +import ( + "context" + "reflect" + "strconv" + + validator "github.com/go-playground/validator/v10" + val "github.com/serverlessworkflow/sdk-go/v2/validator" + "k8s.io/apimachinery/pkg/util/intstr" +) + +func init() { + val.GetValidator().RegisterStructValidationCtx(forEachStateStructLevelValidation, ForEachState{}) +} + +// ForEachStateStructLevelValidation custom validator for ForEachState +func forEachStateStructLevelValidation(_ context.Context, structLevel validator.StructLevel) { + stateObj := structLevel.Current().Interface().(ForEachState) + + if stateObj.Mode != ForEachModeTypeParallel { + return + } + + if stateObj.BatchSize == nil { + return + } + + switch stateObj.BatchSize.Type { + case intstr.Int: + if stateObj.BatchSize.IntVal <= 0 { + structLevel.ReportError(reflect.ValueOf(stateObj.BatchSize), "BatchSize", "batchSize", "gt0", "") + } + case intstr.String: + v, err := strconv.Atoi(stateObj.BatchSize.StrVal) + if err != nil { + structLevel.ReportError(reflect.ValueOf(stateObj.BatchSize), "BatchSize", "batchSize", "gt0", err.Error()) + return + } + + if v <= 0 { + structLevel.ReportError(reflect.ValueOf(stateObj.BatchSize), "BatchSize", "batchSize", "gt0", "") + } + } +} diff --git a/vendor/github.com/serverlessworkflow/sdk-go/v2/model/function.go b/vendor/github.com/serverlessworkflow/sdk-go/v2/model/function.go new file mode 100644 index 0000000000..49e23abcea --- /dev/null +++ b/vendor/github.com/serverlessworkflow/sdk-go/v2/model/function.go @@ -0,0 +1,63 @@ +// Copyright 2021 The Serverless Workflow Specification Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package model + +const ( + // FunctionTypeREST a combination of the function/service OpenAPI definition document URI and the particular service + // operation that needs to be invoked, separated by a '#'. + FunctionTypeREST FunctionType = "rest" + // FunctionTypeRPC a combination of the gRPC proto document URI and the particular service name and service method + // name that needs to be invoked, separated by a '#'. + FunctionTypeRPC FunctionType = "rpc" + // FunctionTypeExpression defines the expression syntax. + FunctionTypeExpression FunctionType = "expression" + // FunctionTypeGraphQL a combination of the GraphQL schema definition URI and the particular service name and + // service method name that needs to be invoked, separated by a '#' + FunctionTypeGraphQL FunctionType = "graphql" + // FunctionTypeAsyncAPI a combination of the AsyncApi definition document URI and the particular service operation + // that needs to be invoked, separated by a '#' + FunctionTypeAsyncAPI FunctionType = "asyncapi" + // FunctionTypeOData a combination of the GraphQL schema definition URI and the particular service name and service + // method name that needs to be invoked, separated by a '#' + FunctionTypeOData FunctionType = "odata" + // FunctionTypeCustom property defines a list of function types that are set by the specification. Some runtime + // implementations might support additional function types that extend the ones defined in the specification + FunctionTypeCustom FunctionType = "custom" +) + +// FunctionType ... +type FunctionType string + +// Function ... +type Function struct { + Common `json:",inline"` + // Unique function name + // +kubebuilder:validation:Required + Name string `json:"name" validate:"required"` + // If type is `rest`, #. + // If type is `rpc`, ##. + // If type is `expression`, defines the workflow expression. If the type is `custom`, + // #. + // +kubebuilder:validation:Required + Operation string `json:"operation" validate:"required,oneof=rest rpc expression"` + // Defines the function type. Is either `custom`, `rest`, `rpc`, `expression`, `graphql`, `odata` or `asyncapi`. + // Default is `rest`. + // +kubebuilder:validation:Enum=rest;rpc;expression;graphql;odata;asyncapi;custom + // +kubebuilder:default=rest + Type FunctionType `json:"type,omitempty"` + // References an auth definition name to be used to access to resource defined in the operation parameter. + // +optional + AuthRef string `json:"authRef,omitempty" validate:"omitempty,min=1"` +} diff --git a/vendor/github.com/serverlessworkflow/sdk-go/v2/model/inject_state.go b/vendor/github.com/serverlessworkflow/sdk-go/v2/model/inject_state.go new file mode 100644 index 0000000000..a195423763 --- /dev/null +++ b/vendor/github.com/serverlessworkflow/sdk-go/v2/model/inject_state.go @@ -0,0 +1,48 @@ +// Copyright 2022 The Serverless Workflow Specification Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package model + +import ( + "encoding/json" +) + +// InjectState used to inject static data into state data input. +type InjectState struct { + // JSON object which can be set as state's data input and can be manipulated via filter + // +kubebuilder:validation:MinProperties=1 + Data map[string]Object `json:"data" validate:"required,min=1"` + // State specific timeouts + // +optional + Timeouts *InjectStateTimeout `json:"timeouts,omitempty"` +} + +func (i *InjectState) MarshalJSON() ([]byte, error) { + type Alias InjectState + custom, err := json.Marshal(&struct { + *Alias + Timeouts *InjectStateTimeout `json:"timeouts,omitempty"` + }{ + Alias: (*Alias)(i), + Timeouts: i.Timeouts, + }) + return custom, err +} + +// InjectStateTimeout defines timeout settings for inject state +type InjectStateTimeout struct { + // Default workflow state execution timeout (ISO 8601 duration format) + // +optional + StateExecTimeout *StateExecTimeout `json:"stateExecTimeout,omitempty"` +} diff --git a/vendor/github.com/serverlessworkflow/sdk-go/v2/model/object.go b/vendor/github.com/serverlessworkflow/sdk-go/v2/model/object.go new file mode 100644 index 0000000000..a0e9fa034a --- /dev/null +++ b/vendor/github.com/serverlessworkflow/sdk-go/v2/model/object.go @@ -0,0 +1,97 @@ +// Copyright 2022 The Serverless Workflow Specification Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package model + +import ( + "encoding/json" + "fmt" + "math" +) + +// Object is used to allow integration with DeepCopy tool by replacing 'interface' generic type. +// The DeepCopy tool allow us to easily import the Workflow types into a Kubernetes operator, +// which requires the DeepCopy method. +// +// It can marshal and unmarshal any type. +// This object type can be three types: +// - String - holds string values +// - Integer - holds int32 values, JSON marshal any number to float64 by default, during the marshaling process it is +// parsed to int32 +// - raw - holds any not typed value, replaces the interface{} behavior. +// +// +kubebuilder:validation:Type=object +type Object struct { + Type Type `json:"type,inline"` + IntVal int32 `json:"intVal,inline"` + StrVal string `json:"strVal,inline"` + RawValue json.RawMessage `json:"rawValue,inline"` +} + +type Type int64 + +const ( + Integer Type = iota + String + Raw +) + +func FromInt(val int) Object { + if val > math.MaxInt32 || val < math.MinInt32 { + fmt.Println(fmt.Errorf("value: %d overflows int32", val)) + } + return Object{Type: Integer, IntVal: int32(val)} +} + +func FromString(val string) Object { + return Object{Type: String, StrVal: val} +} + +func FromRaw(val interface{}) Object { + custom, err := json.Marshal(val) + if err != nil { + er := fmt.Errorf("failed to parse value to Raw: %w", err) + fmt.Println(er.Error()) + return Object{} + } + return Object{Type: Raw, RawValue: custom} +} + +// UnmarshalJSON implements json.Unmarshaler +func (obj *Object) UnmarshalJSON(data []byte) error { + if data[0] == '"' { + obj.Type = String + return json.Unmarshal(data, &obj.StrVal) + } else if data[0] == '{' { + obj.Type = Raw + return json.Unmarshal(data, &obj.RawValue) + } + obj.Type = Integer + return json.Unmarshal(data, &obj.IntVal) +} + +// MarshalJSON marshal the given json object into the respective Object subtype. +func (obj Object) MarshalJSON() ([]byte, error) { + switch obj.Type { + case String: + return []byte(fmt.Sprintf(`%q`, obj.StrVal)), nil + case Integer: + return []byte(fmt.Sprintf(`%d`, obj.IntVal)), nil + case Raw: + val, _ := json.Marshal(obj.RawValue) + return val, nil + default: + return []byte(fmt.Sprintf("%+v", obj)), nil + } +} diff --git a/vendor/github.com/serverlessworkflow/sdk-go/v2/model/operation_state.go b/vendor/github.com/serverlessworkflow/sdk-go/v2/model/operation_state.go new file mode 100644 index 0000000000..ebe97e0352 --- /dev/null +++ b/vendor/github.com/serverlessworkflow/sdk-go/v2/model/operation_state.go @@ -0,0 +1,68 @@ +// Copyright 2022 The Serverless Workflow Specification Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package model + +import ( + "encoding/json" +) + +// OperationState defines a set of actions to be performed in sequence or in parallel. +type OperationState struct { + // Specifies whether actions are performed in sequence or in parallel, defaults to sequential. + // +kubebuilder:validation:Enum=sequential;parallel + // +kubebuilder:default=sequential + ActionMode ActionMode `json:"actionMode,omitempty" validate:"required,oneof=sequential parallel"` + // Actions to be performed + // +kubebuilder:validation:MinItems=1 + Actions []Action `json:"actions" validate:"required,min=1,dive"` + // State specific timeouts + // +optional + Timeouts *OperationStateTimeout `json:"timeouts,omitempty"` +} + +func (a *OperationState) MarshalJSON() ([]byte, error) { + type Alias OperationState + custom, err := json.Marshal(&struct { + *Alias + Timeouts *OperationStateTimeout `json:"timeouts,omitempty"` + }{ + Alias: (*Alias)(a), + Timeouts: a.Timeouts, + }) + return custom, err +} + +type operationStateUnmarshal OperationState + +// UnmarshalJSON unmarshal OperationState object from json bytes +func (o *OperationState) UnmarshalJSON(data []byte) error { + o.ApplyDefault() + return unmarshalObject("operationState", data, (*operationStateUnmarshal)(o)) +} + +// ApplyDefault set the default values for Operation State +func (o *OperationState) ApplyDefault() { + o.ActionMode = ActionModeSequential +} + +// OperationStateTimeout defines the specific timeout settings for operation state +type OperationStateTimeout struct { + // Defines workflow state execution timeout. + // +optional + StateExecTimeout *StateExecTimeout `json:"stateExecTimeout,omitempty"` + // Default single actions definition execution timeout (ISO 8601 duration format) + // +optional + ActionExecTimeout string `json:"actionExecTimeout,omitempty" validate:"omitempty,iso8601duration"` +} diff --git a/vendor/github.com/serverlessworkflow/sdk-go/v2/model/parallel_state.go b/vendor/github.com/serverlessworkflow/sdk-go/v2/model/parallel_state.go new file mode 100644 index 0000000000..f46fa0ac16 --- /dev/null +++ b/vendor/github.com/serverlessworkflow/sdk-go/v2/model/parallel_state.go @@ -0,0 +1,109 @@ +// Copyright 2022 The Serverless Workflow Specification Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package model + +import ( + "encoding/json" + + "k8s.io/apimachinery/pkg/util/intstr" +) + +// CompletionType define on how to complete branch execution. +type CompletionType string + +const ( + // CompletionTypeAllOf defines all branches must complete execution before the state can transition/end. + CompletionTypeAllOf CompletionType = "allOf" + // CompletionTypeAtLeast defines state can transition/end once at least the specified number of branches + // have completed execution. + CompletionTypeAtLeast CompletionType = "atLeast" +) + +// ParallelState Consists of a number of states that are executed in parallel +type ParallelState struct { + // List of branches for this parallel state. + // +kubebuilder:validation:MinItems=1 + Branches []Branch `json:"branches" validate:"required,min=1,dive"` + // Option types on how to complete branch execution. Defaults to `allOf`. + // +kubebuilder:validation:Enum=allOf;atLeast + // +kubebuilder:default=allOf + CompletionType CompletionType `json:"completionType,omitempty" validate:"required,oneof=allOf atLeast"` + // Used when branchCompletionType is set to atLeast to specify the least number of branches that must complete + // in order for the state to transition/end. + // +optional + // TODO: change this field to unmarshal result as int + NumCompleted intstr.IntOrString `json:"numCompleted,omitempty"` + // State specific timeouts + // +optional + Timeouts *ParallelStateTimeout `json:"timeouts,omitempty"` +} + +func (p *ParallelState) MarshalJSON() ([]byte, error) { + type Alias ParallelState + custom, err := json.Marshal(&struct { + *Alias + Timeouts *ParallelStateTimeout `json:"timeouts,omitempty"` + }{ + Alias: (*Alias)(p), + Timeouts: p.Timeouts, + }) + return custom, err +} + +type parallelStateUnmarshal ParallelState + +// UnmarshalJSON unmarshal ParallelState object from json bytes +func (ps *ParallelState) UnmarshalJSON(data []byte) error { + ps.ApplyDefault() + return unmarshalObject("parallelState", data, (*parallelStateUnmarshal)(ps)) +} + +// ApplyDefault set the default values for Parallel State +func (ps *ParallelState) ApplyDefault() { + ps.CompletionType = CompletionTypeAllOf +} + +// Branch Definition +type Branch struct { + // Branch name + // +kubebuilder:validation:Required + Name string `json:"name" validate:"required"` + // Actions to be executed in this branch + // +kubebuilder:validation:MinItems=1 + Actions []Action `json:"actions" validate:"required,min=1,dive"` + // Branch specific timeout settings + // +optional + Timeouts *BranchTimeouts `json:"timeouts,omitempty"` +} + +// BranchTimeouts defines the specific timeout settings for branch +type BranchTimeouts struct { + // Single actions definition execution timeout duration (ISO 8601 duration format) + // +optional + ActionExecTimeout string `json:"actionExecTimeout,omitempty" validate:"omitempty,iso8601duration"` + // Single branch execution timeout duration (ISO 8601 duration format) + // +optional + BranchExecTimeout string `json:"branchExecTimeout,omitempty" validate:"omitempty,iso8601duration"` +} + +// ParallelStateTimeout defines the specific timeout settings for parallel state +type ParallelStateTimeout struct { + // Default workflow state execution timeout (ISO 8601 duration format) + // +optional + StateExecTimeout *StateExecTimeout `json:"stateExecTimeout,omitempty"` + // Default single branch execution timeout (ISO 8601 duration format) + // +optional + BranchExecTimeout string `json:"branchExecTimeout,omitempty" validate:"omitempty,iso8601duration"` +} diff --git a/vendor/github.com/serverlessworkflow/sdk-go/v2/model/parallel_state_validator.go b/vendor/github.com/serverlessworkflow/sdk-go/v2/model/parallel_state_validator.go new file mode 100644 index 0000000000..52869888de --- /dev/null +++ b/vendor/github.com/serverlessworkflow/sdk-go/v2/model/parallel_state_validator.go @@ -0,0 +1,55 @@ +// Copyright 2022 The Serverless Workflow Specification Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package model + +import ( + "context" + "reflect" + "strconv" + + validator "github.com/go-playground/validator/v10" + val "github.com/serverlessworkflow/sdk-go/v2/validator" + "k8s.io/apimachinery/pkg/util/intstr" +) + +func init() { + val.GetValidator().RegisterStructValidationCtx(parallelStateStructLevelValidation, ParallelState{}) +} + +// ParallelStateStructLevelValidation custom validator for ParallelState +func parallelStateStructLevelValidation(_ context.Context, structLevel validator.StructLevel) { + parallelStateObj := structLevel.Current().Interface().(ParallelState) + + if parallelStateObj.CompletionType == CompletionTypeAllOf { + return + } + + switch parallelStateObj.NumCompleted.Type { + case intstr.Int: + if parallelStateObj.NumCompleted.IntVal <= 0 { + structLevel.ReportError(reflect.ValueOf(parallelStateObj.NumCompleted), "NumCompleted", "numCompleted", "gt0", "") + } + case intstr.String: + v, err := strconv.Atoi(parallelStateObj.NumCompleted.StrVal) + if err != nil { + structLevel.ReportError(reflect.ValueOf(parallelStateObj.NumCompleted), "NumCompleted", "numCompleted", "gt0", err.Error()) + return + } + + if v <= 0 { + structLevel.ReportError(reflect.ValueOf(parallelStateObj.NumCompleted), "NumCompleted", "numCompleted", "gt0", "") + } + } +} diff --git a/vendor/github.com/serverlessworkflow/sdk-go/v2/model/retry.go b/vendor/github.com/serverlessworkflow/sdk-go/v2/model/retry.go new file mode 100644 index 0000000000..6ce82771d0 --- /dev/null +++ b/vendor/github.com/serverlessworkflow/sdk-go/v2/model/retry.go @@ -0,0 +1,43 @@ +// Copyright 2021 The Serverless Workflow Specification Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package model + +import ( + "k8s.io/apimachinery/pkg/util/intstr" + + "github.com/serverlessworkflow/sdk-go/v2/util/floatstr" +) + +// Retry ... +type Retry struct { + // Unique retry strategy name + // +kubebuilder:validation:Required + Name string `json:"name" validate:"required"` + // Time delay between retry attempts (ISO 8601 duration format) + Delay string `json:"delay,omitempty" validate:"omitempty,iso8601duration"` + // Maximum time delay between retry attempts (ISO 8601 duration format) + MaxDelay string `json:"maxDelay,omitempty" validate:"omitempty,iso8601duration"` + // Static value by which the delay increases during each attempt (ISO 8601 time format) + Increment string `json:"increment,omitempty" validate:"omitempty,iso8601duration"` + // Numeric value, if specified the delay between retries is multiplied by this value. + // +optional + Multiplier *floatstr.Float32OrString `json:"multiplier,omitempty" validate:"omitempty,min=1"` + // Maximum number of retry attempts. + // +kubebuilder:validation:Required + MaxAttempts intstr.IntOrString `json:"maxAttempts" validate:"required"` + // If float type, maximum amount of random time added or subtracted from the delay between each retry relative to total delay (between 0 and 1). If string type, absolute maximum amount of random time added or subtracted from the delay between each retry (ISO 8601 duration format) + // TODO: make iso8601duration compatible this type + Jitter floatstr.Float32OrString `json:"jitter,omitempty" validate:"omitempty,min=0,max=1"` +} diff --git a/vendor/github.com/serverlessworkflow/sdk-go/v2/model/retry_validator.go b/vendor/github.com/serverlessworkflow/sdk-go/v2/model/retry_validator.go new file mode 100644 index 0000000000..14886ceb46 --- /dev/null +++ b/vendor/github.com/serverlessworkflow/sdk-go/v2/model/retry_validator.go @@ -0,0 +1,39 @@ +// Copyright 2021 The Serverless Workflow Specification Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package model + +import ( + "reflect" + + validator "github.com/go-playground/validator/v10" + "github.com/serverlessworkflow/sdk-go/v2/util/floatstr" + val "github.com/serverlessworkflow/sdk-go/v2/validator" +) + +func init() { + val.GetValidator().RegisterStructValidation(retryStructLevelValidation, Retry{}) +} + +// RetryStructLevelValidation custom validator for Retry Struct +func retryStructLevelValidation(structLevel validator.StructLevel) { + retryObj := structLevel.Current().Interface().(Retry) + + if retryObj.Jitter.Type == floatstr.String && retryObj.Jitter.StrVal != "" { + err := val.ValidateISO8601TimeDuration(retryObj.Jitter.StrVal) + if err != nil { + structLevel.ReportError(reflect.ValueOf(retryObj.Jitter.StrVal), "Jitter", "jitter", "iso8601duration", "") + } + } +} diff --git a/vendor/github.com/serverlessworkflow/sdk-go/v2/model/sleep_state.go b/vendor/github.com/serverlessworkflow/sdk-go/v2/model/sleep_state.go new file mode 100644 index 0000000000..5d144c5548 --- /dev/null +++ b/vendor/github.com/serverlessworkflow/sdk-go/v2/model/sleep_state.go @@ -0,0 +1,48 @@ +// Copyright 2022 The Serverless Workflow Specification Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package model + +import ( + "encoding/json" +) + +// SleepState suspends workflow execution for a given time duration. +type SleepState struct { + // Duration (ISO 8601 duration format) to sleep + // +kubebuilder:validation:Required + Duration string `json:"duration" validate:"required,iso8601duration"` + // Timeouts State specific timeouts + // +optional + Timeouts *SleepStateTimeout `json:"timeouts,omitempty"` +} + +func (s *SleepState) MarshalJSON() ([]byte, error) { + type Alias SleepState + custom, err := json.Marshal(&struct { + *Alias + Timeouts *SleepStateTimeout `json:"timeouts,omitempty"` + }{ + Alias: (*Alias)(s), + Timeouts: s.Timeouts, + }) + return custom, err +} + +// SleepStateTimeout defines timeout settings for sleep state +type SleepStateTimeout struct { + // Default workflow state execution timeout (ISO 8601 duration format) + // +optional + StateExecTimeout *StateExecTimeout `json:"stateExecTimeout,omitempty"` +} diff --git a/vendor/github.com/serverlessworkflow/sdk-go/v2/model/state_exec_timeout.go b/vendor/github.com/serverlessworkflow/sdk-go/v2/model/state_exec_timeout.go new file mode 100644 index 0000000000..c48762999c --- /dev/null +++ b/vendor/github.com/serverlessworkflow/sdk-go/v2/model/state_exec_timeout.go @@ -0,0 +1,32 @@ +// Copyright 2022 The Serverless Workflow Specification Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package model + +// StateExecTimeout defines workflow state execution timeout +type StateExecTimeout struct { + // Single state execution timeout, not including retries (ISO 8601 duration format) + // +optional + Single string `json:"single,omitempty" validate:"omitempty,iso8601duration"` + // Total state execution timeout, including retries (ISO 8601 duration format) + // +kubebuilder:validation:Required + Total string `json:"total" validate:"required,iso8601duration"` +} + +type stateExecTimeoutUnmarshal StateExecTimeout + +// UnmarshalJSON unmarshal StateExecTimeout object from json bytes +func (s *StateExecTimeout) UnmarshalJSON(data []byte) error { + return unmarshalPrimitiveOrObject("stateExecTimeout", data, &s.Total, (*stateExecTimeoutUnmarshal)(s)) +} diff --git a/vendor/github.com/serverlessworkflow/sdk-go/v2/model/states.go b/vendor/github.com/serverlessworkflow/sdk-go/v2/model/states.go new file mode 100644 index 0000000000..42c7b48cc4 --- /dev/null +++ b/vendor/github.com/serverlessworkflow/sdk-go/v2/model/states.go @@ -0,0 +1,278 @@ +// Copyright 2021 The Serverless Workflow Specification Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package model + +import ( + "encoding/json" + "fmt" + "strings" +) + +// StateType ... +type StateType string + +func (s StateType) KindValues() []string { + return []string{ + string(StateTypeDelay), + string(StateTypeEvent), + string(StateTypeOperation), + string(StateTypeParallel), + string(StateTypeSwitch), + string(StateTypeForEach), + string(StateTypeInject), + string(StateTypeCallback), + string(StateTypeSleep), + } +} + +func (s StateType) String() string { + return string(s) +} + +const ( + // StateTypeDelay ... + StateTypeDelay StateType = "delay" + // StateTypeEvent ... + StateTypeEvent StateType = "event" + // StateTypeOperation ... + StateTypeOperation StateType = "operation" + // StateTypeParallel ... + StateTypeParallel StateType = "parallel" + // StateTypeSwitch ... + StateTypeSwitch StateType = "switch" + // StateTypeForEach ... + StateTypeForEach StateType = "foreach" + // StateTypeInject ... + StateTypeInject StateType = "inject" + // StateTypeCallback ... + StateTypeCallback StateType = "callback" + // StateTypeSleep ... + StateTypeSleep StateType = "sleep" +) + +// BaseState ... +type BaseState struct { + // Unique State id. + // +optional + ID string `json:"id,omitempty"` + // State name. + // +kubebuilder:validation:Required + Name string `json:"name" validate:"required"` + // stateType can be any of delay, callback, event, foreach, inject, operation, parallel, sleep, switch + // +kubebuilder:validation:Enum:=delay;callback;event;foreach;inject;operation;parallel;sleep;switch + // +kubebuilder:validation:Required + Type StateType `json:"type" validate:"required,oneofkind"` + // States error handling and retries definitions. + // +optional + OnErrors []OnError `json:"onErrors,omitempty" validate:"omitempty,dive"` + // Next transition of the workflow after the time delay. + // +kubebuilder:validation:Schemaless + // +kubebuilder:pruning:PreserveUnknownFields + // +optional + Transition *Transition `json:"transition,omitempty"` + // State data filter. + // +optional + StateDataFilter *StateDataFilter `json:"stateDataFilter,omitempty"` + // Unique Name of a workflow state which is responsible for compensation of this state. + // +optional + CompensatedBy string `json:"compensatedBy,omitempty"` + // If true, this state is used to compensate another state. Default is false. + // +optional + UsedForCompensation bool `json:"usedForCompensation,omitempty"` + // State end definition. + // +kubebuilder:validation:Schemaless + // +kubebuilder:pruning:PreserveUnknownFields + // +optional + End *End `json:"end,omitempty"` + // Metadata information. + // +optional + Metadata *Metadata `json:"metadata,omitempty"` +} + +func (b *BaseState) MarshalJSON() ([]byte, error) { + type Alias BaseState + if b == nil { + return nil, nil + } + cus, err := json.Marshal(struct { + *Alias + }{ + Alias: (*Alias)(b), + }) + return cus, err +} + +type State struct { + BaseState `json:",inline"` + // delayState Causes the workflow execution to delay for a specified duration. + // +optional + *DelayState `json:"delayState,omitempty"` + // event states await one or more events and perform actions when they are received. If defined as the + // workflow starting state, the event state definition controls when the workflow instances should be created. + // +optional + *EventState `json:"eventState,omitempty"` + // operationState defines a set of actions to be performed in sequence or in parallel. + // +optional + *OperationState `json:"operationState,omitempty"` + // parallelState Consists of a number of states that are executed in parallel. + // +optional + *ParallelState `json:"parallelState,omitempty"` + // switchState is workflow's gateways: direct transitions onf a workflow based on certain conditions. + // +optional + *SwitchState `json:"switchState,omitempty"` + // forEachState used to execute actions for each element of a data set. + // +optional + *ForEachState `json:"forEachState,omitempty"` + // injectState used to inject static data into state data input. + // +optional + *InjectState `json:"injectState,omitempty"` + // callbackState executes a function and waits for callback event that indicates completion of the task. + // +optional + *CallbackState `json:"callbackState,omitempty"` + // sleepState suspends workflow execution for a given time duration. + // +optional + *SleepState `json:"sleepState,omitempty"` +} + +func (s *State) MarshalJSON() ([]byte, error) { + if s == nil { + return nil, nil + } + r := []byte("") + var errs error + + if s.DelayState != nil { + r, errs = s.DelayState.MarshalJSON() + } + + if s.EventState != nil { + r, errs = s.EventState.MarshalJSON() + } + + if s.OperationState != nil { + r, errs = s.OperationState.MarshalJSON() + } + + if s.ParallelState != nil { + r, errs = s.ParallelState.MarshalJSON() + } + + if s.SwitchState != nil { + r, errs = s.SwitchState.MarshalJSON() + } + + if s.ForEachState != nil { + r, errs = s.ForEachState.MarshalJSON() + } + + if s.InjectState != nil { + r, errs = s.InjectState.MarshalJSON() + } + + if s.CallbackState != nil { + r, errs = s.CallbackState.MarshalJSON() + } + + if s.SleepState != nil { + r, errs = s.SleepState.MarshalJSON() + } + + b, err := s.BaseState.MarshalJSON() + if err != nil { + return nil, err + } + + //remove }{ as BaseState and the State Type needs to be merged together + partialResult := append(b, r...) + result := strings.Replace(string(partialResult), "}{", ",", 1) + return []byte(result), errs +} + +type unmarshalState State + +// UnmarshalJSON implements json.Unmarshaler +func (s *State) UnmarshalJSON(data []byte) error { + if err := unmarshalObject("state", data, (*unmarshalState)(s)); err != nil { + return err + } + + switch s.Type { + case StateTypeDelay: + state := &DelayState{} + if err := json.Unmarshal(data, state); err != nil { + return err + } + s.DelayState = state + + case StateTypeEvent: + state := &EventState{} + if err := json.Unmarshal(data, state); err != nil { + return err + } + s.EventState = state + + case StateTypeOperation: + state := &OperationState{} + if err := unmarshalObject("states", data, state); err != nil { + return err + } + s.OperationState = state + + case StateTypeParallel: + state := &ParallelState{} + if err := json.Unmarshal(data, state); err != nil { + return err + } + s.ParallelState = state + + case StateTypeSwitch: + state := &SwitchState{} + if err := json.Unmarshal(data, state); err != nil { + return err + } + s.SwitchState = state + + case StateTypeForEach: + state := &ForEachState{} + if err := json.Unmarshal(data, state); err != nil { + return err + } + s.ForEachState = state + + case StateTypeInject: + state := &InjectState{} + if err := json.Unmarshal(data, state); err != nil { + return err + } + s.InjectState = state + + case StateTypeCallback: + state := &CallbackState{} + if err := json.Unmarshal(data, state); err != nil { + return err + } + s.CallbackState = state + + case StateTypeSleep: + state := &SleepState{} + if err := json.Unmarshal(data, state); err != nil { + return err + } + s.SleepState = state + default: + return fmt.Errorf("states type %q not supported", s.Type.String()) + } + return nil +} diff --git a/vendor/github.com/serverlessworkflow/sdk-go/v2/model/states_validator.go b/vendor/github.com/serverlessworkflow/sdk-go/v2/model/states_validator.go new file mode 100644 index 0000000000..ee5584604a --- /dev/null +++ b/vendor/github.com/serverlessworkflow/sdk-go/v2/model/states_validator.go @@ -0,0 +1,33 @@ +// Copyright 2021 The Serverless Workflow Specification Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package model + +import ( + "reflect" + + validator "github.com/go-playground/validator/v10" + val "github.com/serverlessworkflow/sdk-go/v2/validator" +) + +func init() { + val.GetValidator().RegisterStructValidation(baseStateStructLevelValidation, BaseState{}) +} + +func baseStateStructLevelValidation(structLevel validator.StructLevel) { + baseState := structLevel.Current().Interface().(BaseState) + if baseState.Type != StateTypeSwitch { + validTransitionAndEnd(structLevel, reflect.ValueOf(baseState), baseState.Transition, baseState.End) + } +} diff --git a/vendor/github.com/serverlessworkflow/sdk-go/v2/model/switch_state.go b/vendor/github.com/serverlessworkflow/sdk-go/v2/model/switch_state.go new file mode 100644 index 0000000000..70f1b288f8 --- /dev/null +++ b/vendor/github.com/serverlessworkflow/sdk-go/v2/model/switch_state.go @@ -0,0 +1,146 @@ +// Copyright 2022 The Serverless Workflow Specification Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package model + +import ( + "encoding/json" + "strings" +) + +// SwitchState is workflow's gateways: direct transitions onf a workflow based on certain conditions. +type SwitchState struct { + // TODO: don't use BaseState for this, there are a few fields that SwitchState don't need. + + // Default transition of the workflow if there is no matching data conditions. Can include a transition or + // end definition. + DefaultCondition DefaultCondition `json:"defaultCondition" validate:"required_without=EventConditions"` + // Defines conditions evaluated against events. + // +optional + EventConditions []EventCondition `json:"eventConditions" validate:"required_without=DefaultCondition"` + // Defines conditions evaluated against data + // +optional + DataConditions []DataCondition `json:"dataConditions" validate:"omitempty,min=1,dive"` + // SwitchState specific timeouts + // +optional + Timeouts *SwitchStateTimeout `json:"timeouts,omitempty"` +} + +func (s *SwitchState) MarshalJSON() ([]byte, error) { + type Alias SwitchState + custom, err := json.Marshal(&struct { + *Alias + Timeouts *SwitchStateTimeout `json:"timeouts,omitempty"` + }{ + Alias: (*Alias)(s), + Timeouts: s.Timeouts, + }) + + // Avoid marshal empty objects as null. + st := strings.Replace(string(custom), "\"eventConditions\":null,", "", 1) + st = strings.Replace(st, "\"dataConditions\":null,", "", 1) + st = strings.Replace(st, "\"end\":null,", "", -1) + return []byte(st), err +} + +// DefaultCondition Can be either a transition or end definition +type DefaultCondition struct { + // Serverless workflow states can have one or more incoming and outgoing transitions (from/to other states). + // Each state can define a transition definition that is used to determine which state to transition to next. + // +kubebuilder:validation:Schemaless + // +kubebuilder:pruning:PreserveUnknownFields + // +optional + Transition *Transition `json:"transition,omitempty"` + // If this state an end state + // +kubebuilder:validation:Schemaless + // +kubebuilder:pruning:PreserveUnknownFields + // +optional + End *End `json:"end,omitempty"` +} + +type defaultConditionUnmarshal DefaultCondition + +// UnmarshalJSON implements json.Unmarshaler +func (e *DefaultCondition) UnmarshalJSON(data []byte) error { + var nextState string + err := unmarshalPrimitiveOrObject("defaultCondition", data, &nextState, (*defaultConditionUnmarshal)(e)) + if err != nil { + return err + } + + if nextState != "" { + e.Transition = &Transition{NextState: nextState} + } + + return err +} + +// SwitchStateTimeout defines the specific timeout settings for switch state +type SwitchStateTimeout struct { + // Default workflow state execution timeout (ISO 8601 duration format) + // +optional + StateExecTimeout *StateExecTimeout `json:"stateExecTimeout,omitempty"` + // Specify the expire value to transitions to defaultCondition. When event-based conditions do not arrive. + // NOTE: this is only available for EventConditions + // +optional + EventTimeout string `json:"eventTimeout,omitempty" validate:"omitempty,iso8601duration"` +} + +// EventCondition specify events which the switch state must wait for. +type EventCondition struct { + // Event condition name. + // +optional + Name string `json:"name,omitempty"` + // References a unique event name in the defined workflow events. + // +kubebuilder:validation:Required + EventRef string `json:"eventRef" validate:"required"` + // Event data filter definition. + // +optional + EventDataFilter *EventDataFilter `json:"eventDataFilter,omitempty"` + // Metadata information. + // +kubebuilder:validation:Schemaless + // +kubebuilder:pruning:PreserveUnknownFields + // +optional + Metadata Metadata `json:"metadata,omitempty"` + // TODO End or Transition needs to be exclusive tag, one or another should be set. + // Explicit transition to end + // +kubebuilder:validation:Schemaless + // +kubebuilder:pruning:PreserveUnknownFields + // +optional + End *End `json:"end" validate:"omitempty"` + // Workflow transition if condition is evaluated to true + // +kubebuilder:validation:Schemaless + // +kubebuilder:pruning:PreserveUnknownFields + // +optional + Transition *Transition `json:"transition" validate:"omitempty"` +} + +// DataCondition specify a data-based condition statement which causes a transition to another workflow state +// if evaluated to true. +type DataCondition struct { + // Data condition name. + // +optional + Name string `json:"name,omitempty"` + // Workflow expression evaluated against state data. Must evaluate to true or false. + // +kubebuilder:validation:Required + Condition string `json:"condition" validate:"required"` + // Metadata information. + // +optional + Metadata Metadata `json:"metadata,omitempty"` + // TODO End or Transition needs to be exclusive tag, one or another should be set. + // Explicit transition to end + End *End `json:"end" validate:"omitempty"` + // Workflow transition if condition is evaluated to true + Transition *Transition `json:"transition,omitempty" validate:"omitempty"` +} diff --git a/vendor/github.com/serverlessworkflow/sdk-go/v2/model/switch_state_validator.go b/vendor/github.com/serverlessworkflow/sdk-go/v2/model/switch_state_validator.go new file mode 100644 index 0000000000..83f13791bd --- /dev/null +++ b/vendor/github.com/serverlessworkflow/sdk-go/v2/model/switch_state_validator.go @@ -0,0 +1,59 @@ +// Copyright 2022 The Serverless Workflow Specification Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package model + +import ( + "reflect" + + validator "github.com/go-playground/validator/v10" + val "github.com/serverlessworkflow/sdk-go/v2/validator" +) + +func init() { + val.GetValidator().RegisterStructValidation(switchStateStructLevelValidation, SwitchState{}) + val.GetValidator().RegisterStructValidation(defaultConditionStructLevelValidation, DefaultCondition{}) + val.GetValidator().RegisterStructValidation(eventConditionStructLevelValidation, EventCondition{}) + val.GetValidator().RegisterStructValidation(dataConditionStructLevelValidation, DataCondition{}) +} + +// SwitchStateStructLevelValidation custom validator for SwitchState +func switchStateStructLevelValidation(structLevel validator.StructLevel) { + switchState := structLevel.Current().Interface().(SwitchState) + + switch { + case len(switchState.DataConditions) == 0 && len(switchState.EventConditions) == 0: + structLevel.ReportError(reflect.ValueOf(switchState), "DataConditions", "dataConditions", "required", "must have one of dataConditions, eventConditions") + case len(switchState.DataConditions) > 0 && len(switchState.EventConditions) > 0: + structLevel.ReportError(reflect.ValueOf(switchState), "DataConditions", "dataConditions", "exclusive", "must have one of dataConditions, eventConditions") + } +} + +// DefaultConditionStructLevelValidation custom validator for DefaultCondition +func defaultConditionStructLevelValidation(structLevel validator.StructLevel) { + defaultCondition := structLevel.Current().Interface().(DefaultCondition) + validTransitionAndEnd(structLevel, reflect.ValueOf(defaultCondition), defaultCondition.Transition, defaultCondition.End) +} + +// EventConditionStructLevelValidation custom validator for EventCondition +func eventConditionStructLevelValidation(structLevel validator.StructLevel) { + eventCondition := structLevel.Current().Interface().(EventCondition) + validTransitionAndEnd(structLevel, reflect.ValueOf(eventCondition), eventCondition.Transition, eventCondition.End) +} + +// DataConditionStructLevelValidation custom validator for DataCondition +func dataConditionStructLevelValidation(structLevel validator.StructLevel) { + dataCondition := structLevel.Current().Interface().(DataCondition) + validTransitionAndEnd(structLevel, reflect.ValueOf(dataCondition), dataCondition.Transition, dataCondition.End) +} diff --git a/vendor/github.com/serverlessworkflow/sdk-go/v2/model/util.go b/vendor/github.com/serverlessworkflow/sdk-go/v2/model/util.go new file mode 100644 index 0000000000..2ae4226989 --- /dev/null +++ b/vendor/github.com/serverlessworkflow/sdk-go/v2/model/util.go @@ -0,0 +1,313 @@ +// Copyright 2020 The Serverless Workflow Specification Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package model + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" + "net/http" + "os" + "path/filepath" + "reflect" + "strings" + "sync/atomic" + "time" + + "github.com/serverlessworkflow/sdk-go/v2/validator" + "sigs.k8s.io/yaml" +) + +// Kind ... +// +k8s:deepcopy-gen=false +type Kind interface { + KindValues() []string + String() string +} + +// TODO: Remove global variable +var httpClient = http.Client{Timeout: time.Duration(1) * time.Second} + +// UnmarshalError ... +// +k8s:deepcopy-gen=false +type UnmarshalError struct { + err error + parameterName string + primitiveType reflect.Kind + objectType reflect.Kind +} + +func (e *UnmarshalError) Error() string { + if e.err == nil { + panic("unmarshalError fail") + } + + var syntaxErr *json.SyntaxError + var unmarshalTypeErr *json.UnmarshalTypeError + if errors.As(e.err, &syntaxErr) { + return fmt.Sprintf("%s has a syntax error %q", e.parameterName, syntaxErr.Error()) + + } else if errors.As(e.err, &unmarshalTypeErr) { + return e.unmarshalMessageError(unmarshalTypeErr) + } + + return e.err.Error() +} + +func (e *UnmarshalError) unmarshalMessageError(err *json.UnmarshalTypeError) string { + if err.Struct == "" && err.Field == "" { + primitiveTypeName := e.primitiveType.String() + var objectTypeName string + if e.objectType != reflect.Invalid { + switch e.objectType { + case reflect.Struct: + objectTypeName = "object" + case reflect.Map: + objectTypeName = "object" + case reflect.Slice: + objectTypeName = "array" + default: + objectTypeName = e.objectType.String() + } + } + return fmt.Sprintf("%s must be %s or %s", e.parameterName, primitiveTypeName, objectTypeName) + + } else if err.Struct != "" && err.Field != "" { + var primitiveTypeName string + val := reflect.New(err.Type) + if valKinds, ok := val.Elem().Interface().(validator.Kind); ok { + values := valKinds.KindValues() + if len(values) <= 2 { + primitiveTypeName = strings.Join(values, " or ") + } else { + primitiveTypeName = fmt.Sprintf("%s, %s", strings.Join(values[:len(values)-2], ", "), strings.Join(values[len(values)-2:], " or ")) + } + } else { + primitiveTypeName = err.Type.Name() + } + + return fmt.Sprintf("%s.%s must be %s", e.parameterName, err.Field, primitiveTypeName) + } + + return err.Error() +} + +func loadExternalResource(url string) (b []byte, err error) { + index := strings.Index(url, "://") + if index == -1 { + b, err = getBytesFromFile(url) + } else { + scheme := url[:index] + switch scheme { + case "http", "https": + b, err = getBytesFromHttp(url) + case "file": + b, err = getBytesFromFile(url[index+3:]) + default: + return nil, fmt.Errorf("unsupported scheme: %q", scheme) + } + } + if err != nil { + return + } + + // TODO: optimize this + // NOTE: In specification, we can declare independent definitions with another file format, so + // we must convert independently yaml source to json format data before unmarshal. + if !json.Valid(b) { + b, err = yaml.YAMLToJSON(b) + if err != nil { + return nil, err + } + return b, nil + } + + return b, nil +} + +func getBytesFromFile(path string) ([]byte, error) { + // if path is relative, search in include paths + if !filepath.IsAbs(path) { + paths := IncludePaths() + pathFound := false + for i := 0; i < len(paths) && !pathFound; i++ { + sn := filepath.Join(paths[i], path) + _, err := os.Stat(sn) + if err != nil { + if !errors.Is(err, os.ErrNotExist) { + return nil, err + } + } else { + path = sn + pathFound = true + } + } + if !pathFound { + return nil, fmt.Errorf("file not found: %q", path) + } + } + + return os.ReadFile(filepath.Clean(path)) +} + +func getBytesFromHttp(url string) ([]byte, error) { + req, err := http.NewRequest(http.MethodGet, url, nil) + if err != nil { + return nil, err + } + + resp, err := httpClient.Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + buf := new(bytes.Buffer) + if _, err = buf.ReadFrom(resp.Body); err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +func unmarshalObjectOrFile[U any](parameterName string, data []byte, valObject *U) error { + var valString string + err := unmarshalPrimitiveOrObject(parameterName, data, &valString, valObject) + if err != nil || valString == "" { + return err + } + + // Assumes that the value inside `data` is a path to a known location. + // Returns the content of the file or a not nil error reference. + data, err = loadExternalResource(valString) + if err != nil { + return err + } + + data = bytes.TrimSpace(data) + if data[0] != '{' && data[0] != '[' { + return errors.New("invalid external resource definition") + } + + if data[0] == '[' && parameterName != "auth" && parameterName != "secrets" { + return errors.New("invalid external resource definition") + } + + data = bytes.TrimSpace(data) + if data[0] == '{' && parameterName != "constants" && parameterName != "timeouts" { + extractData := map[string]json.RawMessage{} + err = json.Unmarshal(data, &extractData) + if err != nil { + return &UnmarshalError{ + err: err, + parameterName: parameterName, + primitiveType: reflect.TypeOf(*valObject).Kind(), + } + } + + var ok bool + if data, ok = extractData[parameterName]; !ok { + return fmt.Errorf("external resource parameter not found: %q", parameterName) + } + } + + return unmarshalObject(parameterName, data, valObject) +} + +func unmarshalPrimitiveOrObject[T string | bool, U any](parameterName string, data []byte, valPrimitive *T, valStruct *U) error { + data = bytes.TrimSpace(data) + if len(data) == 0 { + // TODO: Normalize error messages + return fmt.Errorf("%s no bytes to unmarshal", parameterName) + } + + isObject := data[0] == '{' || data[0] == '[' + var err error + if isObject { + err = unmarshalObject(parameterName, data, valStruct) + } else { + err = unmarshalPrimitive(parameterName, data, valPrimitive) + } + + var unmarshalError *UnmarshalError + if errors.As(err, &unmarshalError) { + unmarshalError.objectType = reflect.TypeOf(*valStruct).Kind() + unmarshalError.primitiveType = reflect.TypeOf(*valPrimitive).Kind() + } + + return err +} + +func unmarshalPrimitive[T string | bool](parameterName string, data []byte, value *T) error { + if value == nil { + return nil + } + + err := json.Unmarshal(data, value) + if err != nil { + return &UnmarshalError{ + err: err, + parameterName: parameterName, + primitiveType: reflect.TypeOf(*value).Kind(), + } + } + + return nil +} + +func unmarshalObject[U any](parameterName string, data []byte, value *U) error { + if value == nil { + return nil + } + + err := json.Unmarshal(data, value) + if err != nil { + return &UnmarshalError{ + err: err, + parameterName: parameterName, + objectType: reflect.TypeOf(*value).Kind(), + } + } + + return nil +} + +var defaultIncludePaths atomic.Value + +func init() { + wd, err := os.Getwd() + if err != nil { + panic(err) + } + + SetIncludePaths([]string{wd}) +} + +// IncludePaths will return the search path for non-absolute import file +func IncludePaths() []string { + return defaultIncludePaths.Load().([]string) +} + +// SetIncludePaths will update the search path for non-absolute import file +func SetIncludePaths(paths []string) { + for _, path := range paths { + if !filepath.IsAbs(path) { + panic(fmt.Errorf("%s must be an absolute file path", path)) + } + } + + defaultIncludePaths.Store(paths) +} diff --git a/vendor/github.com/serverlessworkflow/sdk-go/v2/model/workflow.go b/vendor/github.com/serverlessworkflow/sdk-go/v2/model/workflow.go new file mode 100644 index 0000000000..c3b969428c --- /dev/null +++ b/vendor/github.com/serverlessworkflow/sdk-go/v2/model/workflow.go @@ -0,0 +1,517 @@ +// Copyright 2021 The Serverless Workflow Specification Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package model + +import ( + "encoding/json" +) + +// InvokeKind defines how the target is invoked. +type InvokeKind string + +func (i InvokeKind) KindValues() []string { + return []string{string(InvokeKindSync), string(InvokeKindAsync)} +} + +func (i InvokeKind) String() string { + return string(i) +} + +const ( + // InvokeKindSync meaning that worfklow execution should wait until the target completes. + InvokeKindSync InvokeKind = "sync" + // InvokeKindAsync meaning that workflow execution should just invoke the target and should not wait until its + // completion. + InvokeKindAsync InvokeKind = "async" +) + +// ActionMode specifies how actions are to be performed. +type ActionMode string + +const ( + // ActionModeSequential specifies actions should be performed in sequence + ActionModeSequential ActionMode = "sequential" + + // ActionModeParallel specifies actions should be performed in parallel + ActionModeParallel ActionMode = "parallel" +) + +const ( + // UnlimitedTimeout description for unlimited timeouts + UnlimitedTimeout = "unlimited" +) + +type ExpressionLangType string + +const ( + //JqExpressionLang ... + JqExpressionLang ExpressionLangType = "jq" + + // JsonPathExpressionLang ... + JsonPathExpressionLang ExpressionLangType = "jsonpath" +) + +// BaseWorkflow describes the partial Workflow definition that does not rely on generic interfaces +// to make it easy for custom unmarshalers implementations to unmarshal the common data structure. +type BaseWorkflow struct { + // Workflow unique identifier + // +optional + ID string `json:"id,omitempty" validate:"required_without=Key"` + // Key Domain-specific workflow identifier + // +optional + Key string `json:"key,omitempty" validate:"required_without=ID"` + // Workflow name + Name string `json:"name,omitempty"` + // Workflow description. + // +optional + Description string `json:"description,omitempty"` + // Workflow version. + // +optional + Version string `json:"version" validate:"omitempty,min=1"` + // Workflow start definition. + // +kubebuilder:validation:Schemaless + // +kubebuilder:pruning:PreserveUnknownFields + // +optional + Start *Start `json:"start,omitempty"` + // Annotations List of helpful terms describing the workflows intended purpose, subject areas, or other important + // qualities. + // +optional + Annotations []string `json:"annotations,omitempty"` + // DataInputSchema URI of the JSON Schema used to validate the workflow data input + // +optional + DataInputSchema *DataInputSchema `json:"dataInputSchema,omitempty"` + // Serverless Workflow schema version + // +kubebuilder:validation:Required + // +kubebuilder:default="0.8" + SpecVersion string `json:"specVersion" validate:"required"` + // Secrets allow you to access sensitive information, such as passwords, OAuth tokens, ssh keys, etc, + // inside your Workflow Expressions. + // +optional + Secrets Secrets `json:"secrets,omitempty"` + // Constants Workflow constants are used to define static, and immutable, data which is available to + // Workflow Expressions. + // +optional + Constants *Constants `json:"constants,omitempty"` + // Identifies the expression language used for workflow expressions. Default is 'jq'. + // +kubebuilder:validation:Enum=jq;jsonpath + // +kubebuilder:default=jq + // +optional + ExpressionLang ExpressionLangType `json:"expressionLang,omitempty" validate:"omitempty,min=1,oneof=jq jsonpath"` + // Defines the workflow default timeout settings. + // +optional + Timeouts *Timeouts `json:"timeouts,omitempty"` + // Defines checked errors that can be explicitly handled during workflow execution. + // +optional + Errors Errors `json:"errors,omitempty"` + // If "true", workflow instances is not terminated when there are no active execution paths. + // Instance can be terminated with "terminate end definition" or reaching defined "workflowExecTimeout" + // +optional + KeepActive bool `json:"keepActive,omitempty"` + // Metadata custom information shared with the runtime. + // +kubebuilder:validation:Schemaless + // +kubebuilder:pruning:PreserveUnknownFields + // +optional + Metadata Metadata `json:"metadata,omitempty"` + // AutoRetries If set to true, actions should automatically be retried on unchecked errors. Default is false + // +optional + AutoRetries bool `json:"autoRetries,omitempty"` + // Auth definitions can be used to define authentication information that should be applied to resources defined + // in the operation property of function definitions. It is not used as authentication information for the + // function invocation, but just to access the resource containing the function invocation information. + // +kubebuilder:validation:Schemaless + // +kubebuilder:pruning:PreserveUnknownFields + // +optional + Auth Auths `json:"auth,omitempty" validate:"omitempty"` +} + +type Auths []Auth + +type authsUnmarshal Auths + +// UnmarshalJSON implements json.Unmarshaler +func (r *Auths) UnmarshalJSON(data []byte) error { + return unmarshalObjectOrFile("auth", data, (*authsUnmarshal)(r)) +} + +type Errors []Error + +type errorsUnmarshal Errors + +// UnmarshalJSON implements json.Unmarshaler +func (e *Errors) UnmarshalJSON(data []byte) error { + return unmarshalObjectOrFile("errors", data, (*errorsUnmarshal)(e)) +} + +// Workflow base definition +type Workflow struct { + BaseWorkflow `json:",inline"` + // +kubebuilder:validation:MinItems=1 + // +kubebuilder:pruning:PreserveUnknownFields + States []State `json:"states" validate:"required,min=1,dive"` + // +optional + Events Events `json:"events,omitempty"` + // +optional + Functions Functions `json:"functions,omitempty"` + // +optional + Retries Retries `json:"retries,omitempty" validate:"dive"` +} + +type workflowUnmarshal Workflow + +// UnmarshalJSON implementation for json Unmarshal function for the Workflow type +func (w *Workflow) UnmarshalJSON(data []byte) error { + w.ApplyDefault() + err := unmarshalObject("workflow", data, (*workflowUnmarshal)(w)) + if err != nil { + return err + } + + if w.Start == nil && len(w.States) > 0 { + w.Start = &Start{ + StateName: w.States[0].Name, + } + } + + return nil +} + +// ApplyDefault set the default values for Workflow +func (w *Workflow) ApplyDefault() { + w.ExpressionLang = JqExpressionLang +} + +type States []State + +type statesUnmarshal States + +// UnmarshalJSON implements json.Unmarshaler +func (s *States) UnmarshalJSON(data []byte) error { + return unmarshalObject("states", data, (*statesUnmarshal)(s)) +} + +type Events []Event + +type eventsUnmarshal Events + +// UnmarshalJSON implements json.Unmarshaler +func (e *Events) UnmarshalJSON(data []byte) error { + return unmarshalObjectOrFile("events", data, (*eventsUnmarshal)(e)) +} + +type Functions []Function + +type functionsUnmarshal Functions + +// UnmarshalJSON implements json.Unmarshaler +func (f *Functions) UnmarshalJSON(data []byte) error { + return unmarshalObjectOrFile("functions", data, (*functionsUnmarshal)(f)) +} + +type Retries []Retry + +type retriesUnmarshal Retries + +// UnmarshalJSON implements json.Unmarshaler +func (r *Retries) UnmarshalJSON(data []byte) error { + return unmarshalObjectOrFile("retries", data, (*retriesUnmarshal)(r)) +} + +// Timeouts ... +type Timeouts struct { + // WorkflowExecTimeout Workflow execution timeout duration (ISO 8601 duration format). If not specified should + // be 'unlimited'. + // +optional + WorkflowExecTimeout *WorkflowExecTimeout `json:"workflowExecTimeout,omitempty"` + // StateExecTimeout Total state execution timeout (including retries) (ISO 8601 duration format). + // +optional + StateExecTimeout *StateExecTimeout `json:"stateExecTimeout,omitempty"` + // ActionExecTimeout Single actions definition execution timeout duration (ISO 8601 duration format). + // +optional + ActionExecTimeout string `json:"actionExecTimeout,omitempty" validate:"omitempty,min=1"` + // BranchExecTimeout Single branch execution timeout duration (ISO 8601 duration format). + // +optional + BranchExecTimeout string `json:"branchExecTimeout,omitempty" validate:"omitempty,min=1"` + // EventTimeout Timeout duration to wait for consuming defined events (ISO 8601 duration format). + // +optional + EventTimeout string `json:"eventTimeout,omitempty" validate:"omitempty,min=1"` +} + +type timeoutsUnmarshal Timeouts + +// UnmarshalJSON implements json.Unmarshaler +func (t *Timeouts) UnmarshalJSON(data []byte) error { + return unmarshalObjectOrFile("timeouts", data, (*timeoutsUnmarshal)(t)) +} + +// WorkflowExecTimeout property defines the workflow execution timeout. It is defined using the ISO 8601 duration +// format. If not defined, the workflow execution should be given "unlimited" amount of time to complete. +type WorkflowExecTimeout struct { + // Workflow execution timeout duration (ISO 8601 duration format). If not specified should be 'unlimited'. + // +kubebuilder:default=unlimited + Duration string `json:"duration" validate:"required,min=1"` + // If false, workflow instance is allowed to finish current execution. If true, current workflow execution + // is stopped immediately. Default is false. + // +optional + Interrupt bool `json:"interrupt,omitempty"` + // Name of a workflow state to be executed before workflow instance is terminated. + // +optional + RunBefore string `json:"runBefore,omitempty" validate:"omitempty,min=1"` +} + +type workflowExecTimeoutUnmarshal WorkflowExecTimeout + +// UnmarshalJSON implements json.Unmarshaler +func (w *WorkflowExecTimeout) UnmarshalJSON(data []byte) error { + w.ApplyDefault() + return unmarshalPrimitiveOrObject("workflowExecTimeout", data, &w.Duration, (*workflowExecTimeoutUnmarshal)(w)) +} + +// ApplyDefault set the default values for Workflow Exec Timeout +func (w *WorkflowExecTimeout) ApplyDefault() { + w.Duration = UnlimitedTimeout +} + +// Error declaration for workflow definitions +type Error struct { + // Name Domain-specific error name. + // +kubebuilder:validation:Required + Name string `json:"name" validate:"required"` + // Code OnError code. Can be used in addition to the name to help runtimes resolve to technical errors/exceptions. + // Should not be defined if error is set to '*'. + // +optional + Code string `json:"code,omitempty" validate:"omitempty,min=1"` + // OnError description. + // +optional + Description string `json:"description,omitempty"` +} + +// Start definition +type Start struct { + // Name of the starting workflow state + // +kubebuilder:validation:Required + StateName string `json:"stateName" validate:"required"` + // Define the recurring time intervals or cron expressions at which workflow instances should be automatically + // started. + // +optional + Schedule *Schedule `json:"schedule,omitempty" validate:"omitempty"` +} + +type startUnmarshal Start + +// UnmarshalJSON implements json.Unmarshaler +func (s *Start) UnmarshalJSON(data []byte) error { + return unmarshalPrimitiveOrObject("start", data, &s.StateName, (*startUnmarshal)(s)) +} + +// Schedule ... +type Schedule struct { + // TODO Interval is required if Cron is not set and vice-versa, make a exclusive validation + // A recurring time interval expressed in the derivative of ISO 8601 format specified below. Declares that + // workflow instances should be automatically created at the start of each time interval in the series. + // +optional + Interval string `json:"interval,omitempty"` + // Cron expression defining when workflow instances should be automatically created. + // optional + Cron *Cron `json:"cron,omitempty"` + // Timezone name used to evaluate the interval & cron-expression. If the interval specifies a date-time + // w/ timezone then proper timezone conversion will be applied. (default: UTC). + // +optional + Timezone string `json:"timezone,omitempty"` +} + +type scheduleUnmarshal Schedule + +// UnmarshalJSON implements json.Unmarshaler +func (s *Schedule) UnmarshalJSON(data []byte) error { + return unmarshalPrimitiveOrObject("schedule", data, &s.Interval, (*scheduleUnmarshal)(s)) +} + +// Cron ... +type Cron struct { + // Cron expression describing when the workflow instance should be created (automatically). + // +kubebuilder:validation:Required + Expression string `json:"expression" validate:"required"` + // Specific date and time (ISO 8601 format) when the cron expression is no longer valid. + // +optional + ValidUntil string `json:"validUntil,omitempty" validate:"omitempty,iso8601duration"` +} + +type cronUnmarshal Cron + +// UnmarshalJSON custom unmarshal function for Cron +func (c *Cron) UnmarshalJSON(data []byte) error { + return unmarshalPrimitiveOrObject("cron", data, &c.Expression, (*cronUnmarshal)(c)) +} + +// Transition Serverless workflow states can have one or more incoming and outgoing transitions (from/to other states). +// Each state can define a transition definition that is used to determine which state to transition to next. +type Transition struct { + // Name of the state to transition to next. + // +kubebuilder:validation:Required + NextState string `json:"nextState" validate:"required,min=1"` + // Array of producedEvent definitions. Events to be produced before the transition takes place. + // +optional + ProduceEvents []ProduceEvent `json:"produceEvents,omitempty" validate:"omitempty,dive"` + // If set to true, triggers workflow compensation before this transition is taken. Default is false. + // +kubebuilder:default=false + // +optional + Compensate bool `json:"compensate,omitempty"` +} + +type transitionUnmarshal Transition + +// UnmarshalJSON implements json.Unmarshaler +func (t *Transition) UnmarshalJSON(data []byte) error { + return unmarshalPrimitiveOrObject("transition", data, &t.NextState, (*transitionUnmarshal)(t)) +} + +// OnError ... +type OnError struct { + // ErrorRef Reference to a unique workflow error definition. Used of errorRefs is not used + ErrorRef string `json:"errorRef,omitempty"` + // ErrorRefs References one or more workflow error definitions. Used if errorRef is not used + ErrorRefs []string `json:"errorRefs,omitempty"` + // Transition to next state to handle the error. If retryRef is defined, this transition is taken only if + // retries were unsuccessful. + // +kubebuilder:validation:Schemaless + // +kubebuilder:pruning:PreserveUnknownFields + // +optional + Transition *Transition `json:"transition,omitempty"` + // End workflow execution in case of this error. If retryRef is defined, this ends workflow only if + // retries were unsuccessful. + // +kubebuilder:validation:Schemaless + // +kubebuilder:pruning:PreserveUnknownFields + // +optional + End *End `json:"end,omitempty"` +} + +// End definition +type End struct { + // If true, completes all execution flows in the given workflow instance. + // +optional + Terminate bool `json:"terminate,omitempty"` + // Array of producedEvent definitions. Defines events that should be produced. + // +optional + ProduceEvents []ProduceEvent `json:"produceEvents,omitempty"` + // If set to true, triggers workflow compensation before workflow execution completes. Default is false. + // +optional + Compensate bool `json:"compensate,omitempty"` + // Defines that current workflow execution should stop, and execution should continue as a new workflow + // instance of the provided id + // +optional + ContinueAs *ContinueAs `json:"continueAs,omitempty"` +} + +type endUnmarshal End + +// UnmarshalJSON implements json.Unmarshaler +func (e *End) UnmarshalJSON(data []byte) error { + return unmarshalPrimitiveOrObject("end", data, &e.Terminate, (*endUnmarshal)(e)) +} + +// ContinueAs can be used to stop the current workflow execution and start another one (of the same or a different type) +type ContinueAs struct { + // Unique id of the workflow to continue execution as. + // +kubebuilder:validation:Required + WorkflowID string `json:"workflowId" validate:"required"` + // Version of the workflow to continue execution as. + // +optional + Version string `json:"version,omitempty"` + // If string type, an expression which selects parts of the states data output to become the workflow data input of + // continued execution. If object type, a custom object to become the workflow data input of the continued execution + // +optional + Data Object `json:"data,omitempty"` + // WorkflowExecTimeout Workflow execution timeout to be used by the workflow continuing execution. + // Overwrites any specific settings set by that workflow + // +optional + WorkflowExecTimeout WorkflowExecTimeout `json:"workflowExecTimeout,omitempty"` +} + +type continueAsUnmarshal ContinueAs + +// UnmarshalJSON implements json.Unmarshaler +func (c *ContinueAs) UnmarshalJSON(data []byte) error { + return unmarshalPrimitiveOrObject("continueAs", data, &c.WorkflowID, (*continueAsUnmarshal)(c)) +} + +// ProduceEvent Defines the event (CloudEvent format) to be produced when workflow execution completes or during a +// workflow transitions. The eventRef property must match the name of one of the defined produced events in the +// events definition. +type ProduceEvent struct { + // Reference to a defined unique event name in the events definition + // +kubebuilder:validation:Required + EventRef string `json:"eventRef" validate:"required"` + // If String, expression which selects parts of the states data output to become the data of the produced event. + // If object a custom object to become the data of produced event. + // +optional + Data Object `json:"data,omitempty"` + // Add additional event extension context attributes. + // +optional + ContextAttributes map[string]string `json:"contextAttributes,omitempty"` +} + +// StateDataFilter ... +type StateDataFilter struct { + // Workflow expression to filter the state data input + Input string `json:"input,omitempty"` + // Workflow expression that filters the state data output + Output string `json:"output,omitempty"` +} + +// DataInputSchema Used to validate the workflow data input against a defined JSON Schema +type DataInputSchema struct { + // +kubebuilder:validation:Required + Schema string `json:"schema" validate:"required"` + // +kubebuilder:validation:Required + FailOnValidationErrors bool `json:"failOnValidationErrors" validate:"required"` +} + +type dataInputSchemaUnmarshal DataInputSchema + +// UnmarshalJSON implements json.Unmarshaler +func (d *DataInputSchema) UnmarshalJSON(data []byte) error { + d.ApplyDefault() + return unmarshalPrimitiveOrObject("dataInputSchema", data, &d.Schema, (*dataInputSchemaUnmarshal)(d)) +} + +// ApplyDefault set the default values for Data Input Schema +func (d *DataInputSchema) ApplyDefault() { + d.FailOnValidationErrors = true +} + +// Secrets allow you to access sensitive information, such as passwords, OAuth tokens, ssh keys, etc inside your +// Workflow Expressions. +type Secrets []string + +type secretsUnmarshal Secrets + +// UnmarshalJSON implements json.Unmarshaler +func (s *Secrets) UnmarshalJSON(data []byte) error { + return unmarshalObjectOrFile("secrets", data, (*secretsUnmarshal)(s)) +} + +// Constants Workflow constants are used to define static, and immutable, data which is available to Workflow Expressions. +type Constants struct { + // Data represents the generic structure of the constants value + // +optional + Data ConstantsData `json:",omitempty"` +} + +// UnmarshalJSON implements json.Unmarshaler +func (c *Constants) UnmarshalJSON(data []byte) error { + return unmarshalObjectOrFile("constants", data, &c.Data) +} + +type ConstantsData map[string]json.RawMessage diff --git a/vendor/github.com/serverlessworkflow/sdk-go/v2/model/workflow_ref.go b/vendor/github.com/serverlessworkflow/sdk-go/v2/model/workflow_ref.go new file mode 100644 index 0000000000..f0ec215d19 --- /dev/null +++ b/vendor/github.com/serverlessworkflow/sdk-go/v2/model/workflow_ref.go @@ -0,0 +1,50 @@ +// Copyright 2022 The Serverless Workflow Specification Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package model + +// WorkflowRef holds a reference for a workflow definition +type WorkflowRef struct { + // Sub-workflow unique id + // +kubebuilder:validation:Required + WorkflowID string `json:"workflowId" validate:"required"` + // Sub-workflow version + // +optional + Version string `json:"version,omitempty"` + // Specifies if the subflow should be invoked sync or async. + // Defaults to sync. + // +kubebuilder:validation:Enum=async;sync + // +kubebuilder:default=sync + // +optional + Invoke InvokeKind `json:"invoke,omitempty" validate:"required,oneofkind"` + // onParentComplete specifies how subflow execution should behave when parent workflow completes if invoke + // is 'async'. Defaults to terminate. + // +kubebuilder:validation:Enum=terminate;continue + // +kubebuilder:default=terminate + OnParentComplete string `json:"onParentComplete,omitempty" validate:"required,oneof=terminate continue"` +} + +type workflowRefUnmarshal WorkflowRef + +// UnmarshalJSON implements json.Unmarshaler +func (s *WorkflowRef) UnmarshalJSON(data []byte) error { + s.ApplyDefault() + return unmarshalPrimitiveOrObject("subFlowRef", data, &s.WorkflowID, (*workflowRefUnmarshal)(s)) +} + +// ApplyDefault set the default values for Workflow Ref +func (s *WorkflowRef) ApplyDefault() { + s.Invoke = InvokeKindSync + s.OnParentComplete = "terminate" +} diff --git a/vendor/github.com/serverlessworkflow/sdk-go/v2/model/workflow_validator.go b/vendor/github.com/serverlessworkflow/sdk-go/v2/model/workflow_validator.go new file mode 100644 index 0000000000..2ea7cf5ad1 --- /dev/null +++ b/vendor/github.com/serverlessworkflow/sdk-go/v2/model/workflow_validator.go @@ -0,0 +1,97 @@ +// Copyright 2021 The Serverless Workflow Specification Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package model + +import ( + "reflect" + + validator "github.com/go-playground/validator/v10" + val "github.com/serverlessworkflow/sdk-go/v2/validator" +) + +func init() { + val.GetValidator().RegisterStructValidation(continueAsStructLevelValidation, ContinueAs{}) + val.GetValidator().RegisterStructValidation(workflowStructLevelValidation, Workflow{}) +} + +func continueAsStructLevelValidation(structLevel validator.StructLevel) { + continueAs := structLevel.Current().Interface().(ContinueAs) + if len(continueAs.WorkflowExecTimeout.Duration) > 0 { + if err := val.ValidateISO8601TimeDuration(continueAs.WorkflowExecTimeout.Duration); err != nil { + structLevel.ReportError(reflect.ValueOf(continueAs.WorkflowExecTimeout.Duration), + "workflowExecTimeout", "duration", "iso8601duration", "") + } + } +} + +// WorkflowStructLevelValidation custom validator +func workflowStructLevelValidation(structLevel validator.StructLevel) { + // unique name of the auth methods + // NOTE: we cannot add the custom validation of auth to Auth + // because `RegisterStructValidation` only works with struct type + wf := structLevel.Current().Interface().(Workflow) + dict := map[string]bool{} + + for _, a := range wf.BaseWorkflow.Auth { + if !dict[a.Name] { + dict[a.Name] = true + } else { + structLevel.ReportError(reflect.ValueOf(a.Name), "[]Auth.Name", "name", "reqnameunique", "") + } + } + + startAndStatesTransitionValidator(structLevel, wf.BaseWorkflow.Start, wf.States) +} + +func startAndStatesTransitionValidator(structLevel validator.StructLevel, start *Start, states []State) { + statesMap := make(map[string]State, len(states)) + for _, state := range states { + statesMap[state.Name] = state + } + + if start != nil { + // if not exists the start transtion stop the states validations + if _, ok := statesMap[start.StateName]; !ok { + structLevel.ReportError(reflect.ValueOf(start), "Start", "start", "startnotexist", "") + return + } + } + + if len(states) == 1 { + return + } + + // Naive check if transitions exist + for _, state := range statesMap { + if state.Transition != nil { + if _, ok := statesMap[state.Transition.NextState]; !ok { + structLevel.ReportError(reflect.ValueOf(state), "Transition", "transition", "transitionnotexists", state.Transition.NextState) + } + } + } + + // TODO: create states graph to complex check +} + +func validTransitionAndEnd(structLevel validator.StructLevel, field interface{}, transition *Transition, end *End) { + hasTransition := transition != nil + isEnd := end != nil && (end.Terminate || end.ContinueAs != nil || len(end.ProduceEvents) > 0) // TODO: check the spec continueAs/produceEvents to see how it influences the end + + if !hasTransition && !isEnd { + structLevel.ReportError(field, "Transition", "transition", "required", "must have one of transition, end") + } else if hasTransition && isEnd { + structLevel.ReportError(field, "Transition", "transition", "exclusive", "must have one of transition, end") + } +} diff --git a/vendor/github.com/serverlessworkflow/sdk-go/v2/model/zz_generated.deepcopy.go b/vendor/github.com/serverlessworkflow/sdk-go/v2/model/zz_generated.deepcopy.go new file mode 100644 index 0000000000..d04a11b73f --- /dev/null +++ b/vendor/github.com/serverlessworkflow/sdk-go/v2/model/zz_generated.deepcopy.go @@ -0,0 +1,1745 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +// Copyright 2023 The Serverless Workflow Specification Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// Code generated by deepcopy-gen. DO NOT EDIT. + +package model + +import ( + json "encoding/json" + + floatstr "github.com/serverlessworkflow/sdk-go/v2/util/floatstr" + intstr "k8s.io/apimachinery/pkg/util/intstr" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Action) DeepCopyInto(out *Action) { + *out = *in + if in.FunctionRef != nil { + in, out := &in.FunctionRef, &out.FunctionRef + *out = new(FunctionRef) + (*in).DeepCopyInto(*out) + } + if in.EventRef != nil { + in, out := &in.EventRef, &out.EventRef + *out = new(EventRef) + (*in).DeepCopyInto(*out) + } + if in.SubFlowRef != nil { + in, out := &in.SubFlowRef, &out.SubFlowRef + *out = new(WorkflowRef) + **out = **in + } + if in.Sleep != nil { + in, out := &in.Sleep, &out.Sleep + *out = new(Sleep) + **out = **in + } + if in.NonRetryableErrors != nil { + in, out := &in.NonRetryableErrors, &out.NonRetryableErrors + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.RetryableErrors != nil { + in, out := &in.RetryableErrors, &out.RetryableErrors + *out = make([]string, len(*in)) + copy(*out, *in) + } + out.ActionDataFilter = in.ActionDataFilter + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Action. +func (in *Action) DeepCopy() *Action { + if in == nil { + return nil + } + out := new(Action) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ActionDataFilter) DeepCopyInto(out *ActionDataFilter) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ActionDataFilter. +func (in *ActionDataFilter) DeepCopy() *ActionDataFilter { + if in == nil { + return nil + } + out := new(ActionDataFilter) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Auth) DeepCopyInto(out *Auth) { + *out = *in + in.Properties.DeepCopyInto(&out.Properties) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Auth. +func (in *Auth) DeepCopy() *Auth { + if in == nil { + return nil + } + out := new(Auth) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AuthProperties) DeepCopyInto(out *AuthProperties) { + *out = *in + if in.Basic != nil { + in, out := &in.Basic, &out.Basic + *out = new(BasicAuthProperties) + (*in).DeepCopyInto(*out) + } + if in.Bearer != nil { + in, out := &in.Bearer, &out.Bearer + *out = new(BearerAuthProperties) + (*in).DeepCopyInto(*out) + } + if in.OAuth2 != nil { + in, out := &in.OAuth2, &out.OAuth2 + *out = new(OAuth2AuthProperties) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AuthProperties. +func (in *AuthProperties) DeepCopy() *AuthProperties { + if in == nil { + return nil + } + out := new(AuthProperties) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in Auths) DeepCopyInto(out *Auths) { + { + in := &in + *out = make(Auths, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + return + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Auths. +func (in Auths) DeepCopy() Auths { + if in == nil { + return nil + } + out := new(Auths) + in.DeepCopyInto(out) + return *out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BaseState) DeepCopyInto(out *BaseState) { + *out = *in + if in.OnErrors != nil { + in, out := &in.OnErrors, &out.OnErrors + *out = make([]OnError, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Transition != nil { + in, out := &in.Transition, &out.Transition + *out = new(Transition) + (*in).DeepCopyInto(*out) + } + if in.StateDataFilter != nil { + in, out := &in.StateDataFilter, &out.StateDataFilter + *out = new(StateDataFilter) + **out = **in + } + if in.End != nil { + in, out := &in.End, &out.End + *out = new(End) + (*in).DeepCopyInto(*out) + } + if in.Metadata != nil { + in, out := &in.Metadata, &out.Metadata + *out = new(Metadata) + if **in != nil { + in, out := *in, *out + *out = make(map[string]Object, len(*in)) + for key, val := range *in { + (*out)[key] = *val.DeepCopy() + } + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BaseState. +func (in *BaseState) DeepCopy() *BaseState { + if in == nil { + return nil + } + out := new(BaseState) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BaseWorkflow) DeepCopyInto(out *BaseWorkflow) { + *out = *in + if in.Start != nil { + in, out := &in.Start, &out.Start + *out = new(Start) + (*in).DeepCopyInto(*out) + } + if in.Annotations != nil { + in, out := &in.Annotations, &out.Annotations + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.DataInputSchema != nil { + in, out := &in.DataInputSchema, &out.DataInputSchema + *out = new(DataInputSchema) + **out = **in + } + if in.Secrets != nil { + in, out := &in.Secrets, &out.Secrets + *out = make(Secrets, len(*in)) + copy(*out, *in) + } + if in.Constants != nil { + in, out := &in.Constants, &out.Constants + *out = new(Constants) + (*in).DeepCopyInto(*out) + } + if in.Timeouts != nil { + in, out := &in.Timeouts, &out.Timeouts + *out = new(Timeouts) + (*in).DeepCopyInto(*out) + } + if in.Errors != nil { + in, out := &in.Errors, &out.Errors + *out = make(Errors, len(*in)) + copy(*out, *in) + } + if in.Metadata != nil { + in, out := &in.Metadata, &out.Metadata + *out = make(Metadata, len(*in)) + for key, val := range *in { + (*out)[key] = *val.DeepCopy() + } + } + if in.Auth != nil { + in, out := &in.Auth, &out.Auth + *out = make(Auths, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BaseWorkflow. +func (in *BaseWorkflow) DeepCopy() *BaseWorkflow { + if in == nil { + return nil + } + out := new(BaseWorkflow) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BasicAuthProperties) DeepCopyInto(out *BasicAuthProperties) { + *out = *in + in.Common.DeepCopyInto(&out.Common) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BasicAuthProperties. +func (in *BasicAuthProperties) DeepCopy() *BasicAuthProperties { + if in == nil { + return nil + } + out := new(BasicAuthProperties) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BearerAuthProperties) DeepCopyInto(out *BearerAuthProperties) { + *out = *in + in.Common.DeepCopyInto(&out.Common) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BearerAuthProperties. +func (in *BearerAuthProperties) DeepCopy() *BearerAuthProperties { + if in == nil { + return nil + } + out := new(BearerAuthProperties) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Branch) DeepCopyInto(out *Branch) { + *out = *in + if in.Actions != nil { + in, out := &in.Actions, &out.Actions + *out = make([]Action, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Timeouts != nil { + in, out := &in.Timeouts, &out.Timeouts + *out = new(BranchTimeouts) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Branch. +func (in *Branch) DeepCopy() *Branch { + if in == nil { + return nil + } + out := new(Branch) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BranchTimeouts) DeepCopyInto(out *BranchTimeouts) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BranchTimeouts. +func (in *BranchTimeouts) DeepCopy() *BranchTimeouts { + if in == nil { + return nil + } + out := new(BranchTimeouts) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CallbackState) DeepCopyInto(out *CallbackState) { + *out = *in + in.Action.DeepCopyInto(&out.Action) + if in.Timeouts != nil { + in, out := &in.Timeouts, &out.Timeouts + *out = new(CallbackStateTimeout) + (*in).DeepCopyInto(*out) + } + if in.EventDataFilter != nil { + in, out := &in.EventDataFilter, &out.EventDataFilter + *out = new(EventDataFilter) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CallbackState. +func (in *CallbackState) DeepCopy() *CallbackState { + if in == nil { + return nil + } + out := new(CallbackState) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CallbackStateTimeout) DeepCopyInto(out *CallbackStateTimeout) { + *out = *in + if in.StateExecTimeout != nil { + in, out := &in.StateExecTimeout, &out.StateExecTimeout + *out = new(StateExecTimeout) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CallbackStateTimeout. +func (in *CallbackStateTimeout) DeepCopy() *CallbackStateTimeout { + if in == nil { + return nil + } + out := new(CallbackStateTimeout) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Common) DeepCopyInto(out *Common) { + *out = *in + if in.Metadata != nil { + in, out := &in.Metadata, &out.Metadata + *out = make(Metadata, len(*in)) + for key, val := range *in { + (*out)[key] = *val.DeepCopy() + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Common. +func (in *Common) DeepCopy() *Common { + if in == nil { + return nil + } + out := new(Common) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Constants) DeepCopyInto(out *Constants) { + *out = *in + if in.Data != nil { + in, out := &in.Data, &out.Data + *out = make(ConstantsData, len(*in)) + for key, val := range *in { + var outVal []byte + if val == nil { + (*out)[key] = nil + } else { + in, out := &val, &outVal + *out = make(json.RawMessage, len(*in)) + copy(*out, *in) + } + (*out)[key] = outVal + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Constants. +func (in *Constants) DeepCopy() *Constants { + if in == nil { + return nil + } + out := new(Constants) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in ConstantsData) DeepCopyInto(out *ConstantsData) { + { + in := &in + *out = make(ConstantsData, len(*in)) + for key, val := range *in { + var outVal []byte + if val == nil { + (*out)[key] = nil + } else { + in, out := &val, &outVal + *out = make(json.RawMessage, len(*in)) + copy(*out, *in) + } + (*out)[key] = outVal + } + return + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConstantsData. +func (in ConstantsData) DeepCopy() ConstantsData { + if in == nil { + return nil + } + out := new(ConstantsData) + in.DeepCopyInto(out) + return *out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ContinueAs) DeepCopyInto(out *ContinueAs) { + *out = *in + in.Data.DeepCopyInto(&out.Data) + out.WorkflowExecTimeout = in.WorkflowExecTimeout + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ContinueAs. +func (in *ContinueAs) DeepCopy() *ContinueAs { + if in == nil { + return nil + } + out := new(ContinueAs) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Correlation) DeepCopyInto(out *Correlation) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Correlation. +func (in *Correlation) DeepCopy() *Correlation { + if in == nil { + return nil + } + out := new(Correlation) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Cron) DeepCopyInto(out *Cron) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Cron. +func (in *Cron) DeepCopy() *Cron { + if in == nil { + return nil + } + out := new(Cron) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DataCondition) DeepCopyInto(out *DataCondition) { + *out = *in + if in.Metadata != nil { + in, out := &in.Metadata, &out.Metadata + *out = make(Metadata, len(*in)) + for key, val := range *in { + (*out)[key] = *val.DeepCopy() + } + } + if in.End != nil { + in, out := &in.End, &out.End + *out = new(End) + (*in).DeepCopyInto(*out) + } + if in.Transition != nil { + in, out := &in.Transition, &out.Transition + *out = new(Transition) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DataCondition. +func (in *DataCondition) DeepCopy() *DataCondition { + if in == nil { + return nil + } + out := new(DataCondition) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DataInputSchema) DeepCopyInto(out *DataInputSchema) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DataInputSchema. +func (in *DataInputSchema) DeepCopy() *DataInputSchema { + if in == nil { + return nil + } + out := new(DataInputSchema) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DefaultCondition) DeepCopyInto(out *DefaultCondition) { + *out = *in + if in.Transition != nil { + in, out := &in.Transition, &out.Transition + *out = new(Transition) + (*in).DeepCopyInto(*out) + } + if in.End != nil { + in, out := &in.End, &out.End + *out = new(End) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DefaultCondition. +func (in *DefaultCondition) DeepCopy() *DefaultCondition { + if in == nil { + return nil + } + out := new(DefaultCondition) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DelayState) DeepCopyInto(out *DelayState) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DelayState. +func (in *DelayState) DeepCopy() *DelayState { + if in == nil { + return nil + } + out := new(DelayState) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *End) DeepCopyInto(out *End) { + *out = *in + if in.ProduceEvents != nil { + in, out := &in.ProduceEvents, &out.ProduceEvents + *out = make([]ProduceEvent, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.ContinueAs != nil { + in, out := &in.ContinueAs, &out.ContinueAs + *out = new(ContinueAs) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new End. +func (in *End) DeepCopy() *End { + if in == nil { + return nil + } + out := new(End) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Error) DeepCopyInto(out *Error) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Error. +func (in *Error) DeepCopy() *Error { + if in == nil { + return nil + } + out := new(Error) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in Errors) DeepCopyInto(out *Errors) { + { + in := &in + *out = make(Errors, len(*in)) + copy(*out, *in) + return + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Errors. +func (in Errors) DeepCopy() Errors { + if in == nil { + return nil + } + out := new(Errors) + in.DeepCopyInto(out) + return *out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Event) DeepCopyInto(out *Event) { + *out = *in + in.Common.DeepCopyInto(&out.Common) + if in.Correlation != nil { + in, out := &in.Correlation, &out.Correlation + *out = make([]Correlation, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Event. +func (in *Event) DeepCopy() *Event { + if in == nil { + return nil + } + out := new(Event) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *EventCondition) DeepCopyInto(out *EventCondition) { + *out = *in + if in.EventDataFilter != nil { + in, out := &in.EventDataFilter, &out.EventDataFilter + *out = new(EventDataFilter) + **out = **in + } + if in.Metadata != nil { + in, out := &in.Metadata, &out.Metadata + *out = make(Metadata, len(*in)) + for key, val := range *in { + (*out)[key] = *val.DeepCopy() + } + } + if in.End != nil { + in, out := &in.End, &out.End + *out = new(End) + (*in).DeepCopyInto(*out) + } + if in.Transition != nil { + in, out := &in.Transition, &out.Transition + *out = new(Transition) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EventCondition. +func (in *EventCondition) DeepCopy() *EventCondition { + if in == nil { + return nil + } + out := new(EventCondition) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *EventDataFilter) DeepCopyInto(out *EventDataFilter) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EventDataFilter. +func (in *EventDataFilter) DeepCopy() *EventDataFilter { + if in == nil { + return nil + } + out := new(EventDataFilter) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *EventRef) DeepCopyInto(out *EventRef) { + *out = *in + if in.Data != nil { + in, out := &in.Data, &out.Data + *out = new(Object) + (*in).DeepCopyInto(*out) + } + if in.ContextAttributes != nil { + in, out := &in.ContextAttributes, &out.ContextAttributes + *out = make(map[string]Object, len(*in)) + for key, val := range *in { + (*out)[key] = *val.DeepCopy() + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EventRef. +func (in *EventRef) DeepCopy() *EventRef { + if in == nil { + return nil + } + out := new(EventRef) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *EventState) DeepCopyInto(out *EventState) { + *out = *in + if in.OnEvents != nil { + in, out := &in.OnEvents, &out.OnEvents + *out = make([]OnEvents, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Timeouts != nil { + in, out := &in.Timeouts, &out.Timeouts + *out = new(EventStateTimeout) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EventState. +func (in *EventState) DeepCopy() *EventState { + if in == nil { + return nil + } + out := new(EventState) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *EventStateTimeout) DeepCopyInto(out *EventStateTimeout) { + *out = *in + if in.StateExecTimeout != nil { + in, out := &in.StateExecTimeout, &out.StateExecTimeout + *out = new(StateExecTimeout) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EventStateTimeout. +func (in *EventStateTimeout) DeepCopy() *EventStateTimeout { + if in == nil { + return nil + } + out := new(EventStateTimeout) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in Events) DeepCopyInto(out *Events) { + { + in := &in + *out = make(Events, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + return + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Events. +func (in Events) DeepCopy() Events { + if in == nil { + return nil + } + out := new(Events) + in.DeepCopyInto(out) + return *out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ForEachState) DeepCopyInto(out *ForEachState) { + *out = *in + if in.BatchSize != nil { + in, out := &in.BatchSize, &out.BatchSize + *out = new(intstr.IntOrString) + **out = **in + } + if in.Actions != nil { + in, out := &in.Actions, &out.Actions + *out = make([]Action, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Timeouts != nil { + in, out := &in.Timeouts, &out.Timeouts + *out = new(ForEachStateTimeout) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ForEachState. +func (in *ForEachState) DeepCopy() *ForEachState { + if in == nil { + return nil + } + out := new(ForEachState) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ForEachStateTimeout) DeepCopyInto(out *ForEachStateTimeout) { + *out = *in + if in.StateExecTimeout != nil { + in, out := &in.StateExecTimeout, &out.StateExecTimeout + *out = new(StateExecTimeout) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ForEachStateTimeout. +func (in *ForEachStateTimeout) DeepCopy() *ForEachStateTimeout { + if in == nil { + return nil + } + out := new(ForEachStateTimeout) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Function) DeepCopyInto(out *Function) { + *out = *in + in.Common.DeepCopyInto(&out.Common) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Function. +func (in *Function) DeepCopy() *Function { + if in == nil { + return nil + } + out := new(Function) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FunctionRef) DeepCopyInto(out *FunctionRef) { + *out = *in + if in.Arguments != nil { + in, out := &in.Arguments, &out.Arguments + *out = make(map[string]Object, len(*in)) + for key, val := range *in { + (*out)[key] = *val.DeepCopy() + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FunctionRef. +func (in *FunctionRef) DeepCopy() *FunctionRef { + if in == nil { + return nil + } + out := new(FunctionRef) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in Functions) DeepCopyInto(out *Functions) { + { + in := &in + *out = make(Functions, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + return + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Functions. +func (in Functions) DeepCopy() Functions { + if in == nil { + return nil + } + out := new(Functions) + in.DeepCopyInto(out) + return *out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *InjectState) DeepCopyInto(out *InjectState) { + *out = *in + if in.Data != nil { + in, out := &in.Data, &out.Data + *out = make(map[string]Object, len(*in)) + for key, val := range *in { + (*out)[key] = *val.DeepCopy() + } + } + if in.Timeouts != nil { + in, out := &in.Timeouts, &out.Timeouts + *out = new(InjectStateTimeout) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InjectState. +func (in *InjectState) DeepCopy() *InjectState { + if in == nil { + return nil + } + out := new(InjectState) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *InjectStateTimeout) DeepCopyInto(out *InjectStateTimeout) { + *out = *in + if in.StateExecTimeout != nil { + in, out := &in.StateExecTimeout, &out.StateExecTimeout + *out = new(StateExecTimeout) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InjectStateTimeout. +func (in *InjectStateTimeout) DeepCopy() *InjectStateTimeout { + if in == nil { + return nil + } + out := new(InjectStateTimeout) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in Metadata) DeepCopyInto(out *Metadata) { + { + in := &in + *out = make(Metadata, len(*in)) + for key, val := range *in { + (*out)[key] = *val.DeepCopy() + } + return + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Metadata. +func (in Metadata) DeepCopy() Metadata { + if in == nil { + return nil + } + out := new(Metadata) + in.DeepCopyInto(out) + return *out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *OAuth2AuthProperties) DeepCopyInto(out *OAuth2AuthProperties) { + *out = *in + in.Common.DeepCopyInto(&out.Common) + if in.Scopes != nil { + in, out := &in.Scopes, &out.Scopes + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Audiences != nil { + in, out := &in.Audiences, &out.Audiences + *out = make([]string, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OAuth2AuthProperties. +func (in *OAuth2AuthProperties) DeepCopy() *OAuth2AuthProperties { + if in == nil { + return nil + } + out := new(OAuth2AuthProperties) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Object) DeepCopyInto(out *Object) { + *out = *in + if in.RawValue != nil { + in, out := &in.RawValue, &out.RawValue + *out = make(json.RawMessage, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Object. +func (in *Object) DeepCopy() *Object { + if in == nil { + return nil + } + out := new(Object) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *OnError) DeepCopyInto(out *OnError) { + *out = *in + if in.ErrorRefs != nil { + in, out := &in.ErrorRefs, &out.ErrorRefs + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Transition != nil { + in, out := &in.Transition, &out.Transition + *out = new(Transition) + (*in).DeepCopyInto(*out) + } + if in.End != nil { + in, out := &in.End, &out.End + *out = new(End) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OnError. +func (in *OnError) DeepCopy() *OnError { + if in == nil { + return nil + } + out := new(OnError) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *OnEvents) DeepCopyInto(out *OnEvents) { + *out = *in + if in.EventRefs != nil { + in, out := &in.EventRefs, &out.EventRefs + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Actions != nil { + in, out := &in.Actions, &out.Actions + *out = make([]Action, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + out.EventDataFilter = in.EventDataFilter + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OnEvents. +func (in *OnEvents) DeepCopy() *OnEvents { + if in == nil { + return nil + } + out := new(OnEvents) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *OperationState) DeepCopyInto(out *OperationState) { + *out = *in + if in.Actions != nil { + in, out := &in.Actions, &out.Actions + *out = make([]Action, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Timeouts != nil { + in, out := &in.Timeouts, &out.Timeouts + *out = new(OperationStateTimeout) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OperationState. +func (in *OperationState) DeepCopy() *OperationState { + if in == nil { + return nil + } + out := new(OperationState) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *OperationStateTimeout) DeepCopyInto(out *OperationStateTimeout) { + *out = *in + if in.StateExecTimeout != nil { + in, out := &in.StateExecTimeout, &out.StateExecTimeout + *out = new(StateExecTimeout) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OperationStateTimeout. +func (in *OperationStateTimeout) DeepCopy() *OperationStateTimeout { + if in == nil { + return nil + } + out := new(OperationStateTimeout) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ParallelState) DeepCopyInto(out *ParallelState) { + *out = *in + if in.Branches != nil { + in, out := &in.Branches, &out.Branches + *out = make([]Branch, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + out.NumCompleted = in.NumCompleted + if in.Timeouts != nil { + in, out := &in.Timeouts, &out.Timeouts + *out = new(ParallelStateTimeout) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ParallelState. +func (in *ParallelState) DeepCopy() *ParallelState { + if in == nil { + return nil + } + out := new(ParallelState) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ParallelStateTimeout) DeepCopyInto(out *ParallelStateTimeout) { + *out = *in + if in.StateExecTimeout != nil { + in, out := &in.StateExecTimeout, &out.StateExecTimeout + *out = new(StateExecTimeout) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ParallelStateTimeout. +func (in *ParallelStateTimeout) DeepCopy() *ParallelStateTimeout { + if in == nil { + return nil + } + out := new(ParallelStateTimeout) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ProduceEvent) DeepCopyInto(out *ProduceEvent) { + *out = *in + in.Data.DeepCopyInto(&out.Data) + if in.ContextAttributes != nil { + in, out := &in.ContextAttributes, &out.ContextAttributes + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProduceEvent. +func (in *ProduceEvent) DeepCopy() *ProduceEvent { + if in == nil { + return nil + } + out := new(ProduceEvent) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in Retries) DeepCopyInto(out *Retries) { + { + in := &in + *out = make(Retries, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + return + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Retries. +func (in Retries) DeepCopy() Retries { + if in == nil { + return nil + } + out := new(Retries) + in.DeepCopyInto(out) + return *out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Retry) DeepCopyInto(out *Retry) { + *out = *in + if in.Multiplier != nil { + in, out := &in.Multiplier, &out.Multiplier + *out = new(floatstr.Float32OrString) + **out = **in + } + out.MaxAttempts = in.MaxAttempts + out.Jitter = in.Jitter + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Retry. +func (in *Retry) DeepCopy() *Retry { + if in == nil { + return nil + } + out := new(Retry) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Schedule) DeepCopyInto(out *Schedule) { + *out = *in + if in.Cron != nil { + in, out := &in.Cron, &out.Cron + *out = new(Cron) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Schedule. +func (in *Schedule) DeepCopy() *Schedule { + if in == nil { + return nil + } + out := new(Schedule) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in Secrets) DeepCopyInto(out *Secrets) { + { + in := &in + *out = make(Secrets, len(*in)) + copy(*out, *in) + return + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Secrets. +func (in Secrets) DeepCopy() Secrets { + if in == nil { + return nil + } + out := new(Secrets) + in.DeepCopyInto(out) + return *out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Sleep) DeepCopyInto(out *Sleep) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Sleep. +func (in *Sleep) DeepCopy() *Sleep { + if in == nil { + return nil + } + out := new(Sleep) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SleepState) DeepCopyInto(out *SleepState) { + *out = *in + if in.Timeouts != nil { + in, out := &in.Timeouts, &out.Timeouts + *out = new(SleepStateTimeout) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SleepState. +func (in *SleepState) DeepCopy() *SleepState { + if in == nil { + return nil + } + out := new(SleepState) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SleepStateTimeout) DeepCopyInto(out *SleepStateTimeout) { + *out = *in + if in.StateExecTimeout != nil { + in, out := &in.StateExecTimeout, &out.StateExecTimeout + *out = new(StateExecTimeout) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SleepStateTimeout. +func (in *SleepStateTimeout) DeepCopy() *SleepStateTimeout { + if in == nil { + return nil + } + out := new(SleepStateTimeout) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Start) DeepCopyInto(out *Start) { + *out = *in + if in.Schedule != nil { + in, out := &in.Schedule, &out.Schedule + *out = new(Schedule) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Start. +func (in *Start) DeepCopy() *Start { + if in == nil { + return nil + } + out := new(Start) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *State) DeepCopyInto(out *State) { + *out = *in + in.BaseState.DeepCopyInto(&out.BaseState) + if in.DelayState != nil { + in, out := &in.DelayState, &out.DelayState + *out = new(DelayState) + **out = **in + } + if in.EventState != nil { + in, out := &in.EventState, &out.EventState + *out = new(EventState) + (*in).DeepCopyInto(*out) + } + if in.OperationState != nil { + in, out := &in.OperationState, &out.OperationState + *out = new(OperationState) + (*in).DeepCopyInto(*out) + } + if in.ParallelState != nil { + in, out := &in.ParallelState, &out.ParallelState + *out = new(ParallelState) + (*in).DeepCopyInto(*out) + } + if in.SwitchState != nil { + in, out := &in.SwitchState, &out.SwitchState + *out = new(SwitchState) + (*in).DeepCopyInto(*out) + } + if in.ForEachState != nil { + in, out := &in.ForEachState, &out.ForEachState + *out = new(ForEachState) + (*in).DeepCopyInto(*out) + } + if in.InjectState != nil { + in, out := &in.InjectState, &out.InjectState + *out = new(InjectState) + (*in).DeepCopyInto(*out) + } + if in.CallbackState != nil { + in, out := &in.CallbackState, &out.CallbackState + *out = new(CallbackState) + (*in).DeepCopyInto(*out) + } + if in.SleepState != nil { + in, out := &in.SleepState, &out.SleepState + *out = new(SleepState) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new State. +func (in *State) DeepCopy() *State { + if in == nil { + return nil + } + out := new(State) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StateDataFilter) DeepCopyInto(out *StateDataFilter) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StateDataFilter. +func (in *StateDataFilter) DeepCopy() *StateDataFilter { + if in == nil { + return nil + } + out := new(StateDataFilter) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StateExecTimeout) DeepCopyInto(out *StateExecTimeout) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StateExecTimeout. +func (in *StateExecTimeout) DeepCopy() *StateExecTimeout { + if in == nil { + return nil + } + out := new(StateExecTimeout) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in States) DeepCopyInto(out *States) { + { + in := &in + *out = make(States, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + return + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new States. +func (in States) DeepCopy() States { + if in == nil { + return nil + } + out := new(States) + in.DeepCopyInto(out) + return *out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SwitchState) DeepCopyInto(out *SwitchState) { + *out = *in + in.DefaultCondition.DeepCopyInto(&out.DefaultCondition) + if in.EventConditions != nil { + in, out := &in.EventConditions, &out.EventConditions + *out = make([]EventCondition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.DataConditions != nil { + in, out := &in.DataConditions, &out.DataConditions + *out = make([]DataCondition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Timeouts != nil { + in, out := &in.Timeouts, &out.Timeouts + *out = new(SwitchStateTimeout) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SwitchState. +func (in *SwitchState) DeepCopy() *SwitchState { + if in == nil { + return nil + } + out := new(SwitchState) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SwitchStateTimeout) DeepCopyInto(out *SwitchStateTimeout) { + *out = *in + if in.StateExecTimeout != nil { + in, out := &in.StateExecTimeout, &out.StateExecTimeout + *out = new(StateExecTimeout) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SwitchStateTimeout. +func (in *SwitchStateTimeout) DeepCopy() *SwitchStateTimeout { + if in == nil { + return nil + } + out := new(SwitchStateTimeout) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Timeouts) DeepCopyInto(out *Timeouts) { + *out = *in + if in.WorkflowExecTimeout != nil { + in, out := &in.WorkflowExecTimeout, &out.WorkflowExecTimeout + *out = new(WorkflowExecTimeout) + **out = **in + } + if in.StateExecTimeout != nil { + in, out := &in.StateExecTimeout, &out.StateExecTimeout + *out = new(StateExecTimeout) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Timeouts. +func (in *Timeouts) DeepCopy() *Timeouts { + if in == nil { + return nil + } + out := new(Timeouts) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Transition) DeepCopyInto(out *Transition) { + *out = *in + if in.ProduceEvents != nil { + in, out := &in.ProduceEvents, &out.ProduceEvents + *out = make([]ProduceEvent, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Transition. +func (in *Transition) DeepCopy() *Transition { + if in == nil { + return nil + } + out := new(Transition) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Workflow) DeepCopyInto(out *Workflow) { + *out = *in + in.BaseWorkflow.DeepCopyInto(&out.BaseWorkflow) + if in.States != nil { + in, out := &in.States, &out.States + *out = make([]State, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Events != nil { + in, out := &in.Events, &out.Events + *out = make(Events, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Functions != nil { + in, out := &in.Functions, &out.Functions + *out = make(Functions, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Retries != nil { + in, out := &in.Retries, &out.Retries + *out = make(Retries, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Workflow. +func (in *Workflow) DeepCopy() *Workflow { + if in == nil { + return nil + } + out := new(Workflow) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *WorkflowExecTimeout) DeepCopyInto(out *WorkflowExecTimeout) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkflowExecTimeout. +func (in *WorkflowExecTimeout) DeepCopy() *WorkflowExecTimeout { + if in == nil { + return nil + } + out := new(WorkflowExecTimeout) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *WorkflowRef) DeepCopyInto(out *WorkflowRef) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkflowRef. +func (in *WorkflowRef) DeepCopy() *WorkflowRef { + if in == nil { + return nil + } + out := new(WorkflowRef) + in.DeepCopyInto(out) + return out +} diff --git a/vendor/github.com/serverlessworkflow/sdk-go/v2/parser/parser.go b/vendor/github.com/serverlessworkflow/sdk-go/v2/parser/parser.go new file mode 100644 index 0000000000..fe9972dc7b --- /dev/null +++ b/vendor/github.com/serverlessworkflow/sdk-go/v2/parser/parser.go @@ -0,0 +1,89 @@ +// Copyright 2020 The Serverless Workflow Specification Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package parser + +import ( + "encoding/json" + "fmt" + "os" + "path/filepath" + "strings" + + "github.com/serverlessworkflow/sdk-go/v2/validator" + + "github.com/serverlessworkflow/sdk-go/v2/model" + "sigs.k8s.io/yaml" +) + +const ( + extJSON = ".json" + extYAML = ".yaml" + extYML = ".yml" +) + +var supportedExt = []string{extYAML, extYML, extJSON} + +// FromYAMLSource parses the given Serverless Workflow YAML source into the Workflow type. +func FromYAMLSource(source []byte) (workflow *model.Workflow, err error) { + var jsonBytes []byte + if jsonBytes, err = yaml.YAMLToJSON(source); err != nil { + return nil, err + } + return FromJSONSource(jsonBytes) +} + +// FromJSONSource parses the given Serverless Workflow JSON source into the Workflow type. +func FromJSONSource(source []byte) (workflow *model.Workflow, err error) { + workflow = &model.Workflow{} + if err := json.Unmarshal(source, workflow); err != nil { + return nil, err + } + if err := validator.GetValidator().Struct(workflow); err != nil { + return nil, err + } + return workflow, nil +} + +// FromFile parses the given Serverless Workflow file into the Workflow type. +func FromFile(path string) (*model.Workflow, error) { + if err := checkFilePath(path); err != nil { + return nil, err + } + fileBytes, err := os.ReadFile(filepath.Clean(path)) + if err != nil { + return nil, err + } + if strings.HasSuffix(path, extYAML) || strings.HasSuffix(path, extYML) { + return FromYAMLSource(fileBytes) + } + return FromJSONSource(fileBytes) +} + +// checkFilePath verifies if the file exists in the given path and if it's supported by the parser package +func checkFilePath(path string) error { + info, err := os.Stat(path) + if err != nil { + return err + } + if info.IsDir() { + return fmt.Errorf("file path '%s' must stand to a file", path) + } + for _, ext := range supportedExt { + if strings.HasSuffix(path, ext) { + return nil + } + } + return fmt.Errorf("file extension not supported for '%s'. supported formats are %s", path, supportedExt) +} diff --git a/vendor/github.com/serverlessworkflow/sdk-go/v2/util/floatstr/floatstr.go b/vendor/github.com/serverlessworkflow/sdk-go/v2/util/floatstr/floatstr.go new file mode 100644 index 0000000000..3261fdd709 --- /dev/null +++ b/vendor/github.com/serverlessworkflow/sdk-go/v2/util/floatstr/floatstr.go @@ -0,0 +1,105 @@ +// Copyright 2021 The Serverless Workflow Specification Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package floatstr + +import ( + "encoding/json" + "fmt" + "strconv" +) + +// Float32OrString is a type that can hold a float32 or a string. +// implementation borrowed from apimachinary intstr package: https://github.com/kubernetes/apimachinery/blob/master/pkg/util/intstr/intstr.go +type Float32OrString struct { + Type Type `json:"type,omitempty"` + FloatVal float32 `json:"floatVal,omitempty"` + StrVal string `json:"strVal,omitempty"` +} + +// Type represents the stored type of Float32OrString. +type Type int64 + +const ( + // Float ... + Float Type = iota // The Float32OrString holds a float. + // String ... + String // The Float32OrString holds a string. +) + +// FromFloat creates an Float32OrString object with a float32 value. It is +// your responsibility not to call this method with a value greater +// than float32. +func FromFloat(val float32) Float32OrString { + return Float32OrString{Type: Float, FloatVal: val} +} + +// FromString creates a Float32OrString object with a string value. +func FromString(val string) Float32OrString { + return Float32OrString{Type: String, StrVal: val} +} + +// Parse the given string and try to convert it to a float32 before +// setting it as a string value. +func Parse(val string) Float32OrString { + f, err := strconv.ParseFloat(val, 32) + if err != nil { + return FromString(val) + } + return FromFloat(float32(f)) +} + +// UnmarshalJSON implements the json.Unmarshaller interface. +func (floatstr *Float32OrString) UnmarshalJSON(value []byte) error { + if value[0] == '"' { + floatstr.Type = String + return json.Unmarshal(value, &floatstr.StrVal) + } + floatstr.Type = Float + return json.Unmarshal(value, &floatstr.FloatVal) +} + +// MarshalJSON implements the json.Marshaller interface. +func (floatstr Float32OrString) MarshalJSON() ([]byte, error) { + switch floatstr.Type { + case Float: + return json.Marshal(floatstr.FloatVal) + case String: + return json.Marshal(floatstr.StrVal) + default: + return []byte{}, fmt.Errorf("impossible Float32OrString.Type") + } +} + +// String returns the string value, or the float value. +func (floatstr *Float32OrString) String() string { + if floatstr == nil { + return "" + } + if floatstr.Type == String { + return floatstr.StrVal + } + return strconv.FormatFloat(float64(floatstr.FloatValue()), 'E', -1, 32) +} + +// FloatValue returns the FloatVal if type float32, or if +// it is a String, will attempt a conversion to float32, +// returning 0 if a parsing error occurs. +func (floatstr *Float32OrString) FloatValue() float32 { + if floatstr.Type == String { + f, _ := strconv.ParseFloat(floatstr.StrVal, 32) + return float32(f) + } + return floatstr.FloatVal +} diff --git a/vendor/github.com/serverlessworkflow/sdk-go/v2/validator/tags.go b/vendor/github.com/serverlessworkflow/sdk-go/v2/validator/tags.go new file mode 100644 index 0000000000..e568aba9b5 --- /dev/null +++ b/vendor/github.com/serverlessworkflow/sdk-go/v2/validator/tags.go @@ -0,0 +1,20 @@ +// Copyright 2022 The Serverless Workflow Specification Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package validator + +const ( + // TagISO8601Duration is the validate tag for iso8601 time duration format + TagISO8601Duration = "iso8601duration" +) diff --git a/vendor/github.com/serverlessworkflow/sdk-go/v2/validator/validator.go b/vendor/github.com/serverlessworkflow/sdk-go/v2/validator/validator.go new file mode 100644 index 0000000000..846203d256 --- /dev/null +++ b/vendor/github.com/serverlessworkflow/sdk-go/v2/validator/validator.go @@ -0,0 +1,74 @@ +// Copyright 2021 The Serverless Workflow Specification Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package validator + +import ( + "context" + + validator "github.com/go-playground/validator/v10" + "github.com/senseyeio/duration" +) + +// TODO: expose a better validation message. See: https://pkg.go.dev/gopkg.in/go-playground/validator.v8#section-documentation + +type Kind interface { + KindValues() []string + String() string +} + +var validate *validator.Validate + +func init() { + validate = validator.New() + + err := validate.RegisterValidationCtx("iso8601duration", validateISO8601TimeDurationFunc) + if err != nil { + panic(err) + } + + err = validate.RegisterValidation("oneofkind", oneOfKind) + if err != nil { + panic(err) + } + +} + +// GetValidator gets the default validator.Validate reference +func GetValidator() *validator.Validate { + return validate +} + +// ValidateISO8601TimeDuration validate the string is iso8601 duration format +func ValidateISO8601TimeDuration(s string) error { + _, err := duration.ParseISO8601(s) + return err +} + +func validateISO8601TimeDurationFunc(_ context.Context, fl validator.FieldLevel) bool { + err := ValidateISO8601TimeDuration(fl.Field().String()) + return err == nil +} + +func oneOfKind(fl validator.FieldLevel) bool { + if val, ok := fl.Field().Interface().(Kind); ok { + for _, value := range val.KindValues() { + if value == val.String() { + return true + } + } + } + + return false +} diff --git a/vendor/github.com/vmware-labs/yaml-jsonpath/LICENSE b/vendor/github.com/vmware-labs/yaml-jsonpath/LICENSE new file mode 100644 index 0000000000..62a56a3359 --- /dev/null +++ b/vendor/github.com/vmware-labs/yaml-jsonpath/LICENSE @@ -0,0 +1,181 @@ +yaml-jsonpath +Copyright (c) 2020 VMware, Inc. All rights reserved. + +The Apache 2.0 license (the "License") set forth below applies to all parts of the yaml-jsonpath project. You may not use this file except in compliance with the License. + +Apache License + +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, +and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the +copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other +entities that control, are controlled by, or are under common control +with that entity. For the purposes of this definition, "control" means +(i) the power, direct or indirect, to cause the direction or management +of such entity, whether by contract or otherwise, or (ii) ownership +of fifty percent (50%) or more of the outstanding shares, or (iii) +beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising +permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, +including but not limited to software source code, documentation source, +and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation +or translation of a Source form, including but not limited to compiled +object code, generated documentation, and conversions to other media +types. + +"Work" shall mean the work of authorship, whether in Source or +Object form, made available under the License, as indicated by a copyright +notice that is included in or attached to the work (an example is provided +in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, +that is based on (or derived from) the Work and for which the editorial +revisions, annotations, elaborations, or other modifications represent, +as a whole, an original work of authorship. For the purposes of this +License, Derivative Works shall not include works that remain separable +from, or merely link (or bind by name) to the interfaces of, the Work +and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the +original version of the Work and any modifications or additions to +that Work or Derivative Works thereof, that is intentionally submitted +to Licensor for inclusion in the Work by the copyright owner or by an +individual or Legal Entity authorized to submit on behalf of the copyright +owner. For the purposes of this definition, "submitted" means any form of +electronic, verbal, or written communication sent to the Licensor or its +representatives, including but not limited to communication on electronic +mailing lists, source code control systems, and issue tracking systems +that are managed by, or on behalf of, the Licensor for the purpose of +discussing and improving the Work, but excluding communication that is +conspicuously marked or otherwise designated in writing by the copyright +owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity +on behalf of whom a Contribution has been received by Licensor and +subsequently incorporated within the Work. + +2. Grant of Copyright License. +Subject to the terms and conditions of this License, each Contributor +hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, +royalty-free, irrevocable copyright license to reproduce, prepare +Derivative Works of, publicly display, publicly perform, sublicense, and +distribute the Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. +Subject to the terms and conditions of this License, each Contributor +hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, +royalty- free, irrevocable (except as stated in this section) patent +license to make, have made, use, offer to sell, sell, import, and +otherwise transfer the Work, where such license applies only to those +patent claims licensable by such Contributor that are necessarily +infringed by their Contribution(s) alone or by combination of +their Contribution(s) with the Work to which such Contribution(s) +was submitted. If You institute patent litigation against any entity +(including a cross-claim or counterclaim in a lawsuit) alleging that the +Work or a Contribution incorporated within the Work constitutes direct +or contributory patent infringement, then any patent licenses granted +to You under this License for that Work shall terminate as of the date +such litigation is filed. + +4. Redistribution. +You may reproduce and distribute copies of the Work or Derivative Works +thereof in any medium, with or without modifications, and in Source or +Object form, provided that You meet the following conditions: + + a. You must give any other recipients of the Work or Derivative Works + a copy of this License; and + + b. You must cause any modified files to carry prominent notices stating + that You changed the files; and + + c. You must retain, in the Source form of any Derivative Works that + You distribute, all copyright, patent, trademark, and attribution + notices from the Source form of the Work, excluding those notices + that do not pertain to any part of the Derivative Works; and + + d. If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one of + the following places: within a NOTICE text file distributed as part + of the Derivative Works; within the Source form or documentation, + if provided along with the Derivative Works; or, within a display + generated by the Derivative Works, if and wherever such third-party + notices normally appear. The contents of the NOTICE file are for + informational purposes only and do not modify the License. You + may add Your own attribution notices within Derivative Works that + You distribute, alongside or as an addendum to the NOTICE text + from the Work, provided that such additional attribution notices + cannot be construed as modifying the License. You may add Your own + copyright statement to Your modifications and may provide additional + or different license terms and conditions for use, reproduction, or + distribution of Your modifications, or for any such Derivative Works + as a whole, provided Your use, reproduction, and distribution of the + Work otherwise complies with the conditions stated in this License. + +5. Submission of Contributions. +Unless You explicitly state otherwise, any Contribution intentionally +submitted for inclusion in the Work by You to the Licensor shall be +under the terms and conditions of this License, without any additional +terms or conditions. Notwithstanding the above, nothing herein shall +supersede or modify the terms of any separate license agreement you may +have executed with Licensor regarding such Contributions. + +6. Trademarks. +This License does not grant permission to use the trade names, trademarks, +service marks, or product names of the Licensor, except as required for +reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. +Unless required by applicable law or agreed to in writing, Licensor +provides the Work (and each Contributor provides its Contributions) on +an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +express or implied, including, without limitation, any warranties or +conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR +A PARTICULAR PURPOSE. You are solely responsible for determining the +appropriateness of using or redistributing the Work and assume any risks +associated with Your exercise of permissions under this License. + +8. Limitation of Liability. +In no event and under no legal theory, whether in tort (including +negligence), contract, or otherwise, unless required by applicable law +(such as deliberate and grossly negligent acts) or agreed to in writing, +shall any Contributor be liable to You for damages, including any direct, +indirect, special, incidental, or consequential damages of any character +arising as a result of this License or out of the use or inability to +use the Work (including but not limited to damages for loss of goodwill, +work stoppage, computer failure or malfunction, or any and all other +commercial damages or losses), even if such Contributor has been advised +of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. +While redistributing the Work or Derivative Works thereof, You may +choose to offer, and charge a fee for, acceptance of support, warranty, +indemnity, or other liability obligations and/or rights consistent with +this License. However, in accepting such obligations, You may act only +on Your own behalf and on Your sole responsibility, not on behalf of +any other Contributor, and only if You agree to indemnify, defend, and +hold each Contributor harmless for any liability incurred by, or claims +asserted against, such Contributor by reason of your accepting any such +warranty or additional liability. + +END OF TERMS AND CONDITIONS + + diff --git a/vendor/github.com/vmware-labs/yaml-jsonpath/NOTICE b/vendor/github.com/vmware-labs/yaml-jsonpath/NOTICE new file mode 100644 index 0000000000..055021a2dd --- /dev/null +++ b/vendor/github.com/vmware-labs/yaml-jsonpath/NOTICE @@ -0,0 +1,7 @@ +yaml-jsonpath +Copyright (c) 2020 VMware, Inc. All Rights Reserved. + +This product is licensed to you under the Apache 2.0 license (the "License"). You may not use this product except in compliance with the Apache 2.0 License. + +This product may include a number of subcomponents with separate copyright notices and license terms. Your use of these subcomponents is subject to the terms and conditions of the subcomponent's license, as noted in the LICENSE file. + diff --git a/vendor/github.com/vmware-labs/yaml-jsonpath/pkg/yamlpath/comparison.go b/vendor/github.com/vmware-labs/yaml-jsonpath/pkg/yamlpath/comparison.go new file mode 100644 index 0000000000..15cc38a0f7 --- /dev/null +++ b/vendor/github.com/vmware-labs/yaml-jsonpath/pkg/yamlpath/comparison.go @@ -0,0 +1,93 @@ +/* + * Copyright 2020 VMware, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package yamlpath + +import "strconv" + +type comparison int + +const ( + compareLessThan comparison = iota + compareEqual + compareGreaterThan + compareIncomparable +) + +type orderingOperator string + +const ( + operatorLessThan orderingOperator = "<" + operatorLessThanOrEqual orderingOperator = "<=" + operatorGreaterThan orderingOperator = ">" + operatorGreaterThanOrEqual orderingOperator = ">=" +) + +func (o orderingOperator) String() string { + return string(o) +} + +type comparator func(comparison) bool + +func equal(c comparison) bool { + return c == compareEqual +} + +func notEqual(c comparison) bool { + return c != compareEqual +} + +func greaterThan(c comparison) bool { + return c == compareGreaterThan +} + +func greaterThanOrEqual(c comparison) bool { + return c == compareGreaterThan || c == compareEqual +} + +func lessThan(c comparison) bool { + return c == compareLessThan +} + +func lessThanOrEqual(c comparison) bool { + return c == compareLessThan || c == compareEqual +} + +func compareStrings(a, b string) comparison { + if a == b { + return compareEqual + } + return compareIncomparable +} + +func compareFloat64(lhs, rhs float64) comparison { + if lhs < rhs { + return compareLessThan + } + if lhs > rhs { + return compareGreaterThan + } + return compareEqual +} + +// compareNodeValues compares two values each of which may be a string, integer, or float +func compareNodeValues(lhs, rhs typedValue) comparison { + if lhs.typ.isNumeric() && rhs.typ.isNumeric() { + return compareFloat64(mustParseFloat64(lhs.val), mustParseFloat64(rhs.val)) + } + if (lhs.typ != stringValueType && !lhs.typ.isNumeric()) || (rhs.typ != stringValueType && !rhs.typ.isNumeric()) { + panic("invalid type of value passed to compareNodeValues") // should never happen + } + return compareStrings(lhs.val, rhs.val) +} + +func mustParseFloat64(s string) float64 { + f, err := strconv.ParseFloat(s, 64) + if err != nil { + panic("invalid numeric value " + s) // should never happen + } + return f +} diff --git a/vendor/github.com/vmware-labs/yaml-jsonpath/pkg/yamlpath/doc.go b/vendor/github.com/vmware-labs/yaml-jsonpath/pkg/yamlpath/doc.go new file mode 100644 index 0000000000..bba7f27689 --- /dev/null +++ b/vendor/github.com/vmware-labs/yaml-jsonpath/pkg/yamlpath/doc.go @@ -0,0 +1,8 @@ +/* + * Copyright 2020 VMware, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +// Package yamlpath provides YAML node searching using path notation. +package yamlpath diff --git a/vendor/github.com/vmware-labs/yaml-jsonpath/pkg/yamlpath/filter.go b/vendor/github.com/vmware-labs/yaml-jsonpath/pkg/yamlpath/filter.go new file mode 100644 index 0000000000..dead1912bf --- /dev/null +++ b/vendor/github.com/vmware-labs/yaml-jsonpath/pkg/yamlpath/filter.go @@ -0,0 +1,297 @@ +/* + * Copyright 2020 VMware, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package yamlpath + +import ( + "fmt" + "regexp" + "strconv" + "strings" + + "gopkg.in/yaml.v3" +) + +type filter func(node, root *yaml.Node) bool + +func newFilter(n *filterNode) filter { + if n == nil { + return never + } + + switch n.lexeme.typ { + case lexemeFilterAt, lexemeRoot: + path := pathFilterScanner(n) + return func(node, root *yaml.Node) bool { + return len(path(node, root)) > 0 + } + + case lexemeFilterEquality, lexemeFilterInequality, + lexemeFilterGreaterThan, lexemeFilterGreaterThanOrEqual, + lexemeFilterLessThan, lexemeFilterLessThanOrEqual: + return comparisonFilter(n) + + case lexemeFilterMatchesRegularExpression: + return matchRegularExpression(n) + + case lexemeFilterNot: + f := newFilter(n.children[0]) + return func(node, root *yaml.Node) bool { + return !f(node, root) + } + + case lexemeFilterOr: + f1 := newFilter(n.children[0]) + f2 := newFilter(n.children[1]) + return func(node, root *yaml.Node) bool { + return f1(node, root) || f2(node, root) + } + + case lexemeFilterAnd: + f1 := newFilter(n.children[0]) + f2 := newFilter(n.children[1]) + return func(node, root *yaml.Node) bool { + return f1(node, root) && f2(node, root) + } + + case lexemeFilterBooleanLiteral: + b, err := strconv.ParseBool(n.lexeme.val) + if err != nil { + panic(err) // should not happen + } + return func(node, root *yaml.Node) bool { + return b + } + + default: + return never + } +} + +func never(node, root *yaml.Node) bool { + return false +} + +func comparisonFilter(n *filterNode) filter { + compare := func(b bool) bool { + var c comparison + if b { + c = compareEqual + } else { + c = compareIncomparable + } + return n.lexeme.comparator()(c) + } + return nodeToFilter(n, func(l, r typedValue) bool { + if !l.typ.compatibleWith(r.typ) { + return compare(false) + } + switch l.typ { + case booleanValueType: + return compare(equalBooleans(l.val, r.val)) + + case nullValueType: + return compare(equalNulls(l.val, r.val)) + + default: + return n.lexeme.comparator()(compareNodeValues(l, r)) + } + }) +} + +var x, y typedValue + +func init() { + x = typedValue{stringValueType, "x"} + y = typedValue{stringValueType, "y"} +} + +func nodeToFilter(n *filterNode, accept func(typedValue, typedValue) bool) filter { + lhsPath := newFilterScanner(n.children[0]) + rhsPath := newFilterScanner(n.children[1]) + return func(node, root *yaml.Node) (result bool) { + // perform a set-wise comparison of the values in each path + match := false + for _, l := range lhsPath(node, root) { + for _, r := range rhsPath(node, root) { + if !accept(l, r) { + return false + } + match = true + } + } + return match + } +} + +func equalBooleans(l, r string) bool { + // Note: the YAML parser and our JSONPath lexer both rule out invalid boolean literals such as tRue. + return strings.EqualFold(l, r) +} + +func equalNulls(l, r string) bool { + // Note: the YAML parser and our JSONPath lexer both rule out invalid null literals such as nUll. + return true +} + +// filterScanner is a function that returns a slice of typed values from either a filter literal or a path expression +// which refers to either the current node or the root node. It is used in filter comparisons. +type filterScanner func(node, root *yaml.Node) []typedValue + +func emptyScanner(*yaml.Node, *yaml.Node) []typedValue { + return []typedValue{} +} + +func newFilterScanner(n *filterNode) filterScanner { + switch { + case n == nil: + return emptyScanner + + case n.isItemFilter(): + return pathFilterScanner(n) + + case n.isLiteral(): + return literalFilterScanner(n) + + default: + return emptyScanner + } +} + +func pathFilterScanner(n *filterNode) filterScanner { + var at bool + switch n.lexeme.typ { + case lexemeFilterAt: + at = true + case lexemeRoot: + at = false + default: + panic("false precondition") + } + subpath := "" + for _, lexeme := range n.subpath { + subpath += lexeme.val + } + path, err := NewPath(subpath) + if err != nil { + return emptyScanner + } + return func(node, root *yaml.Node) []typedValue { + if at { + return values(path.Find(node)) + } + return values(path.Find(root)) + } +} + +type valueType int + +const ( + unknownValueType valueType = iota + stringValueType + intValueType + floatValueType + booleanValueType + nullValueType + regularExpressionValueType +) + +func (vt valueType) isNumeric() bool { + return vt == intValueType || vt == floatValueType +} + +func (vt valueType) compatibleWith(vt2 valueType) bool { + return vt.isNumeric() && vt2.isNumeric() || vt == vt2 || vt == stringValueType && vt2 == regularExpressionValueType +} + +type typedValue struct { + typ valueType + val string +} + +const ( + nullTag = "!!null" + boolTag = "!!bool" + strTag = "!!str" + intTag = "!!int" + floatTag = "!!float" +) + +func typedValueOfNode(node *yaml.Node) typedValue { + var t valueType = unknownValueType + if node.Kind == yaml.ScalarNode { + switch node.ShortTag() { + case nullTag: + t = nullValueType + + case boolTag: + t = booleanValueType + + case strTag: + t = stringValueType + + case intTag: + t = intValueType + + case floatTag: + t = floatValueType + } + } + + return typedValue{ + typ: t, + val: node.Value, + } +} + +func newTypedValue(t valueType, v string) typedValue { + return typedValue{ + typ: t, + val: v, + } +} + +func typedValueOfString(s string) typedValue { + return newTypedValue(stringValueType, s) +} + +func typedValueOfInt(i string) typedValue { + return newTypedValue(intValueType, i) +} + +func typedValueOfFloat(f string) typedValue { + return newTypedValue(floatValueType, f) +} + +func values(nodes []*yaml.Node, err error) []typedValue { + if err != nil { + panic(fmt.Errorf("unexpected error: %v", err)) // should never happen + } + v := []typedValue{} + for _, n := range nodes { + v = append(v, typedValueOfNode(n)) + } + return v +} + +func literalFilterScanner(n *filterNode) filterScanner { + v := n.lexeme.literalValue() + return func(node, root *yaml.Node) []typedValue { + return []typedValue{v} + } +} + +func matchRegularExpression(parseTree *filterNode) filter { + return nodeToFilter(parseTree, stringMatchesRegularExpression) +} + +func stringMatchesRegularExpression(s, expr typedValue) bool { + if s.typ != stringValueType || expr.typ != regularExpressionValueType { + return false // can't compare types so return false + } + re, _ := regexp.Compile(expr.val) // regex already compiled during lexing + return re.Match([]byte(s.val)) +} diff --git a/vendor/github.com/vmware-labs/yaml-jsonpath/pkg/yamlpath/filter_parser.go b/vendor/github.com/vmware-labs/yaml-jsonpath/pkg/yamlpath/filter_parser.go new file mode 100644 index 0000000000..48a1c7af57 --- /dev/null +++ b/vendor/github.com/vmware-labs/yaml-jsonpath/pkg/yamlpath/filter_parser.go @@ -0,0 +1,295 @@ +/* + * Copyright 2020 VMware, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package yamlpath + +/* + filterNode represents a node of a filter expression parse tree. Each node is labelled with a lexeme. + + Terminal nodes have one of the following lexemes: root, lexemeFilterAt, lexemeFilterIntegerLiteral, + lexemeFilterFloatLiteral, lexemeFilterStringLiteral, lexemeFilterBooleanLiteral. + root and lexemeFilterAt nodes also have a slice of lexemes representing the subpath of `$`` or `@``, + respectively. + + Non-terminal nodes represent either basic filters (simpler predicates of one or two terminal + nodes) or filter expressions (more complex predicates of basic filters). A filter existence expression + is represented as a terminal node with lexemeFilterAt or (less commonly) root. + + The following examples illustrate the approach. + + The basic filter `@.child > 3` is represented as the following parse tree (where each node is indicated by + its lexeme and `<...>` represents the node's children): + + lexemeFilterGreaterThan + + or, graphically: + + > + / \ + @.child 3 + + The filter expression `@.child > 3 && @.other` is represented as the parse tree: + + lexemeFilterConjunction,lexemeFilterAt> + + or, graphically: + + && + / \ + > @.other + / \ + @.child 3 + + The filter expression `(@.child < 5 || @.child > 10) && @.other == 'x'` is represented as the parse tree: + + lexemeFilterConjunction, + lexemeFilterGreaterThan + >, + lexemeFilterEquality + > + + or, graphically: + + && + / \ + || == + / \ / \ + < > @.other 'x' + / \ / \ + @.child 5 @.child 10 + + Note that brackets do not appear in the parse tree. +*/ +type filterNode struct { + lexeme lexeme + subpath []lexeme // empty unless lexeme is root or lexemeFilterAt + children []*filterNode +} + +func newFilterNode(lexemes []lexeme) *filterNode { + return newParser(lexemes).parse() +} + +func (n *filterNode) isItemFilter() bool { + return n.lexeme.typ == lexemeFilterAt || n.lexeme.typ == lexemeRoot +} + +func (n *filterNode) isLiteral() bool { + return n.isStringLiteral() || n.isBooleanLiteral() || n.isNullLiteral() || n.isNumericLiteral() || n.isRegularExpressionLiteral() +} + +func (n *filterNode) isStringLiteral() bool { + return n.lexeme.typ == lexemeFilterStringLiteral +} + +func (n *filterNode) isBooleanLiteral() bool { + return n.lexeme.typ == lexemeFilterBooleanLiteral +} + +func (n *filterNode) isNullLiteral() bool { + return n.lexeme.typ == lexemeFilterNullLiteral +} + +func (n *filterNode) isNumericLiteral() bool { + return n.lexeme.typ == lexemeFilterFloatLiteral || n.lexeme.typ == lexemeFilterIntegerLiteral +} + +func (n *filterNode) isRegularExpressionLiteral() bool { + return n.lexeme.typ == lexemeFilterRegularExpressionLiteral +} + +// parser holds the state of the filter expression parser. +type parser struct { + input []lexeme // the lexemes being scanned + pos int // current position in the input + stack []*filterNode // parser stack + tree *filterNode // parse tree +} + +// newParser creates a new parser for the input slice of lexemes. +func newParser(input []lexeme) *parser { + l := &parser{ + input: input, + stack: make([]*filterNode, 0), + } + return l +} + +// push pushes a parse tree on the stack. +func (p *parser) push(tree *filterNode) { + p.stack = append(p.stack, tree) +} + +// pop pops a parse tree from the stack, which must be non-empty. +func (p *parser) pop() *filterNode { + index := len(p.stack) - 1 + element := p.stack[index] + p.stack = p.stack[:index] + return element +} + +// nextLexeme returns the next item from the input. +// The caller must peek to ensure there is more input before calling nextLexeme. +func (p *parser) nextLexeme() lexeme { + next := p.input[p.pos] + p.pos++ + return next +} + +// peek returns the next item from the input without consuming the item. +func (p *parser) peek() lexeme { + if p.pos >= len(p.input) { + return lexeme{lexemeEOF, ""} + } + return p.input[p.pos] +} + +func (p *parser) parse() *filterNode { + if p.peek().typ == lexemeEOF { + return nil + } + p.expression() + return p.tree +} + +func (p *parser) expression() { + p.conjunction() + for p.peek().typ == lexemeFilterOr { + p.push(p.tree) + p.or() + } +} + +func (p *parser) or() { + n := p.nextLexeme() + p.conjunction() + p.tree = &filterNode{ + lexeme: n, + subpath: []lexeme{}, + children: []*filterNode{ + p.pop(), + p.tree, + }, + } +} + +func (p *parser) conjunction() { + p.basicFilter() + for p.peek().typ == lexemeFilterAnd { + p.push(p.tree) + p.and() + } +} + +func (p *parser) and() { + n := p.nextLexeme() + p.basicFilter() + p.tree = &filterNode{ + lexeme: n, + subpath: []lexeme{}, + children: []*filterNode{ + p.pop(), + p.tree, + }, + } +} + +// basicFilter consumes then next basic filter and sets it as the parser's tree. If a basic filter it not next, nil is set. +func (p *parser) basicFilter() { + n := p.peek() + switch n.typ { + case lexemeFilterNot: + p.nextLexeme() + p.basicFilter() + p.tree = &filterNode{ + lexeme: n, + subpath: []lexeme{}, + children: []*filterNode{ + p.tree, + }, + } + return + + case lexemeFilterOpenBracket: + p.nextLexeme() + p.expression() + if p.peek().typ == lexemeFilterCloseBracket { + p.nextLexeme() + } + return + } + + p.filterTerm() + n = p.peek() + if n.typ.isComparisonOrMatch() { + p.nextLexeme() + filterTerm := p.tree + p.filterTerm() + p.tree = &filterNode{ + lexeme: n, + subpath: []lexeme{}, + children: []*filterNode{ + filterTerm, + p.tree, + }, + } + } +} + +// filterTerm consumes the next filter term and sets it as the parser's tree. If a filter term is not next, nil is set. +func (p *parser) filterTerm() { + n := p.peek() + switch n.typ { + case lexemeEOF, lexemeError: + p.tree = nil + + case lexemeFilterAt, lexemeRoot: + p.nextLexeme() + subpath := []lexeme{} + filterNestingLevel := 1 + f: + for { + s := p.peek() + switch s.typ { + case lexemeIdentity, lexemeDotChild, lexemeBracketChild, lexemeRecursiveDescent, lexemeArraySubscript: + + case lexemeFilterBegin: + filterNestingLevel++ + + case lexemeFilterEnd: + filterNestingLevel-- + if filterNestingLevel == 0 { + break f + } + + case lexemeEOF: + break f + + default: + // allow any other lexemes only in a nested filter + if filterNestingLevel == 1 { + break f + } + } + subpath = append(subpath, s) + p.nextLexeme() + } + p.tree = &filterNode{ + lexeme: n, + subpath: subpath, + children: []*filterNode{}, + } + + case lexemeFilterIntegerLiteral, lexemeFilterFloatLiteral, lexemeFilterStringLiteral, lexemeFilterBooleanLiteral, + lexemeFilterNullLiteral, lexemeFilterRegularExpressionLiteral: + p.nextLexeme() + p.tree = &filterNode{ + lexeme: n, + subpath: []lexeme{}, + children: []*filterNode{}, + } + } +} diff --git a/vendor/github.com/vmware-labs/yaml-jsonpath/pkg/yamlpath/lexer.go b/vendor/github.com/vmware-labs/yaml-jsonpath/pkg/yamlpath/lexer.go new file mode 100644 index 0000000000..67fe197a30 --- /dev/null +++ b/vendor/github.com/vmware-labs/yaml-jsonpath/pkg/yamlpath/lexer.go @@ -0,0 +1,1011 @@ +/* + * Copyright 2020 VMware, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package yamlpath + +import ( + "fmt" + "regexp" + "strconv" + "strings" + "unicode" + "unicode/utf8" +) + +// This lexer was based on Rob Pike's talk "Lexical Scanning in Go" (https://talks.golang.org/2011/lex.slide#1) + +type lexemeType int + +const ( + lexemeError lexemeType = iota + lexemeIdentity + lexemeRoot + lexemeDotChild + lexemeUndottedChild + lexemeBracketChild + lexemeRecursiveDescent + lexemeArraySubscript + lexemeFilterBegin + lexemeFilterEnd + lexemeFilterOpenBracket + lexemeFilterCloseBracket + lexemeFilterNot + lexemeFilterAt + lexemeFilterAnd + lexemeFilterOr + lexemeFilterEquality + lexemeFilterInequality + lexemeFilterGreaterThan + lexemeFilterGreaterThanOrEqual + lexemeFilterLessThanOrEqual + lexemeFilterLessThan + lexemeFilterMatchesRegularExpression + lexemeFilterIntegerLiteral + lexemeFilterFloatLiteral + lexemeFilterStringLiteral + lexemeFilterBooleanLiteral + lexemeFilterNullLiteral + lexemeFilterRegularExpressionLiteral + lexemePropertyName + lexemeBracketPropertyName + lexemeArraySubscriptPropertyName + lexemeRecursiveFilterBegin + lexemeEOF // lexing complete +) + +func (t lexemeType) comparator() comparator { + switch t { + case lexemeFilterEquality: + return equal + + case lexemeFilterInequality: + return notEqual + + case lexemeFilterGreaterThan: + return greaterThan + + case lexemeFilterGreaterThanOrEqual: + return greaterThanOrEqual + + case lexemeFilterLessThan: + return lessThan + + case lexemeFilterLessThanOrEqual: + return lessThanOrEqual + + default: + panic(fmt.Sprintf("invalid comparator %d", t)) // should never happen + } +} + +func (t lexemeType) isComparisonOrMatch() bool { + switch t { + case lexemeFilterEquality, lexemeFilterInequality, + lexemeFilterGreaterThan, lexemeFilterGreaterThanOrEqual, + lexemeFilterLessThan, lexemeFilterLessThanOrEqual, + lexemeFilterMatchesRegularExpression: + return true + } + return false +} + +// a lexeme is a token returned from the lexer +type lexeme struct { + typ lexemeType + val string // original lexeme or error message if typ is lexemeError +} + +func (l lexeme) literalValue() typedValue { + switch l.typ { + case lexemeFilterIntegerLiteral: + return typedValue{ + typ: intValueType, + val: l.val, + } + + case lexemeFilterFloatLiteral: + return typedValue{ + typ: floatValueType, + val: l.val, + } + + case lexemeFilterStringLiteral: + return typedValue{ + typ: stringValueType, + val: l.val[1 : len(l.val)-1], + } + + case lexemeFilterBooleanLiteral: + return typedValue{ + typ: booleanValueType, + val: l.val, + } + + case lexemeFilterNullLiteral: + return typedValue{ + typ: nullValueType, + val: l.val, + } + + case lexemeFilterRegularExpressionLiteral: + return typedValue{ + typ: regularExpressionValueType, + val: sanitiseRegularExpressionLiteral(l.val), + } + + default: + return typedValue{ + typ: unknownValueType, + val: l.val, + } + } +} + +func sanitiseRegularExpressionLiteral(re string) string { + return strings.ReplaceAll(re[1:len(re)-1], `\/`, `/`) +} + +func (l lexeme) comparator() comparator { + return l.typ.comparator() +} + +// stateFn represents the state of the lexer as a function that returns the next state. +// A nil stateFn indicates lexing is complete. +type stateFn func(*lexer) stateFn + +// lexer holds the state of the scanner. +type lexer struct { + name string // name of the lexer, used only for error reports + input string // the string being scanned + start int // start position of this item + pos int // current position in the input + width int // width of last rune read from input + state stateFn // lexer state + stack []stateFn // lexer stack + items chan lexeme // channel of scanned lexemes + lastEmittedStart int // start position of last scanned lexeme + lastEmittedLexemeType lexemeType // type of last emitted lexeme (or lexemEOF if no lexeme has been emitted) +} + +// lex creates a new scanner for the input string. +func lex(name, input string) *lexer { + l := &lexer{ + name: name, + input: input, + state: lexPath, + stack: make([]stateFn, 0), + items: make(chan lexeme, 2), + lastEmittedLexemeType: lexemeEOF, + } + return l +} + +// push pushes a state function on the stack which will be resumed when parsing terminates. +func (l *lexer) push(state stateFn) { + l.stack = append(l.stack, state) +} + +// pop pops a state function from the stack. If the stack is empty, returns an error function. +func (l *lexer) pop() stateFn { + if len(l.stack) == 0 { + return l.errorf("syntax error") + } + index := len(l.stack) - 1 + element := l.stack[index] + l.stack = l.stack[:index] + return element +} + +// empty returns true if and onl if the stack of state functions is empty. +func (l *lexer) emptyStack() bool { + return len(l.stack) == 0 +} + +// nextLexeme returns the next item from the input. +func (l *lexer) nextLexeme() lexeme { + for { + select { + case item := <-l.items: + return item + default: + if l.state == nil { + return lexeme{ + typ: lexemeEOF, + } + } + l.state = l.state(l) + } + } +} + +const eof rune = -1 // invalid Unicode code point + +// next returns the next rune in the input. +func (l *lexer) next() (rune rune) { + if l.pos >= len(l.input) { + l.width = 0 + return eof + } + rune, l.width = utf8.DecodeRuneInString(l.input[l.pos:]) + l.pos += l.width + return rune +} + +// consume consumes as many runes as there are in the given string +func (l *lexer) consume(s string) { + for range s { + l.next() + } +} + +// consumed checks the input to see if it starts with the given token and does +// not start with any of the given exceptions. If so, it consumes the given +// token and returns true. Otherwise, it returns false. +func (l *lexer) consumed(token string, except ...string) bool { + if l.hasPrefix(token) { + for _, e := range except { + if l.hasPrefix(e) { + return false + } + } + l.consume(token) + return true + } + return false +} + +// consumedWhitespaces checks the input to see if, after whitespace is removed, it +// starts with the given tokens. If so, it consumes the given +// tokens and any whitespace and returns true. Otherwise, it returns false. +func (l *lexer) consumedWhitespaced(tokens ...string) bool { + pos := l.pos + for _, token := range tokens { + // skip past whitespace + for { + if pos >= len(l.input) { + return false + } + rune, width := utf8.DecodeRuneInString(l.input[pos:]) + if !unicode.IsSpace(rune) { + break + } + pos += width + } + if !strings.HasPrefix(l.input[pos:], token) { + return false + } + pos += len(token) + } + l.pos = pos + return true +} + +// consumeWhitespace consumes any leading whitespace. +func (l *lexer) consumeWhitespace() { + pos := l.pos + for { + if pos >= len(l.input) { + break + } + rune, width := utf8.DecodeRuneInString(l.input[pos:]) + if !unicode.IsSpace(rune) { + break + } + pos += width + } + l.pos = pos +} + +// peek returns the next rune in the input but without consuming it. +// it is equivalent to calling next() followed by backup() +func (l *lexer) peek() (rune rune) { + if l.pos >= len(l.input) { + l.width = 0 + return eof + } + rune, l.width = utf8.DecodeRuneInString(l.input[l.pos:]) + return rune +} + +// peeked checks the input to see if it starts with the given token and does +// not start with any of the given exceptions. If so, it returns true. +// Otherwise, it returns false. +func (l *lexer) peeked(token string, except ...string) bool { + if l.hasPrefix(token) { + for _, e := range except { + if l.hasPrefix(e) { + return false + } + } + return true + } + return false +} + +// peekedWhitespaces checks the input to see if, after whitespace is removed, it +// starts with the given tokens. If so, it returns true. Otherwise, it returns false. +func (l *lexer) peekedWhitespaced(tokens ...string) bool { + pos := l.pos + for _, token := range tokens { + // skip past whitespace + for { + if pos >= len(l.input) { + return false + } + rune, width := utf8.DecodeRuneInString(l.input[pos:]) + if !unicode.IsSpace(rune) { + break + } + pos += width + } + if !strings.HasPrefix(l.input[pos:], token) { + return false + } + pos += len(token) + } + return true +} + +// backup steps back one rune. +// Can be called only once per call of next. +func (l *lexer) backup() { + l.pos -= l.width +} + +// stripWhitespace strips out whitespace +// it should only be called immediately after emitting a lexeme +func (l *lexer) stripWhitespace() { + // find whitespace + for { + nextRune := l.next() + if !unicode.IsSpace(nextRune) { + l.backup() + break + } + } + // strip any whitespace + l.start = l.pos +} + +// emit passes a lexeme back to the client. +func (l *lexer) emit(typ lexemeType) { + l.items <- lexeme{ + typ: typ, + val: l.value(), + } + l.lastEmittedStart = l.start + l.start = l.pos + l.lastEmittedLexemeType = typ +} + +// value returns the portion of the current lexeme scanned so far +func (l *lexer) value() string { + return l.input[l.start:l.pos] +} + +// context returns the last emitted lexeme (if any) followed by the portion +// of the current lexeme scanned so far +func (l *lexer) context() string { + return l.input[l.lastEmittedStart:l.pos] +} + +// emitSynthetic passes a lexeme back to the client which wasn't encountered in the input. +// The lexing position is not modified. +func (l *lexer) emitSynthetic(typ lexemeType, val string) { + l.items <- lexeme{ + typ: typ, + val: val, + } +} + +func (l *lexer) empty() bool { + return l.pos >= len(l.input) +} + +func (l *lexer) hasPrefix(p string) bool { + return strings.HasPrefix(l.input[l.pos:], p) +} + +// errorf returns an error lexeme with context and terminates the scan +func (l *lexer) errorf(format string, args ...interface{}) stateFn { + l.items <- lexeme{ + typ: lexemeError, + val: fmt.Sprintf("%s at position %d, following %q", fmt.Sprintf(format, args...), l.pos, l.context()), + } + return nil +} + +// rawErrorf returns an error lexeme with no context and terminates the scan +func (l *lexer) rawErrorf(format string, args ...interface{}) stateFn { + l.items <- lexeme{ + typ: lexemeError, + val: fmt.Sprintf(format, args...), + } + return nil +} + +const ( + root string = "$" + dot string = "." + leftBracket string = "[" + rightBracket string = "]" + bracketQuote string = "['" + bracketDoubleQuote string = `["` + filterBegin string = "[?(" + filterEnd string = ")]" + filterOpenBracket string = "(" + filterCloseBracket string = ")" + filterNot string = "!" + filterAt string = "@" + filterConjunction string = "&&" + filterDisjunction string = "||" + filterEquality string = "==" + filterInequality string = "!=" + filterMatchesRegularExpression string = "=~" + filterStringLiteralDelimiter string = "'" + filterStringLiteralAlternateDelimiter string = `"` + filterRegularExpressionLiteralDelimiter string = "/" + filterRegularExpressionEscape string = `\` + recursiveDescent string = ".." + propertyName string = "~" +) + +var orderingOperators []orderingOperator + +func init() { + // list the ordering operators in an order suitable for lexing + orderingOperators = []orderingOperator{ + operatorGreaterThanOrEqual, + operatorGreaterThan, + operatorLessThanOrEqual, + operatorLessThan, + } +} + +func lexPath(l *lexer) stateFn { + if l.empty() { + l.emit(lexemeIdentity) + l.emit(lexemeEOF) + return nil + } + if l.hasPrefix(root) { + return lexRoot + } + + // emit implicit root + l.emitSynthetic(lexemeRoot, root) + return lexSubPath +} + +func lexRoot(l *lexer) stateFn { + l.pos += len(root) + l.emit(lexemeRoot) + return lexSubPath +} + +// consumedEscapedString consumes a string with the given string validly escaped using "\" and returns +// true if and only if such a string was consumed. +func consumedEscapedString(l *lexer, quote string) bool { + for { + switch { + case l.peeked(quote): // unescaped quote + return true + case l.consumed(`\` + quote): + case l.consumed(`\\`): + case l.peeked(`\`): + l.errorf("unsupported escape sequence inside %s%s", quote, quote) + return false + default: + if l.next() == eof { + l.errorf("unmatched %s", enquote(quote)) + return false + } + } + } +} + +func lexSubPath(l *lexer) stateFn { + switch { + case l.hasPrefix(")"): + return l.pop() + + case l.empty(): + if !l.emptyStack() { + return l.pop() + } + l.emit(lexemeIdentity) + l.emit(lexemeEOF) + return nil + + case l.consumed(recursiveDescent): + childName := false + for { + le := l.next() + if le == '.' || le == '[' || le == eof { + l.backup() + break + } + childName = true + } + if !childName && !l.peeked(leftBracket, bracketQuote, bracketDoubleQuote) { + return l.errorf("child name or array access or filter missing after recursive descent") + } + l.emit(lexemeRecursiveDescent) + return lexSubPath + + case l.consumed(dot): + childName := false + for { + le := l.next() + if le == '.' || le == '[' || le == ')' || le == ' ' || le == '&' || le == '|' || le == '=' || le == '!' || le == '>' || le == '<' || le == '~' || le == eof { + l.backup() + break + } + childName = true + } + if !childName { + return l.errorf("child name missing") + } + if l.consumed(propertyName) { + if l.peek() != eof { + return l.errorf("property name operator may only be used on last child in path") + } + l.emit(lexemePropertyName) + return lexSubPath + } + + l.emit(lexemeDotChild) + + return lexOptionalArrayIndex + + case l.peekedWhitespaced("[", "'") || l.peekedWhitespaced("[", `"`): // bracketQuote or bracketDoubleQuote + l.consumedWhitespaced("[") + for { + l.consumeWhitespace() + quote := string(l.next()) + + if !consumedEscapedString(l, quote) { + return nil + } + if !l.consumed(quote) { + return l.errorf(`missing %s`, enquote(quote)) + } + if l.consumedWhitespaced(",") { + if !l.peekedWhitespaced("'") && !l.peekedWhitespaced(`"`) { + return l.errorf(`missing %s or %s`, enquote("'"), enquote(`"`)) + } + } else { + break + } + } + if !l.consumedWhitespaced("]") { + return l.errorf(`missing "]" or ","`) + } + if l.consumed(propertyName) { + l.emit(lexemeBracketPropertyName) + if l.peek() != eof { + return l.errorf("property name operator may only be used on last child in path") + } + return lexSubPath + } + + l.emit(lexemeBracketChild) + + return lexOptionalArrayIndex + + case l.consumed(filterBegin): + if l.lastEmittedLexemeType == lexemeRecursiveDescent { + l.emit(lexemeRecursiveFilterBegin) + } else { + l.emit(lexemeFilterBegin) + } + l.push(lexFilterEnd) + return lexFilterExprInitial + + case l.peeked(leftBracket): + return lexOptionalArrayIndex + + case l.lastEmittedLexemeType == lexemeEOF: + childName := false + for { + le := l.next() + if le == '.' || le == '[' || le == ']' || le == ')' || le == ' ' || le == '&' || le == '|' || le == '=' || le == '!' || le == '>' || le == '<' || le == '~' || le == eof { + l.backup() + break + } + childName = true + } + if !childName { + return l.errorf("child name missing") + } + if l.consumed(propertyName) { + if l.peek() != eof { + return l.errorf("property name operator may only be used on last child in path") + } + l.emit(lexemePropertyName) + return lexSubPath + } + l.emit(lexemeUndottedChild) + + return lexOptionalArrayIndex + + default: + return l.errorf("invalid path syntax") + } +} + +func lexOptionalArrayIndex(l *lexer) stateFn { + if l.consumed(leftBracket, bracketQuote, bracketDoubleQuote, filterBegin) { + subscript := false + for { + if l.consumed(rightBracket) { + break + } + if l.next() == eof { + return l.errorf("unmatched %s", leftBracket) + } + subscript = true + } + if !subscript { + return l.rawErrorf("subscript missing from %s%s before position %d", leftBracket, rightBracket, l.pos) + } + if !validateArrayIndex(l) { + return nil + } + if l.consumed(propertyName) { + if l.peek() != eof { + return l.errorf("property name operator can only be used on last item in path") + } + subscript := l.value() + index := strings.TrimSuffix(strings.TrimPrefix(subscript, leftBracket), rightBracket+propertyName) + if index != "*" { + return l.errorf("property name operator can only be used on map nodes") + } + l.emit(lexemeArraySubscriptPropertyName) + return lexSubPath + + } + l.emit(lexemeArraySubscript) + } + + le := l.peek() + if le == ' ' || le == '&' || le == '|' || le == '=' || le == '!' || le == '>' || le == '<' { + if l.emptyStack() { + return l.errorf("invalid character %q", l.peek()) + } + return l.pop() + } + + return lexSubPath +} + +func enquote(quote string) string { + switch quote { + case "'": + return `"'"` + + case `"`: + return `'"'` + + default: + panic(fmt.Sprintf(`enquote called with incorrect argument %q`, quote)) + } +} + +func lexFilterExprInitial(l *lexer) stateFn { + l.stripWhitespace() + + if nextState, present := lexNumericLiteral(l, lexFilterExpr); present { + return nextState + } + + if nextState, present := lexStringLiteral(l, lexFilterExpr); present { + return nextState + } + + if nextState, present := lexBooleanLiteral(l, lexFilterExpr); present { + return nextState + } + + if nextState, present := lexNullLiteral(l, lexFilterExpr); present { + return nextState + } + + switch { + case l.consumed(filterOpenBracket): + l.emit(lexemeFilterOpenBracket) + l.push(lexFilterExpr) + return lexFilterExprInitial + + case l.hasPrefix(filterInequality): + return l.errorf("missing first operand for binary operator !=") + + case l.consumed(filterNot): + l.emit(lexemeFilterNot) + return lexFilterExprInitial + + case l.consumed(filterAt): + l.emit(lexemeFilterAt) + if l.peekedWhitespaced("=") || l.peekedWhitespaced("!") || l.peekedWhitespaced(">") || l.peekedWhitespaced("<") { + return lexFilterExpr + } + l.push(lexFilterExpr) + return lexSubPath + + case l.consumed(root): + l.emit(lexemeRoot) + l.push(lexFilterExpr) + return lexSubPath + + case l.hasPrefix(filterConjunction): + return l.errorf("missing first operand for binary operator &&") + + case l.hasPrefix(filterDisjunction): + return l.errorf("missing first operand for binary operator ||") + + case l.hasPrefix(filterEquality): + return l.errorf("missing first operand for binary operator ==") + } + + for _, o := range orderingOperators { + if l.hasPrefix(o.String()) { + return l.errorf("missing first operand for binary operator %s", o) + } + } + + return l.pop() +} + +func lexFilterExpr(l *lexer) stateFn { + l.stripWhitespace() + + switch { + case l.empty(): + return l.errorf("missing end of filter") + + case l.hasPrefix(filterEnd): // this will be consumed by the popped state function + return l.pop() + + case l.consumed(filterCloseBracket): + l.emit(lexemeFilterCloseBracket) + return l.pop() + + case l.consumed(filterConjunction): + l.emit(lexemeFilterAnd) + l.stripWhitespace() + return lexFilterExprInitial + + case l.consumed(filterDisjunction): + l.emit(lexemeFilterOr) + l.stripWhitespace() + return lexFilterExprInitial + + case l.consumed(filterEquality): + l.emit(lexemeFilterEquality) + l.push(lexFilterExpr) + return lexFilterTerm + + case l.consumed(filterInequality): + l.emit(lexemeFilterInequality) + l.push(lexFilterExpr) + return lexFilterTerm + + case l.hasPrefix(filterMatchesRegularExpression): + switch l.lastEmittedLexemeType { + case lexemeFilterStringLiteral, lexemeFilterIntegerLiteral, lexemeFilterFloatLiteral: + return l.errorf("literal cannot be matched using %s", filterMatchesRegularExpression) + } + l.consume(filterMatchesRegularExpression) + l.emit(lexemeFilterMatchesRegularExpression) + + l.stripWhitespace() + return lexRegularExpressionLiteral(l, lexFilterExpr) + } + + for _, o := range orderingOperators { + if l.hasPrefix(o.String()) { + return lexComparison(l, o) + } + } + + return l.errorf("invalid filter expression") +} + +func lexFilterTerm(l *lexer) stateFn { + l.stripWhitespace() + + if l.consumed(filterAt) { + l.emit(lexemeFilterAt) + + if l.peekedWhitespaced("|") || l.peekedWhitespaced("&") || l.peekedWhitespaced(")") { + if l.emptyStack() { + return l.errorf("invalid character %q", l.peek()) + } + return l.pop() + } + return lexSubPath + } + + if l.consumed(root) { + l.emit(lexemeRoot) + return lexSubPath + } + + if nextState, present := lexNumericLiteral(l, lexFilterExpr); present { + return nextState + } + + if nextState, present := lexStringLiteral(l, lexFilterExpr); present { + return nextState + } + + if nextState, present := lexBooleanLiteral(l, lexFilterExpr); present { + return nextState + } + + if nextState, present := lexNullLiteral(l, lexFilterExpr); present { + return nextState + } + + return l.errorf("invalid filter term") +} + +func lexFilterEnd(l *lexer) stateFn { + if l.hasPrefix(filterEnd) { + if l.lastEmittedLexemeType == lexemeFilterBegin { + return l.errorf("missing filter") + } + l.consume(filterEnd) + l.emit(lexemeFilterEnd) + return lexSubPath + } + + return l.errorf("invalid filter syntax") +} + +func validateArrayIndex(l *lexer) bool { + subscript := l.value() + index := strings.TrimSuffix(strings.TrimPrefix(subscript, leftBracket), rightBracket) + if _, err := slice(index, 0); err != nil { + l.rawErrorf("invalid array index %s before position %d: %s", subscript, l.pos, err) + return false + } + return true +} + +func lexNumericLiteral(l *lexer, nextState stateFn) (stateFn, bool) { + n := l.peek() + if n == '.' || n == '-' || (n >= '0' && n <= '9') { + float := n == '.' + for { + l.next() + n := l.peek() + if n == '.' || n == 'e' || n == 'E' || n == '-' { + float = true + continue + } + if !(n >= '0' && n <= '9') { + break + } + } + + if float { + // validate float + if _, err := strconv.ParseFloat(l.value(), 64); err != nil { + err := err.(*strconv.NumError) + return l.rawErrorf("invalid float literal %q: %s before position %d", err.Num, err, l.pos), true + } + l.emit(lexemeFilterFloatLiteral) + return lexFilterExpr, true + } + // validate integer + if _, err := strconv.Atoi(l.value()); err != nil { + err := err.(*strconv.NumError) + return l.rawErrorf("invalid integer literal %q: %s before position %d", err.Num, err, l.pos), true + } + l.emit(lexemeFilterIntegerLiteral) + return lexFilterExpr, true + } + return nil, false +} + +func lexStringLiteral(l *lexer, nextState stateFn) (stateFn, bool) { + var quote string + if l.hasPrefix(filterStringLiteralDelimiter) { + quote = filterStringLiteralDelimiter + } else if l.hasPrefix(filterStringLiteralAlternateDelimiter) { + quote = filterStringLiteralAlternateDelimiter + } + if quote != "" { + pos := l.pos + context := l.context() + for { + if l.next() == eof { + return l.rawErrorf(`unmatched string delimiter %s at position %d, following %q`, quote, pos, context), true + } + if l.hasPrefix(quote) { + break + } + } + l.next() + l.emit(lexemeFilterStringLiteral) + + return nextState, true + } + return nil, false +} + +func lexBooleanLiteral(l *lexer, nextState stateFn) (stateFn, bool) { + if l.consumedWhitespaced("true") || l.consumedWhitespaced("false") { + l.emit(lexemeFilterBooleanLiteral) + return nextState, true + } + return nil, false +} + +func lexNullLiteral(l *lexer, nextState stateFn) (stateFn, bool) { + if l.consumedWhitespaced("null") { + l.emit(lexemeFilterNullLiteral) + return nextState, true + } + return nil, false +} + +var comparisonOperatorLexeme map[orderingOperator]lexemeType + +func init() { + comparisonOperatorLexeme = map[orderingOperator]lexemeType{ + operatorGreaterThan: lexemeFilterGreaterThan, + operatorGreaterThanOrEqual: lexemeFilterGreaterThanOrEqual, + operatorLessThan: lexemeFilterLessThan, + operatorLessThanOrEqual: lexemeFilterLessThanOrEqual, + } +} + +func lexComparison(l *lexer, comparisonOperator orderingOperator) stateFn { + if l.lastEmittedLexemeType == lexemeFilterStringLiteral { + return l.errorf("strings cannot be compared using %s", comparisonOperator) + } + l.consume(comparisonOperator.String()) + l.emit(comparisonOperatorLexeme[comparisonOperator]) + + l.stripWhitespace() + if l.hasPrefix(filterStringLiteralDelimiter) { + return l.errorf("strings cannot be compared using %s", comparisonOperator) + } + + l.push(lexFilterExpr) + return lexFilterTerm +} + +func lexRegularExpressionLiteral(l *lexer, nextState stateFn) stateFn { + if !l.hasPrefix(filterRegularExpressionLiteralDelimiter) { + return l.errorf("regular expression does not start with %s", filterRegularExpressionLiteralDelimiter) + } + pos := l.pos + context := l.context() + escape := false + for { + if l.next() == eof { + return l.rawErrorf(`unmatched regular expression delimiter %s at position %d, following %q`, filterRegularExpressionLiteralDelimiter, pos, context) + } + if !escape && l.hasPrefix(filterRegularExpressionLiteralDelimiter) { + break + } + if !escape && l.hasPrefix(filterRegularExpressionEscape) { + escape = true + } else { + escape = false + } + } + l.next() + if _, err := regexp.Compile(sanitiseRegularExpressionLiteral(l.value())); err != nil { + return l.rawErrorf(`invalid regular expression at position %d, following %q: %s`, pos, context, err) + } + l.emit(lexemeFilterRegularExpressionLiteral) + + return nextState +} diff --git a/vendor/github.com/vmware-labs/yaml-jsonpath/pkg/yamlpath/path.go b/vendor/github.com/vmware-labs/yaml-jsonpath/pkg/yamlpath/path.go new file mode 100644 index 0000000000..fb0fd0219a --- /dev/null +++ b/vendor/github.com/vmware-labs/yaml-jsonpath/pkg/yamlpath/path.go @@ -0,0 +1,463 @@ +/* + * Copyright 2020 VMware, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package yamlpath + +import ( + "errors" + "strings" + "unicode/utf8" + + "github.com/dprotaso/go-yit" + "gopkg.in/yaml.v3" +) + +// Path is a compiled YAML path expression. +type Path struct { + f func(node, root *yaml.Node) yit.Iterator +} + +// Find applies the Path to a YAML node and returns the addresses of the subnodes which match the Path. +func (p *Path) Find(node *yaml.Node) ([]*yaml.Node, error) { + return p.find(node, node), nil // currently, errors are not possible +} + +func (p *Path) find(node, root *yaml.Node) []*yaml.Node { + return p.f(node, root).ToArray() +} + +// NewPath constructs a Path from a string expression. +func NewPath(path string) (*Path, error) { + return newPath(lex("Path lexer", path)) +} + +func newPath(l *lexer) (*Path, error) { + lx := l.nextLexeme() + + switch lx.typ { + + case lexemeError: + return nil, errors.New(lx.val) + + case lexemeIdentity, lexemeEOF: + return new(identity), nil + + case lexemeRoot: + subPath, err := newPath(l) + if err != nil { + return nil, err + } + return new(func(node, root *yaml.Node) yit.Iterator { + if node.Kind == yaml.DocumentNode { + node = node.Content[0] + } + return compose(yit.FromNode(node), subPath, root) + }), nil + + case lexemeRecursiveDescent: + subPath, err := newPath(l) + if err != nil { + return nil, err + } + childName := strings.TrimPrefix(lx.val, "..") + switch childName { + case "*": + // includes all nodes, not just mapping nodes + return new(func(node, root *yaml.Node) yit.Iterator { + return compose(yit.FromNode(node).RecurseNodes(), allChildrenThen(subPath), root) + }), nil + + case "": + return new(func(node, root *yaml.Node) yit.Iterator { + return compose(yit.FromNode(node).RecurseNodes(), subPath, root) + }), nil + + default: + return new(func(node, root *yaml.Node) yit.Iterator { + return compose(yit.FromNode(node).RecurseNodes(), childThen(childName, subPath), root) + }), nil + } + + case lexemeDotChild: + subPath, err := newPath(l) + if err != nil { + return nil, err + } + childName := strings.TrimPrefix(lx.val, ".") + + return childThen(childName, subPath), nil + + case lexemeUndottedChild: + subPath, err := newPath(l) + if err != nil { + return nil, err + } + + return childThen(lx.val, subPath), nil + + case lexemeBracketChild: + subPath, err := newPath(l) + if err != nil { + return nil, err + } + childNames := strings.TrimSpace(lx.val) + childNames = strings.TrimSuffix(strings.TrimPrefix(childNames, "["), "]") + childNames = strings.TrimSpace(childNames) + return bracketChildThen(childNames, subPath), nil + + case lexemeArraySubscript: + subPath, err := newPath(l) + if err != nil { + return nil, err + } + subscript := strings.TrimSuffix(strings.TrimPrefix(lx.val, "["), "]") + return arraySubscriptThen(subscript, subPath), nil + + case lexemeFilterBegin, lexemeRecursiveFilterBegin: + var recursive bool + + if lx.typ == lexemeRecursiveFilterBegin { + recursive = true + } + filterLexemes := []lexeme{} + filterNestingLevel := 1 + f: + for { + lx := l.nextLexeme() + switch lx.typ { + case lexemeFilterBegin: + filterNestingLevel++ + case lexemeFilterEnd: + filterNestingLevel-- + if filterNestingLevel == 0 { + break f + } + case lexemeError: + return nil, errors.New(lx.val) + + case lexemeEOF: + // should never happen as lexer should have detected an error + return nil, errors.New("missing end of filter") + } + filterLexemes = append(filterLexemes, lx) + } + + subPath, err := newPath(l) + if err != nil { + return nil, err + } + if recursive { + return recursiveFilterThen(filterLexemes, subPath), nil + } + return filterThen(filterLexemes, subPath), nil + case lexemePropertyName: + subPath, err := newPath(l) + if err != nil { + return nil, err + } + childName := strings.TrimPrefix(lx.val, ".") + childName = strings.TrimSuffix(childName, propertyName) + return propertyNameChildThen(childName, subPath), nil + case lexemeBracketPropertyName: + subPath, err := newPath(l) + if err != nil { + return nil, err + } + childNames := strings.TrimSpace(lx.val) + childNames = strings.TrimSuffix(childNames, propertyName) + childNames = strings.TrimSuffix(strings.TrimPrefix(childNames, "["), "]") + childNames = strings.TrimSpace(childNames) + return propertyNameBracketChildThen(childNames, subPath), nil + case lexemeArraySubscriptPropertyName: + subPath, err := newPath(l) + if err != nil { + return nil, err + } + subscript := strings.TrimSuffix(strings.TrimPrefix(lx.val, "["), "]~") + return propertyNameArraySubscriptThen(subscript, subPath), nil + } + + return nil, errors.New("invalid path syntax") +} + +func identity(node, root *yaml.Node) yit.Iterator { + if node.Kind == 0 { + return yit.FromNodes() + } + return yit.FromNode(node) +} + +func empty(node, root *yaml.Node) yit.Iterator { + return yit.FromNodes() +} + +func compose(i yit.Iterator, p *Path, root *yaml.Node) yit.Iterator { + its := []yit.Iterator{} + for a, ok := i(); ok; a, ok = i() { + its = append(its, p.f(a, root)) + } + return yit.FromIterators(its...) +} + +func new(f func(node, root *yaml.Node) yit.Iterator) *Path { + return &Path{f: f} +} + +func propertyNameChildThen(childName string, p *Path) *Path { + childName = unescape(childName) + + return new(func(node, root *yaml.Node) yit.Iterator { + if node.Kind != yaml.MappingNode { + return empty(node, root) + } + for i, n := range node.Content { + if i%2 == 0 && n.Value == childName { + return compose(yit.FromNode(node.Content[i]), p, root) + } + } + return empty(node, root) + }) +} + +func propertyNameBracketChildThen(childNames string, p *Path) *Path { + unquotedChildren := bracketChildNames(childNames) + + return new(func(node, root *yaml.Node) yit.Iterator { + if node.Kind != yaml.MappingNode { + return empty(node, root) + } + its := []yit.Iterator{} + for _, childName := range unquotedChildren { + for i, n := range node.Content { + if i%2 == 0 && n.Value == childName { + its = append(its, yit.FromNode(node.Content[i])) + } + } + } + return compose(yit.FromIterators(its...), p, root) + }) +} + +func propertyNameArraySubscriptThen(subscript string, p *Path) *Path { + return new(func(node, root *yaml.Node) yit.Iterator { + if node.Kind == yaml.MappingNode && subscript == "*" { + its := []yit.Iterator{} + for i, n := range node.Content { + if i%2 != 0 { + continue // skip child values + } + its = append(its, compose(yit.FromNode(n), p, root)) + } + return yit.FromIterators(its...) + } + return empty(node, root) + }) +} + +func childThen(childName string, p *Path) *Path { + if childName == "*" { + return allChildrenThen(p) + } + childName = unescape(childName) + + return new(func(node, root *yaml.Node) yit.Iterator { + if node.Kind != yaml.MappingNode { + return empty(node, root) + } + for i, n := range node.Content { + if i%2 == 0 && n.Value == childName { + return compose(yit.FromNode(node.Content[i+1]), p, root) + } + } + return empty(node, root) + }) +} + +func bracketChildNames(childNames string) []string { + s := strings.Split(childNames, ",") + // reconstitute child names with embedded commas + children := []string{} + accum := "" + for _, c := range s { + if balanced(c, '\'') && balanced(c, '"') { + if accum != "" { + accum += "," + c + } else { + children = append(children, c) + accum = "" + } + } else { + if accum == "" { + accum = c + } else { + accum += "," + c + children = append(children, accum) + accum = "" + } + } + } + if accum != "" { + children = append(children, accum) + } + + unquotedChildren := []string{} + for _, c := range children { + c = strings.TrimSpace(c) + if strings.HasPrefix(c, "'") { + c = strings.TrimSuffix(strings.TrimPrefix(c, "'"), "'") + } else { + c = strings.TrimSuffix(strings.TrimPrefix(c, `"`), `"`) + } + c = unescape(c) + unquotedChildren = append(unquotedChildren, c) + } + return unquotedChildren +} + +func balanced(c string, q rune) bool { + bal := true + prev := eof + for i := 0; i < len(c); { + rune, width := utf8.DecodeRuneInString(c[i:]) + i += width + if rune == q { + if i > 0 && prev == '\\' { + prev = rune + continue + } + bal = !bal + } + prev = rune + } + return bal +} + +func bracketChildThen(childNames string, p *Path) *Path { + unquotedChildren := bracketChildNames(childNames) + + return new(func(node, root *yaml.Node) yit.Iterator { + if node.Kind != yaml.MappingNode { + return empty(node, root) + } + its := []yit.Iterator{} + for _, childName := range unquotedChildren { + for i, n := range node.Content { + if i%2 == 0 && n.Value == childName { + its = append(its, yit.FromNode(node.Content[i+1])) + } + } + } + return compose(yit.FromIterators(its...), p, root) + }) +} + +func unescape(raw string) string { + esc := "" + escaped := false + for i := 0; i < len(raw); { + rune, width := utf8.DecodeRuneInString(raw[i:]) + i += width + if rune == '\\' { + if escaped { + esc += string(rune) + } + escaped = !escaped + continue + } + escaped = false + esc += string(rune) + } + + return esc +} + +func allChildrenThen(p *Path) *Path { + return new(func(node, root *yaml.Node) yit.Iterator { + switch node.Kind { + case yaml.MappingNode: + its := []yit.Iterator{} + for i, n := range node.Content { + if i%2 == 0 { + continue // skip child names + } + its = append(its, compose(yit.FromNode(n), p, root)) + } + return yit.FromIterators(its...) + + case yaml.SequenceNode: + its := []yit.Iterator{} + for i := 0; i < len(node.Content); i++ { + its = append(its, compose(yit.FromNode(node.Content[i]), p, root)) + } + return yit.FromIterators(its...) + + default: + return empty(node, root) + } + }) +} + +func arraySubscriptThen(subscript string, p *Path) *Path { + return new(func(node, root *yaml.Node) yit.Iterator { + if node.Kind == yaml.MappingNode && subscript == "*" { + its := []yit.Iterator{} + for i, n := range node.Content { + if i%2 == 0 { + continue // skip child names + } + its = append(its, compose(yit.FromNode(n), p, root)) + } + return yit.FromIterators(its...) + } + if node.Kind != yaml.SequenceNode { + return empty(node, root) + } + + slice, err := slice(subscript, len(node.Content)) + if err != nil { + panic(err) // should not happen, lexer should have detected errors + } + + its := []yit.Iterator{} + for _, s := range slice { + if s >= 0 && s < len(node.Content) { + its = append(its, compose(yit.FromNode(node.Content[s]), p, root)) + } + } + return yit.FromIterators(its...) + }) +} + +func filterThen(filterLexemes []lexeme, p *Path) *Path { + filter := newFilter(newFilterNode(filterLexemes)) + return new(func(node, root *yaml.Node) yit.Iterator { + its := []yit.Iterator{} + if node.Kind == yaml.SequenceNode { + for _, c := range node.Content { + if filter(c, root) { + its = append(its, compose(yit.FromNode(c), p, root)) + } + } + } else { + if filter(node, root) { + its = append(its, compose(yit.FromNode(node), p, root)) + } + } + return yit.FromIterators(its...) + }) +} + +func recursiveFilterThen(filterLexemes []lexeme, p *Path) *Path { + filter := newFilter(newFilterNode(filterLexemes)) + return new(func(node, root *yaml.Node) yit.Iterator { + its := []yit.Iterator{} + + if filter(node, root) { + its = append(its, compose(yit.FromNode(node), p, root)) + } + return yit.FromIterators(its...) + }) +} diff --git a/vendor/github.com/vmware-labs/yaml-jsonpath/pkg/yamlpath/slicer.go b/vendor/github.com/vmware-labs/yaml-jsonpath/pkg/yamlpath/slicer.go new file mode 100644 index 0000000000..da66989b3a --- /dev/null +++ b/vendor/github.com/vmware-labs/yaml-jsonpath/pkg/yamlpath/slicer.go @@ -0,0 +1,143 @@ +/* + * Copyright 2020 VMware, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package yamlpath + +import ( + "errors" + "fmt" + "strconv" + "strings" +) + +func slice(index string, length int) ([]int, error) { + if union := strings.Split(index, ","); len(union) > 1 { + combination := []int{} + for i, idx := range union { + sl, err := slice(idx, length) + if err != nil { + return nil, fmt.Errorf("error in union member %d: %s", i, err) + } + combination = append(combination, sl...) + } + return combination, nil + } + + index = strings.TrimSpace(index) + + if index == "*" { + return indices(0, length, 1, length), nil + } + + subscr := strings.Split(index, ":") + if len(subscr) > 3 { + return nil, errors.New("malformed array index, too many colons") + } + type subscript struct { + present bool + value int + } + var subscripts []subscript = []subscript{{false, 0}, {false, 0}, {false, 0}} + const ( + sFrom = iota + sTo + sStep + ) + for i, s := range subscr { + s = strings.TrimSpace(s) + if s != "" { + n, err := strconv.Atoi(s) + if err != nil { + return nil, errors.New("non-integer array index") + } + subscripts[i] = subscript{ + present: true, + value: n, + } + } + } + + // pick out the case of a single subscript first since the "to" value needs special-casing + if len(subscr) == 1 { + if !subscripts[sFrom].present { + return nil, errors.New("array index missing") + } + from := subscripts[sFrom].value + if from < 0 { + from += length + } + return indices(from, from+1, 1, length), nil + } + + var from, to, step int + + if subscripts[sStep].present { + step = subscripts[sStep].value + if step == 0 { + return nil, errors.New("array index step value must be non-zero") + } + } else { + step = 1 + } + + if subscripts[sFrom].present { + from = subscripts[sFrom].value + if from < 0 { + from += length + } + } else { + if step > 0 { + from = 0 + } else { + from = length - 1 + } + } + + if subscripts[sTo].present { + to = subscripts[sTo].value + if to < 0 { + to += length + } + } else { + if step > 0 { + to = length + } else { + to = -1 + } + } + + return indices(from, to, step, length), nil +} + +func indices(from, to, step, length int) []int { + slice := []int{} + if step > 0 { + if from < 0 { + from = 0 // avoid CPU attack + } + if to > length { + to = length // avoid CPU attack + } + for i := from; i < to; i += step { + if 0 <= i && i < length { + slice = append(slice, i) + } + } + } else if step < 0 { + if from > length { + from = length // avoid CPU attack + } + if to < -1 { + to = -1 // avoid CPU attack + } + for i := from; i > to; i += step { + if 0 <= i && i < length { + slice = append(slice, i) + } + } + } + return slice +} diff --git a/vendor/go.uber.org/zap/CHANGELOG.md b/vendor/go.uber.org/zap/CHANGELOG.md index da36c37080..0db1f9f15f 100644 --- a/vendor/go.uber.org/zap/CHANGELOG.md +++ b/vendor/go.uber.org/zap/CHANGELOG.md @@ -3,6 +3,19 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). +## 1.24.0 (30 Nov 2022) + +Enhancements: +* [#1148][]: Add `Level` to both `Logger` and `SugaredLogger` that reports the + current minimum enabled log level. +* [#1185][]: `SugaredLogger` turns errors to zap.Error automatically. + +Thanks to @Abirdcfly, @craigpastro, @nnnkkk7, and @sashamelentyev for their +contributions to this release. + +[#1148]: https://github.coml/uber-go/zap/pull/1148 +[#1185]: https://github.coml/uber-go/zap/pull/1185 + ## 1.23.0 (24 Aug 2022) Enhancements: diff --git a/vendor/go.uber.org/zap/array_go118.go b/vendor/go.uber.org/zap/array_go118.go index ea94f9d75d..d0d2c49d69 100644 --- a/vendor/go.uber.org/zap/array_go118.go +++ b/vendor/go.uber.org/zap/array_go118.go @@ -76,9 +76,9 @@ func (os objects[T]) MarshalLogArray(arr zapcore.ArrayEncoder) error { return nil } -// objectMarshalerPtr is a constraint that specifies that the given type +// ObjectMarshalerPtr is a constraint that specifies that the given type // implements zapcore.ObjectMarshaler on a pointer receiver. -type objectMarshalerPtr[T any] interface { +type ObjectMarshalerPtr[T any] interface { *T zapcore.ObjectMarshaler } @@ -105,11 +105,11 @@ type objectMarshalerPtr[T any] interface { // // var requests []*Request = ... // logger.Info("sending requests", zap.Objects("requests", requests)) -func ObjectValues[T any, P objectMarshalerPtr[T]](key string, values []T) Field { +func ObjectValues[T any, P ObjectMarshalerPtr[T]](key string, values []T) Field { return Array(key, objectValues[T, P](values)) } -type objectValues[T any, P objectMarshalerPtr[T]] []T +type objectValues[T any, P ObjectMarshalerPtr[T]] []T func (os objectValues[T, P]) MarshalLogArray(arr zapcore.ArrayEncoder) error { for i := range os { diff --git a/vendor/go.uber.org/zap/logger.go b/vendor/go.uber.org/zap/logger.go index b5f9a99fd8..cd44030d13 100644 --- a/vendor/go.uber.org/zap/logger.go +++ b/vendor/go.uber.org/zap/logger.go @@ -183,6 +183,13 @@ func (log *Logger) With(fields ...Field) *Logger { return l } +// Level reports the minimum enabled level for this logger. +// +// For NopLoggers, this is [zapcore.InvalidLevel]. +func (log *Logger) Level() zapcore.Level { + return zapcore.LevelOf(log.core) +} + // Check returns a CheckedEntry if logging a message at the specified level // is enabled. It's a completely optional optimization; in high-performance // applications, Check can help avoid allocating a slice to hold fields. diff --git a/vendor/go.uber.org/zap/options.go b/vendor/go.uber.org/zap/options.go index 1511166c06..c4f3bca3d2 100644 --- a/vendor/go.uber.org/zap/options.go +++ b/vendor/go.uber.org/zap/options.go @@ -133,7 +133,8 @@ func IncreaseLevel(lvl zapcore.LevelEnabler) Option { } // OnFatal sets the action to take on fatal logs. -// Deprecated: Use WithFatalHook instead. +// +// Deprecated: Use [WithFatalHook] instead. func OnFatal(action zapcore.CheckWriteAction) Option { return WithFatalHook(action) } diff --git a/vendor/go.uber.org/zap/sink.go b/vendor/go.uber.org/zap/sink.go index df46fa87a7..478c9a10ff 100644 --- a/vendor/go.uber.org/zap/sink.go +++ b/vendor/go.uber.org/zap/sink.go @@ -1,4 +1,4 @@ -// Copyright (c) 2016 Uber Technologies, Inc. +// Copyright (c) 2016-2022 Uber Technologies, Inc. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -26,6 +26,7 @@ import ( "io" "net/url" "os" + "path/filepath" "strings" "sync" @@ -34,23 +35,7 @@ import ( const schemeFile = "file" -var ( - _sinkMutex sync.RWMutex - _sinkFactories map[string]func(*url.URL) (Sink, error) // keyed by scheme -) - -func init() { - resetSinkRegistry() -} - -func resetSinkRegistry() { - _sinkMutex.Lock() - defer _sinkMutex.Unlock() - - _sinkFactories = map[string]func(*url.URL) (Sink, error){ - schemeFile: newFileSink, - } -} +var _sinkRegistry = newSinkRegistry() // Sink defines the interface to write to and close logger destinations. type Sink interface { @@ -58,10 +43,6 @@ type Sink interface { io.Closer } -type nopCloserSink struct{ zapcore.WriteSyncer } - -func (nopCloserSink) Close() error { return nil } - type errSinkNotFound struct { scheme string } @@ -70,16 +51,29 @@ func (e *errSinkNotFound) Error() string { return fmt.Sprintf("no sink found for scheme %q", e.scheme) } -// RegisterSink registers a user-supplied factory for all sinks with a -// particular scheme. -// -// All schemes must be ASCII, valid under section 3.1 of RFC 3986 -// (https://tools.ietf.org/html/rfc3986#section-3.1), and must not already -// have a factory registered. Zap automatically registers a factory for the -// "file" scheme. -func RegisterSink(scheme string, factory func(*url.URL) (Sink, error)) error { - _sinkMutex.Lock() - defer _sinkMutex.Unlock() +type nopCloserSink struct{ zapcore.WriteSyncer } + +func (nopCloserSink) Close() error { return nil } + +type sinkRegistry struct { + mu sync.Mutex + factories map[string]func(*url.URL) (Sink, error) // keyed by scheme + openFile func(string, int, os.FileMode) (*os.File, error) // type matches os.OpenFile +} + +func newSinkRegistry() *sinkRegistry { + sr := &sinkRegistry{ + factories: make(map[string]func(*url.URL) (Sink, error)), + openFile: os.OpenFile, + } + sr.RegisterSink(schemeFile, sr.newFileSinkFromURL) + return sr +} + +// RegisterScheme registers the given factory for the specific scheme. +func (sr *sinkRegistry) RegisterSink(scheme string, factory func(*url.URL) (Sink, error)) error { + sr.mu.Lock() + defer sr.mu.Unlock() if scheme == "" { return errors.New("can't register a sink factory for empty string") @@ -88,14 +82,22 @@ func RegisterSink(scheme string, factory func(*url.URL) (Sink, error)) error { if err != nil { return fmt.Errorf("%q is not a valid scheme: %v", scheme, err) } - if _, ok := _sinkFactories[normalized]; ok { + if _, ok := sr.factories[normalized]; ok { return fmt.Errorf("sink factory already registered for scheme %q", normalized) } - _sinkFactories[normalized] = factory + sr.factories[normalized] = factory return nil } -func newSink(rawURL string) (Sink, error) { +func (sr *sinkRegistry) newSink(rawURL string) (Sink, error) { + // URL parsing doesn't work well for Windows paths such as `c:\log.txt`, as scheme is set to + // the drive, and path is unset unless `c:/log.txt` is used. + // To avoid Windows-specific URL handling, we instead check IsAbs to open as a file. + // filepath.IsAbs is OS-specific, so IsAbs('c:/log.txt') is false outside of Windows. + if filepath.IsAbs(rawURL) { + return sr.newFileSinkFromPath(rawURL) + } + u, err := url.Parse(rawURL) if err != nil { return nil, fmt.Errorf("can't parse %q as a URL: %v", rawURL, err) @@ -104,16 +106,27 @@ func newSink(rawURL string) (Sink, error) { u.Scheme = schemeFile } - _sinkMutex.RLock() - factory, ok := _sinkFactories[u.Scheme] - _sinkMutex.RUnlock() + sr.mu.Lock() + factory, ok := sr.factories[u.Scheme] + sr.mu.Unlock() if !ok { return nil, &errSinkNotFound{u.Scheme} } return factory(u) } -func newFileSink(u *url.URL) (Sink, error) { +// RegisterSink registers a user-supplied factory for all sinks with a +// particular scheme. +// +// All schemes must be ASCII, valid under section 0.1 of RFC 3986 +// (https://tools.ietf.org/html/rfc3983#section-3.1), and must not already +// have a factory registered. Zap automatically registers a factory for the +// "file" scheme. +func RegisterSink(scheme string, factory func(*url.URL) (Sink, error)) error { + return _sinkRegistry.RegisterSink(scheme, factory) +} + +func (sr *sinkRegistry) newFileSinkFromURL(u *url.URL) (Sink, error) { if u.User != nil { return nil, fmt.Errorf("user and password not allowed with file URLs: got %v", u) } @@ -130,13 +143,18 @@ func newFileSink(u *url.URL) (Sink, error) { if hn := u.Hostname(); hn != "" && hn != "localhost" { return nil, fmt.Errorf("file URLs must leave host empty or use localhost: got %v", u) } - switch u.Path { + + return sr.newFileSinkFromPath(u.Path) +} + +func (sr *sinkRegistry) newFileSinkFromPath(path string) (Sink, error) { + switch path { case "stdout": return nopCloserSink{os.Stdout}, nil case "stderr": return nopCloserSink{os.Stderr}, nil } - return os.OpenFile(u.Path, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0666) + return sr.openFile(path, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0666) } func normalizeScheme(s string) (string, error) { diff --git a/vendor/go.uber.org/zap/stacktrace.go b/vendor/go.uber.org/zap/stacktrace.go index 3d187fa566..817a3bde8b 100644 --- a/vendor/go.uber.org/zap/stacktrace.go +++ b/vendor/go.uber.org/zap/stacktrace.go @@ -154,7 +154,7 @@ func newStackFormatter(b *buffer.Buffer) stackFormatter { // the final runtime.main/runtime.goexit frame. func (sf *stackFormatter) FormatStack(stack *stacktrace) { // Note: On the last iteration, frames.Next() returns false, with a valid - // frame, but we ignore this frame. The last frame is a a runtime frame which + // frame, but we ignore this frame. The last frame is a runtime frame which // adds noise, since it's only either runtime.main or runtime.goexit. for frame, more := stack.Next(); more; frame, more = stack.Next() { sf.FormatFrame(frame) diff --git a/vendor/go.uber.org/zap/sugar.go b/vendor/go.uber.org/zap/sugar.go index c450b2dda8..ac387b3e47 100644 --- a/vendor/go.uber.org/zap/sugar.go +++ b/vendor/go.uber.org/zap/sugar.go @@ -31,6 +31,7 @@ import ( const ( _oddNumberErrMsg = "Ignored key without a value." _nonStringKeyErrMsg = "Ignored key-value pairs with non-string keys." + _multipleErrMsg = "Multiple errors without a key." ) // A SugaredLogger wraps the base Logger functionality in a slower, but less @@ -114,6 +115,13 @@ func (s *SugaredLogger) With(args ...interface{}) *SugaredLogger { return &SugaredLogger{base: s.base.With(s.sweetenFields(args)...)} } +// Level reports the minimum enabled level for this logger. +// +// For NopLoggers, this is [zapcore.InvalidLevel]. +func (s *SugaredLogger) Level() zapcore.Level { + return zapcore.LevelOf(s.base.core) +} + // Debug uses fmt.Sprint to construct and log a message. func (s *SugaredLogger) Debug(args ...interface{}) { s.log(DebugLevel, "", args, nil) @@ -329,10 +337,13 @@ func (s *SugaredLogger) sweetenFields(args []interface{}) []Field { return nil } - // Allocate enough space for the worst case; if users pass only structured - // fields, we shouldn't penalize them with extra allocations. - fields := make([]Field, 0, len(args)) - var invalid invalidPairs + var ( + // Allocate enough space for the worst case; if users pass only structured + // fields, we shouldn't penalize them with extra allocations. + fields = make([]Field, 0, len(args)) + invalid invalidPairs + seenError bool + ) for i := 0; i < len(args); { // This is a strongly-typed field. Consume it and move on. @@ -342,6 +353,18 @@ func (s *SugaredLogger) sweetenFields(args []interface{}) []Field { continue } + // If it is an error, consume it and move on. + if err, ok := args[i].(error); ok { + if !seenError { + seenError = true + fields = append(fields, Error(err)) + } else { + s.base.Error(_multipleErrMsg, Error(err)) + } + i++ + continue + } + // Make sure this element isn't a dangling key. if i == len(args)-1 { s.base.Error(_oddNumberErrMsg, Any("ignored", args[i])) diff --git a/vendor/go.uber.org/zap/writer.go b/vendor/go.uber.org/zap/writer.go index 2c3dbd425e..f08728e1ec 100644 --- a/vendor/go.uber.org/zap/writer.go +++ b/vendor/go.uber.org/zap/writer.go @@ -68,7 +68,7 @@ func open(paths []string) ([]zapcore.WriteSyncer, func(), error) { var openErr error for _, path := range paths { - sink, err := newSink(path) + sink, err := _sinkRegistry.newSink(path) if err != nil { openErr = multierr.Append(openErr, fmt.Errorf("open sink %q: %w", path, err)) continue diff --git a/vendor/go.uber.org/zap/zapcore/entry.go b/vendor/go.uber.org/zap/zapcore/entry.go index ea0431eb35..9d326e95ea 100644 --- a/vendor/go.uber.org/zap/zapcore/entry.go +++ b/vendor/go.uber.org/zap/zapcore/entry.go @@ -281,7 +281,8 @@ func (ce *CheckedEntry) AddCore(ent Entry, core Core) *CheckedEntry { // Should sets this CheckedEntry's CheckWriteAction, which controls whether a // Core will panic or fatal after writing this log entry. Like AddCore, it's // safe to call on nil CheckedEntry references. -// Deprecated: Use After(ent Entry, after CheckWriteHook) instead. +// +// Deprecated: Use [CheckedEntry.After] instead. func (ce *CheckedEntry) Should(ent Entry, should CheckWriteAction) *CheckedEntry { return ce.After(ent, should) } diff --git a/vendor/golang.org/x/crypto/sha3/doc.go b/vendor/golang.org/x/crypto/sha3/doc.go new file mode 100644 index 0000000000..decd8cf9bf --- /dev/null +++ b/vendor/golang.org/x/crypto/sha3/doc.go @@ -0,0 +1,62 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package sha3 implements the SHA-3 fixed-output-length hash functions and +// the SHAKE variable-output-length hash functions defined by FIPS-202. +// +// Both types of hash function use the "sponge" construction and the Keccak +// permutation. For a detailed specification see http://keccak.noekeon.org/ +// +// # Guidance +// +// If you aren't sure what function you need, use SHAKE256 with at least 64 +// bytes of output. The SHAKE instances are faster than the SHA3 instances; +// the latter have to allocate memory to conform to the hash.Hash interface. +// +// If you need a secret-key MAC (message authentication code), prepend the +// secret key to the input, hash with SHAKE256 and read at least 32 bytes of +// output. +// +// # Security strengths +// +// The SHA3-x (x equals 224, 256, 384, or 512) functions have a security +// strength against preimage attacks of x bits. Since they only produce "x" +// bits of output, their collision-resistance is only "x/2" bits. +// +// The SHAKE-256 and -128 functions have a generic security strength of 256 and +// 128 bits against all attacks, provided that at least 2x bits of their output +// is used. Requesting more than 64 or 32 bytes of output, respectively, does +// not increase the collision-resistance of the SHAKE functions. +// +// # The sponge construction +// +// A sponge builds a pseudo-random function from a public pseudo-random +// permutation, by applying the permutation to a state of "rate + capacity" +// bytes, but hiding "capacity" of the bytes. +// +// A sponge starts out with a zero state. To hash an input using a sponge, up +// to "rate" bytes of the input are XORed into the sponge's state. The sponge +// is then "full" and the permutation is applied to "empty" it. This process is +// repeated until all the input has been "absorbed". The input is then padded. +// The digest is "squeezed" from the sponge in the same way, except that output +// is copied out instead of input being XORed in. +// +// A sponge is parameterized by its generic security strength, which is equal +// to half its capacity; capacity + rate is equal to the permutation's width. +// Since the KeccakF-1600 permutation is 1600 bits (200 bytes) wide, this means +// that the security strength of a sponge instance is equal to (1600 - bitrate) / 2. +// +// # Recommendations +// +// The SHAKE functions are recommended for most new uses. They can produce +// output of arbitrary length. SHAKE256, with an output length of at least +// 64 bytes, provides 256-bit security against all attacks. The Keccak team +// recommends it for most applications upgrading from SHA2-512. (NIST chose a +// much stronger, but much slower, sponge instance for SHA3-512.) +// +// The SHA-3 functions are "drop-in" replacements for the SHA-2 functions. +// They produce output of the same length, with the same security strengths +// against all attacks. This means, in particular, that SHA3-256 only has +// 128-bit collision resistance, because its output length is 32 bytes. +package sha3 // import "golang.org/x/crypto/sha3" diff --git a/vendor/golang.org/x/crypto/sha3/hashes.go b/vendor/golang.org/x/crypto/sha3/hashes.go new file mode 100644 index 0000000000..0d8043fd2a --- /dev/null +++ b/vendor/golang.org/x/crypto/sha3/hashes.go @@ -0,0 +1,97 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package sha3 + +// This file provides functions for creating instances of the SHA-3 +// and SHAKE hash functions, as well as utility functions for hashing +// bytes. + +import ( + "hash" +) + +// New224 creates a new SHA3-224 hash. +// Its generic security strength is 224 bits against preimage attacks, +// and 112 bits against collision attacks. +func New224() hash.Hash { + if h := new224Asm(); h != nil { + return h + } + return &state{rate: 144, outputLen: 28, dsbyte: 0x06} +} + +// New256 creates a new SHA3-256 hash. +// Its generic security strength is 256 bits against preimage attacks, +// and 128 bits against collision attacks. +func New256() hash.Hash { + if h := new256Asm(); h != nil { + return h + } + return &state{rate: 136, outputLen: 32, dsbyte: 0x06} +} + +// New384 creates a new SHA3-384 hash. +// Its generic security strength is 384 bits against preimage attacks, +// and 192 bits against collision attacks. +func New384() hash.Hash { + if h := new384Asm(); h != nil { + return h + } + return &state{rate: 104, outputLen: 48, dsbyte: 0x06} +} + +// New512 creates a new SHA3-512 hash. +// Its generic security strength is 512 bits against preimage attacks, +// and 256 bits against collision attacks. +func New512() hash.Hash { + if h := new512Asm(); h != nil { + return h + } + return &state{rate: 72, outputLen: 64, dsbyte: 0x06} +} + +// NewLegacyKeccak256 creates a new Keccak-256 hash. +// +// Only use this function if you require compatibility with an existing cryptosystem +// that uses non-standard padding. All other users should use New256 instead. +func NewLegacyKeccak256() hash.Hash { return &state{rate: 136, outputLen: 32, dsbyte: 0x01} } + +// NewLegacyKeccak512 creates a new Keccak-512 hash. +// +// Only use this function if you require compatibility with an existing cryptosystem +// that uses non-standard padding. All other users should use New512 instead. +func NewLegacyKeccak512() hash.Hash { return &state{rate: 72, outputLen: 64, dsbyte: 0x01} } + +// Sum224 returns the SHA3-224 digest of the data. +func Sum224(data []byte) (digest [28]byte) { + h := New224() + h.Write(data) + h.Sum(digest[:0]) + return +} + +// Sum256 returns the SHA3-256 digest of the data. +func Sum256(data []byte) (digest [32]byte) { + h := New256() + h.Write(data) + h.Sum(digest[:0]) + return +} + +// Sum384 returns the SHA3-384 digest of the data. +func Sum384(data []byte) (digest [48]byte) { + h := New384() + h.Write(data) + h.Sum(digest[:0]) + return +} + +// Sum512 returns the SHA3-512 digest of the data. +func Sum512(data []byte) (digest [64]byte) { + h := New512() + h.Write(data) + h.Sum(digest[:0]) + return +} diff --git a/vendor/golang.org/x/crypto/sha3/hashes_generic.go b/vendor/golang.org/x/crypto/sha3/hashes_generic.go new file mode 100644 index 0000000000..c74fc20fcb --- /dev/null +++ b/vendor/golang.org/x/crypto/sha3/hashes_generic.go @@ -0,0 +1,28 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !gc || purego || !s390x +// +build !gc purego !s390x + +package sha3 + +import ( + "hash" +) + +// new224Asm returns an assembly implementation of SHA3-224 if available, +// otherwise it returns nil. +func new224Asm() hash.Hash { return nil } + +// new256Asm returns an assembly implementation of SHA3-256 if available, +// otherwise it returns nil. +func new256Asm() hash.Hash { return nil } + +// new384Asm returns an assembly implementation of SHA3-384 if available, +// otherwise it returns nil. +func new384Asm() hash.Hash { return nil } + +// new512Asm returns an assembly implementation of SHA3-512 if available, +// otherwise it returns nil. +func new512Asm() hash.Hash { return nil } diff --git a/vendor/golang.org/x/crypto/sha3/keccakf.go b/vendor/golang.org/x/crypto/sha3/keccakf.go new file mode 100644 index 0000000000..e5faa375c0 --- /dev/null +++ b/vendor/golang.org/x/crypto/sha3/keccakf.go @@ -0,0 +1,415 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !amd64 || purego || !gc +// +build !amd64 purego !gc + +package sha3 + +import "math/bits" + +// rc stores the round constants for use in the ι step. +var rc = [24]uint64{ + 0x0000000000000001, + 0x0000000000008082, + 0x800000000000808A, + 0x8000000080008000, + 0x000000000000808B, + 0x0000000080000001, + 0x8000000080008081, + 0x8000000000008009, + 0x000000000000008A, + 0x0000000000000088, + 0x0000000080008009, + 0x000000008000000A, + 0x000000008000808B, + 0x800000000000008B, + 0x8000000000008089, + 0x8000000000008003, + 0x8000000000008002, + 0x8000000000000080, + 0x000000000000800A, + 0x800000008000000A, + 0x8000000080008081, + 0x8000000000008080, + 0x0000000080000001, + 0x8000000080008008, +} + +// keccakF1600 applies the Keccak permutation to a 1600b-wide +// state represented as a slice of 25 uint64s. +func keccakF1600(a *[25]uint64) { + // Implementation translated from Keccak-inplace.c + // in the keccak reference code. + var t, bc0, bc1, bc2, bc3, bc4, d0, d1, d2, d3, d4 uint64 + + for i := 0; i < 24; i += 4 { + // Combines the 5 steps in each round into 2 steps. + // Unrolls 4 rounds per loop and spreads some steps across rounds. + + // Round 1 + bc0 = a[0] ^ a[5] ^ a[10] ^ a[15] ^ a[20] + bc1 = a[1] ^ a[6] ^ a[11] ^ a[16] ^ a[21] + bc2 = a[2] ^ a[7] ^ a[12] ^ a[17] ^ a[22] + bc3 = a[3] ^ a[8] ^ a[13] ^ a[18] ^ a[23] + bc4 = a[4] ^ a[9] ^ a[14] ^ a[19] ^ a[24] + d0 = bc4 ^ (bc1<<1 | bc1>>63) + d1 = bc0 ^ (bc2<<1 | bc2>>63) + d2 = bc1 ^ (bc3<<1 | bc3>>63) + d3 = bc2 ^ (bc4<<1 | bc4>>63) + d4 = bc3 ^ (bc0<<1 | bc0>>63) + + bc0 = a[0] ^ d0 + t = a[6] ^ d1 + bc1 = bits.RotateLeft64(t, 44) + t = a[12] ^ d2 + bc2 = bits.RotateLeft64(t, 43) + t = a[18] ^ d3 + bc3 = bits.RotateLeft64(t, 21) + t = a[24] ^ d4 + bc4 = bits.RotateLeft64(t, 14) + a[0] = bc0 ^ (bc2 &^ bc1) ^ rc[i] + a[6] = bc1 ^ (bc3 &^ bc2) + a[12] = bc2 ^ (bc4 &^ bc3) + a[18] = bc3 ^ (bc0 &^ bc4) + a[24] = bc4 ^ (bc1 &^ bc0) + + t = a[10] ^ d0 + bc2 = bits.RotateLeft64(t, 3) + t = a[16] ^ d1 + bc3 = bits.RotateLeft64(t, 45) + t = a[22] ^ d2 + bc4 = bits.RotateLeft64(t, 61) + t = a[3] ^ d3 + bc0 = bits.RotateLeft64(t, 28) + t = a[9] ^ d4 + bc1 = bits.RotateLeft64(t, 20) + a[10] = bc0 ^ (bc2 &^ bc1) + a[16] = bc1 ^ (bc3 &^ bc2) + a[22] = bc2 ^ (bc4 &^ bc3) + a[3] = bc3 ^ (bc0 &^ bc4) + a[9] = bc4 ^ (bc1 &^ bc0) + + t = a[20] ^ d0 + bc4 = bits.RotateLeft64(t, 18) + t = a[1] ^ d1 + bc0 = bits.RotateLeft64(t, 1) + t = a[7] ^ d2 + bc1 = bits.RotateLeft64(t, 6) + t = a[13] ^ d3 + bc2 = bits.RotateLeft64(t, 25) + t = a[19] ^ d4 + bc3 = bits.RotateLeft64(t, 8) + a[20] = bc0 ^ (bc2 &^ bc1) + a[1] = bc1 ^ (bc3 &^ bc2) + a[7] = bc2 ^ (bc4 &^ bc3) + a[13] = bc3 ^ (bc0 &^ bc4) + a[19] = bc4 ^ (bc1 &^ bc0) + + t = a[5] ^ d0 + bc1 = bits.RotateLeft64(t, 36) + t = a[11] ^ d1 + bc2 = bits.RotateLeft64(t, 10) + t = a[17] ^ d2 + bc3 = bits.RotateLeft64(t, 15) + t = a[23] ^ d3 + bc4 = bits.RotateLeft64(t, 56) + t = a[4] ^ d4 + bc0 = bits.RotateLeft64(t, 27) + a[5] = bc0 ^ (bc2 &^ bc1) + a[11] = bc1 ^ (bc3 &^ bc2) + a[17] = bc2 ^ (bc4 &^ bc3) + a[23] = bc3 ^ (bc0 &^ bc4) + a[4] = bc4 ^ (bc1 &^ bc0) + + t = a[15] ^ d0 + bc3 = bits.RotateLeft64(t, 41) + t = a[21] ^ d1 + bc4 = bits.RotateLeft64(t, 2) + t = a[2] ^ d2 + bc0 = bits.RotateLeft64(t, 62) + t = a[8] ^ d3 + bc1 = bits.RotateLeft64(t, 55) + t = a[14] ^ d4 + bc2 = bits.RotateLeft64(t, 39) + a[15] = bc0 ^ (bc2 &^ bc1) + a[21] = bc1 ^ (bc3 &^ bc2) + a[2] = bc2 ^ (bc4 &^ bc3) + a[8] = bc3 ^ (bc0 &^ bc4) + a[14] = bc4 ^ (bc1 &^ bc0) + + // Round 2 + bc0 = a[0] ^ a[5] ^ a[10] ^ a[15] ^ a[20] + bc1 = a[1] ^ a[6] ^ a[11] ^ a[16] ^ a[21] + bc2 = a[2] ^ a[7] ^ a[12] ^ a[17] ^ a[22] + bc3 = a[3] ^ a[8] ^ a[13] ^ a[18] ^ a[23] + bc4 = a[4] ^ a[9] ^ a[14] ^ a[19] ^ a[24] + d0 = bc4 ^ (bc1<<1 | bc1>>63) + d1 = bc0 ^ (bc2<<1 | bc2>>63) + d2 = bc1 ^ (bc3<<1 | bc3>>63) + d3 = bc2 ^ (bc4<<1 | bc4>>63) + d4 = bc3 ^ (bc0<<1 | bc0>>63) + + bc0 = a[0] ^ d0 + t = a[16] ^ d1 + bc1 = bits.RotateLeft64(t, 44) + t = a[7] ^ d2 + bc2 = bits.RotateLeft64(t, 43) + t = a[23] ^ d3 + bc3 = bits.RotateLeft64(t, 21) + t = a[14] ^ d4 + bc4 = bits.RotateLeft64(t, 14) + a[0] = bc0 ^ (bc2 &^ bc1) ^ rc[i+1] + a[16] = bc1 ^ (bc3 &^ bc2) + a[7] = bc2 ^ (bc4 &^ bc3) + a[23] = bc3 ^ (bc0 &^ bc4) + a[14] = bc4 ^ (bc1 &^ bc0) + + t = a[20] ^ d0 + bc2 = bits.RotateLeft64(t, 3) + t = a[11] ^ d1 + bc3 = bits.RotateLeft64(t, 45) + t = a[2] ^ d2 + bc4 = bits.RotateLeft64(t, 61) + t = a[18] ^ d3 + bc0 = bits.RotateLeft64(t, 28) + t = a[9] ^ d4 + bc1 = bits.RotateLeft64(t, 20) + a[20] = bc0 ^ (bc2 &^ bc1) + a[11] = bc1 ^ (bc3 &^ bc2) + a[2] = bc2 ^ (bc4 &^ bc3) + a[18] = bc3 ^ (bc0 &^ bc4) + a[9] = bc4 ^ (bc1 &^ bc0) + + t = a[15] ^ d0 + bc4 = bits.RotateLeft64(t, 18) + t = a[6] ^ d1 + bc0 = bits.RotateLeft64(t, 1) + t = a[22] ^ d2 + bc1 = bits.RotateLeft64(t, 6) + t = a[13] ^ d3 + bc2 = bits.RotateLeft64(t, 25) + t = a[4] ^ d4 + bc3 = bits.RotateLeft64(t, 8) + a[15] = bc0 ^ (bc2 &^ bc1) + a[6] = bc1 ^ (bc3 &^ bc2) + a[22] = bc2 ^ (bc4 &^ bc3) + a[13] = bc3 ^ (bc0 &^ bc4) + a[4] = bc4 ^ (bc1 &^ bc0) + + t = a[10] ^ d0 + bc1 = bits.RotateLeft64(t, 36) + t = a[1] ^ d1 + bc2 = bits.RotateLeft64(t, 10) + t = a[17] ^ d2 + bc3 = bits.RotateLeft64(t, 15) + t = a[8] ^ d3 + bc4 = bits.RotateLeft64(t, 56) + t = a[24] ^ d4 + bc0 = bits.RotateLeft64(t, 27) + a[10] = bc0 ^ (bc2 &^ bc1) + a[1] = bc1 ^ (bc3 &^ bc2) + a[17] = bc2 ^ (bc4 &^ bc3) + a[8] = bc3 ^ (bc0 &^ bc4) + a[24] = bc4 ^ (bc1 &^ bc0) + + t = a[5] ^ d0 + bc3 = bits.RotateLeft64(t, 41) + t = a[21] ^ d1 + bc4 = bits.RotateLeft64(t, 2) + t = a[12] ^ d2 + bc0 = bits.RotateLeft64(t, 62) + t = a[3] ^ d3 + bc1 = bits.RotateLeft64(t, 55) + t = a[19] ^ d4 + bc2 = bits.RotateLeft64(t, 39) + a[5] = bc0 ^ (bc2 &^ bc1) + a[21] = bc1 ^ (bc3 &^ bc2) + a[12] = bc2 ^ (bc4 &^ bc3) + a[3] = bc3 ^ (bc0 &^ bc4) + a[19] = bc4 ^ (bc1 &^ bc0) + + // Round 3 + bc0 = a[0] ^ a[5] ^ a[10] ^ a[15] ^ a[20] + bc1 = a[1] ^ a[6] ^ a[11] ^ a[16] ^ a[21] + bc2 = a[2] ^ a[7] ^ a[12] ^ a[17] ^ a[22] + bc3 = a[3] ^ a[8] ^ a[13] ^ a[18] ^ a[23] + bc4 = a[4] ^ a[9] ^ a[14] ^ a[19] ^ a[24] + d0 = bc4 ^ (bc1<<1 | bc1>>63) + d1 = bc0 ^ (bc2<<1 | bc2>>63) + d2 = bc1 ^ (bc3<<1 | bc3>>63) + d3 = bc2 ^ (bc4<<1 | bc4>>63) + d4 = bc3 ^ (bc0<<1 | bc0>>63) + + bc0 = a[0] ^ d0 + t = a[11] ^ d1 + bc1 = bits.RotateLeft64(t, 44) + t = a[22] ^ d2 + bc2 = bits.RotateLeft64(t, 43) + t = a[8] ^ d3 + bc3 = bits.RotateLeft64(t, 21) + t = a[19] ^ d4 + bc4 = bits.RotateLeft64(t, 14) + a[0] = bc0 ^ (bc2 &^ bc1) ^ rc[i+2] + a[11] = bc1 ^ (bc3 &^ bc2) + a[22] = bc2 ^ (bc4 &^ bc3) + a[8] = bc3 ^ (bc0 &^ bc4) + a[19] = bc4 ^ (bc1 &^ bc0) + + t = a[15] ^ d0 + bc2 = bits.RotateLeft64(t, 3) + t = a[1] ^ d1 + bc3 = bits.RotateLeft64(t, 45) + t = a[12] ^ d2 + bc4 = bits.RotateLeft64(t, 61) + t = a[23] ^ d3 + bc0 = bits.RotateLeft64(t, 28) + t = a[9] ^ d4 + bc1 = bits.RotateLeft64(t, 20) + a[15] = bc0 ^ (bc2 &^ bc1) + a[1] = bc1 ^ (bc3 &^ bc2) + a[12] = bc2 ^ (bc4 &^ bc3) + a[23] = bc3 ^ (bc0 &^ bc4) + a[9] = bc4 ^ (bc1 &^ bc0) + + t = a[5] ^ d0 + bc4 = bits.RotateLeft64(t, 18) + t = a[16] ^ d1 + bc0 = bits.RotateLeft64(t, 1) + t = a[2] ^ d2 + bc1 = bits.RotateLeft64(t, 6) + t = a[13] ^ d3 + bc2 = bits.RotateLeft64(t, 25) + t = a[24] ^ d4 + bc3 = bits.RotateLeft64(t, 8) + a[5] = bc0 ^ (bc2 &^ bc1) + a[16] = bc1 ^ (bc3 &^ bc2) + a[2] = bc2 ^ (bc4 &^ bc3) + a[13] = bc3 ^ (bc0 &^ bc4) + a[24] = bc4 ^ (bc1 &^ bc0) + + t = a[20] ^ d0 + bc1 = bits.RotateLeft64(t, 36) + t = a[6] ^ d1 + bc2 = bits.RotateLeft64(t, 10) + t = a[17] ^ d2 + bc3 = bits.RotateLeft64(t, 15) + t = a[3] ^ d3 + bc4 = bits.RotateLeft64(t, 56) + t = a[14] ^ d4 + bc0 = bits.RotateLeft64(t, 27) + a[20] = bc0 ^ (bc2 &^ bc1) + a[6] = bc1 ^ (bc3 &^ bc2) + a[17] = bc2 ^ (bc4 &^ bc3) + a[3] = bc3 ^ (bc0 &^ bc4) + a[14] = bc4 ^ (bc1 &^ bc0) + + t = a[10] ^ d0 + bc3 = bits.RotateLeft64(t, 41) + t = a[21] ^ d1 + bc4 = bits.RotateLeft64(t, 2) + t = a[7] ^ d2 + bc0 = bits.RotateLeft64(t, 62) + t = a[18] ^ d3 + bc1 = bits.RotateLeft64(t, 55) + t = a[4] ^ d4 + bc2 = bits.RotateLeft64(t, 39) + a[10] = bc0 ^ (bc2 &^ bc1) + a[21] = bc1 ^ (bc3 &^ bc2) + a[7] = bc2 ^ (bc4 &^ bc3) + a[18] = bc3 ^ (bc0 &^ bc4) + a[4] = bc4 ^ (bc1 &^ bc0) + + // Round 4 + bc0 = a[0] ^ a[5] ^ a[10] ^ a[15] ^ a[20] + bc1 = a[1] ^ a[6] ^ a[11] ^ a[16] ^ a[21] + bc2 = a[2] ^ a[7] ^ a[12] ^ a[17] ^ a[22] + bc3 = a[3] ^ a[8] ^ a[13] ^ a[18] ^ a[23] + bc4 = a[4] ^ a[9] ^ a[14] ^ a[19] ^ a[24] + d0 = bc4 ^ (bc1<<1 | bc1>>63) + d1 = bc0 ^ (bc2<<1 | bc2>>63) + d2 = bc1 ^ (bc3<<1 | bc3>>63) + d3 = bc2 ^ (bc4<<1 | bc4>>63) + d4 = bc3 ^ (bc0<<1 | bc0>>63) + + bc0 = a[0] ^ d0 + t = a[1] ^ d1 + bc1 = bits.RotateLeft64(t, 44) + t = a[2] ^ d2 + bc2 = bits.RotateLeft64(t, 43) + t = a[3] ^ d3 + bc3 = bits.RotateLeft64(t, 21) + t = a[4] ^ d4 + bc4 = bits.RotateLeft64(t, 14) + a[0] = bc0 ^ (bc2 &^ bc1) ^ rc[i+3] + a[1] = bc1 ^ (bc3 &^ bc2) + a[2] = bc2 ^ (bc4 &^ bc3) + a[3] = bc3 ^ (bc0 &^ bc4) + a[4] = bc4 ^ (bc1 &^ bc0) + + t = a[5] ^ d0 + bc2 = bits.RotateLeft64(t, 3) + t = a[6] ^ d1 + bc3 = bits.RotateLeft64(t, 45) + t = a[7] ^ d2 + bc4 = bits.RotateLeft64(t, 61) + t = a[8] ^ d3 + bc0 = bits.RotateLeft64(t, 28) + t = a[9] ^ d4 + bc1 = bits.RotateLeft64(t, 20) + a[5] = bc0 ^ (bc2 &^ bc1) + a[6] = bc1 ^ (bc3 &^ bc2) + a[7] = bc2 ^ (bc4 &^ bc3) + a[8] = bc3 ^ (bc0 &^ bc4) + a[9] = bc4 ^ (bc1 &^ bc0) + + t = a[10] ^ d0 + bc4 = bits.RotateLeft64(t, 18) + t = a[11] ^ d1 + bc0 = bits.RotateLeft64(t, 1) + t = a[12] ^ d2 + bc1 = bits.RotateLeft64(t, 6) + t = a[13] ^ d3 + bc2 = bits.RotateLeft64(t, 25) + t = a[14] ^ d4 + bc3 = bits.RotateLeft64(t, 8) + a[10] = bc0 ^ (bc2 &^ bc1) + a[11] = bc1 ^ (bc3 &^ bc2) + a[12] = bc2 ^ (bc4 &^ bc3) + a[13] = bc3 ^ (bc0 &^ bc4) + a[14] = bc4 ^ (bc1 &^ bc0) + + t = a[15] ^ d0 + bc1 = bits.RotateLeft64(t, 36) + t = a[16] ^ d1 + bc2 = bits.RotateLeft64(t, 10) + t = a[17] ^ d2 + bc3 = bits.RotateLeft64(t, 15) + t = a[18] ^ d3 + bc4 = bits.RotateLeft64(t, 56) + t = a[19] ^ d4 + bc0 = bits.RotateLeft64(t, 27) + a[15] = bc0 ^ (bc2 &^ bc1) + a[16] = bc1 ^ (bc3 &^ bc2) + a[17] = bc2 ^ (bc4 &^ bc3) + a[18] = bc3 ^ (bc0 &^ bc4) + a[19] = bc4 ^ (bc1 &^ bc0) + + t = a[20] ^ d0 + bc3 = bits.RotateLeft64(t, 41) + t = a[21] ^ d1 + bc4 = bits.RotateLeft64(t, 2) + t = a[22] ^ d2 + bc0 = bits.RotateLeft64(t, 62) + t = a[23] ^ d3 + bc1 = bits.RotateLeft64(t, 55) + t = a[24] ^ d4 + bc2 = bits.RotateLeft64(t, 39) + a[20] = bc0 ^ (bc2 &^ bc1) + a[21] = bc1 ^ (bc3 &^ bc2) + a[22] = bc2 ^ (bc4 &^ bc3) + a[23] = bc3 ^ (bc0 &^ bc4) + a[24] = bc4 ^ (bc1 &^ bc0) + } +} diff --git a/vendor/golang.org/x/crypto/sha3/keccakf_amd64.go b/vendor/golang.org/x/crypto/sha3/keccakf_amd64.go new file mode 100644 index 0000000000..248a38241f --- /dev/null +++ b/vendor/golang.org/x/crypto/sha3/keccakf_amd64.go @@ -0,0 +1,14 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build amd64 && !purego && gc +// +build amd64,!purego,gc + +package sha3 + +// This function is implemented in keccakf_amd64.s. + +//go:noescape + +func keccakF1600(a *[25]uint64) diff --git a/vendor/golang.org/x/crypto/sha3/keccakf_amd64.s b/vendor/golang.org/x/crypto/sha3/keccakf_amd64.s new file mode 100644 index 0000000000..4cfa54383b --- /dev/null +++ b/vendor/golang.org/x/crypto/sha3/keccakf_amd64.s @@ -0,0 +1,391 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build amd64 && !purego && gc +// +build amd64,!purego,gc + +// This code was translated into a form compatible with 6a from the public +// domain sources at https://github.com/gvanas/KeccakCodePackage + +// Offsets in state +#define _ba (0*8) +#define _be (1*8) +#define _bi (2*8) +#define _bo (3*8) +#define _bu (4*8) +#define _ga (5*8) +#define _ge (6*8) +#define _gi (7*8) +#define _go (8*8) +#define _gu (9*8) +#define _ka (10*8) +#define _ke (11*8) +#define _ki (12*8) +#define _ko (13*8) +#define _ku (14*8) +#define _ma (15*8) +#define _me (16*8) +#define _mi (17*8) +#define _mo (18*8) +#define _mu (19*8) +#define _sa (20*8) +#define _se (21*8) +#define _si (22*8) +#define _so (23*8) +#define _su (24*8) + +// Temporary registers +#define rT1 AX + +// Round vars +#define rpState DI +#define rpStack SP + +#define rDa BX +#define rDe CX +#define rDi DX +#define rDo R8 +#define rDu R9 + +#define rBa R10 +#define rBe R11 +#define rBi R12 +#define rBo R13 +#define rBu R14 + +#define rCa SI +#define rCe BP +#define rCi rBi +#define rCo rBo +#define rCu R15 + +#define MOVQ_RBI_RCE MOVQ rBi, rCe +#define XORQ_RT1_RCA XORQ rT1, rCa +#define XORQ_RT1_RCE XORQ rT1, rCe +#define XORQ_RBA_RCU XORQ rBa, rCu +#define XORQ_RBE_RCU XORQ rBe, rCu +#define XORQ_RDU_RCU XORQ rDu, rCu +#define XORQ_RDA_RCA XORQ rDa, rCa +#define XORQ_RDE_RCE XORQ rDe, rCe + +#define mKeccakRound(iState, oState, rc, B_RBI_RCE, G_RT1_RCA, G_RT1_RCE, G_RBA_RCU, K_RT1_RCA, K_RT1_RCE, K_RBA_RCU, M_RT1_RCA, M_RT1_RCE, M_RBE_RCU, S_RDU_RCU, S_RDA_RCA, S_RDE_RCE) \ + /* Prepare round */ \ + MOVQ rCe, rDa; \ + ROLQ $1, rDa; \ + \ + MOVQ _bi(iState), rCi; \ + XORQ _gi(iState), rDi; \ + XORQ rCu, rDa; \ + XORQ _ki(iState), rCi; \ + XORQ _mi(iState), rDi; \ + XORQ rDi, rCi; \ + \ + MOVQ rCi, rDe; \ + ROLQ $1, rDe; \ + \ + MOVQ _bo(iState), rCo; \ + XORQ _go(iState), rDo; \ + XORQ rCa, rDe; \ + XORQ _ko(iState), rCo; \ + XORQ _mo(iState), rDo; \ + XORQ rDo, rCo; \ + \ + MOVQ rCo, rDi; \ + ROLQ $1, rDi; \ + \ + MOVQ rCu, rDo; \ + XORQ rCe, rDi; \ + ROLQ $1, rDo; \ + \ + MOVQ rCa, rDu; \ + XORQ rCi, rDo; \ + ROLQ $1, rDu; \ + \ + /* Result b */ \ + MOVQ _ba(iState), rBa; \ + MOVQ _ge(iState), rBe; \ + XORQ rCo, rDu; \ + MOVQ _ki(iState), rBi; \ + MOVQ _mo(iState), rBo; \ + MOVQ _su(iState), rBu; \ + XORQ rDe, rBe; \ + ROLQ $44, rBe; \ + XORQ rDi, rBi; \ + XORQ rDa, rBa; \ + ROLQ $43, rBi; \ + \ + MOVQ rBe, rCa; \ + MOVQ rc, rT1; \ + ORQ rBi, rCa; \ + XORQ rBa, rT1; \ + XORQ rT1, rCa; \ + MOVQ rCa, _ba(oState); \ + \ + XORQ rDu, rBu; \ + ROLQ $14, rBu; \ + MOVQ rBa, rCu; \ + ANDQ rBe, rCu; \ + XORQ rBu, rCu; \ + MOVQ rCu, _bu(oState); \ + \ + XORQ rDo, rBo; \ + ROLQ $21, rBo; \ + MOVQ rBo, rT1; \ + ANDQ rBu, rT1; \ + XORQ rBi, rT1; \ + MOVQ rT1, _bi(oState); \ + \ + NOTQ rBi; \ + ORQ rBa, rBu; \ + ORQ rBo, rBi; \ + XORQ rBo, rBu; \ + XORQ rBe, rBi; \ + MOVQ rBu, _bo(oState); \ + MOVQ rBi, _be(oState); \ + B_RBI_RCE; \ + \ + /* Result g */ \ + MOVQ _gu(iState), rBe; \ + XORQ rDu, rBe; \ + MOVQ _ka(iState), rBi; \ + ROLQ $20, rBe; \ + XORQ rDa, rBi; \ + ROLQ $3, rBi; \ + MOVQ _bo(iState), rBa; \ + MOVQ rBe, rT1; \ + ORQ rBi, rT1; \ + XORQ rDo, rBa; \ + MOVQ _me(iState), rBo; \ + MOVQ _si(iState), rBu; \ + ROLQ $28, rBa; \ + XORQ rBa, rT1; \ + MOVQ rT1, _ga(oState); \ + G_RT1_RCA; \ + \ + XORQ rDe, rBo; \ + ROLQ $45, rBo; \ + MOVQ rBi, rT1; \ + ANDQ rBo, rT1; \ + XORQ rBe, rT1; \ + MOVQ rT1, _ge(oState); \ + G_RT1_RCE; \ + \ + XORQ rDi, rBu; \ + ROLQ $61, rBu; \ + MOVQ rBu, rT1; \ + ORQ rBa, rT1; \ + XORQ rBo, rT1; \ + MOVQ rT1, _go(oState); \ + \ + ANDQ rBe, rBa; \ + XORQ rBu, rBa; \ + MOVQ rBa, _gu(oState); \ + NOTQ rBu; \ + G_RBA_RCU; \ + \ + ORQ rBu, rBo; \ + XORQ rBi, rBo; \ + MOVQ rBo, _gi(oState); \ + \ + /* Result k */ \ + MOVQ _be(iState), rBa; \ + MOVQ _gi(iState), rBe; \ + MOVQ _ko(iState), rBi; \ + MOVQ _mu(iState), rBo; \ + MOVQ _sa(iState), rBu; \ + XORQ rDi, rBe; \ + ROLQ $6, rBe; \ + XORQ rDo, rBi; \ + ROLQ $25, rBi; \ + MOVQ rBe, rT1; \ + ORQ rBi, rT1; \ + XORQ rDe, rBa; \ + ROLQ $1, rBa; \ + XORQ rBa, rT1; \ + MOVQ rT1, _ka(oState); \ + K_RT1_RCA; \ + \ + XORQ rDu, rBo; \ + ROLQ $8, rBo; \ + MOVQ rBi, rT1; \ + ANDQ rBo, rT1; \ + XORQ rBe, rT1; \ + MOVQ rT1, _ke(oState); \ + K_RT1_RCE; \ + \ + XORQ rDa, rBu; \ + ROLQ $18, rBu; \ + NOTQ rBo; \ + MOVQ rBo, rT1; \ + ANDQ rBu, rT1; \ + XORQ rBi, rT1; \ + MOVQ rT1, _ki(oState); \ + \ + MOVQ rBu, rT1; \ + ORQ rBa, rT1; \ + XORQ rBo, rT1; \ + MOVQ rT1, _ko(oState); \ + \ + ANDQ rBe, rBa; \ + XORQ rBu, rBa; \ + MOVQ rBa, _ku(oState); \ + K_RBA_RCU; \ + \ + /* Result m */ \ + MOVQ _ga(iState), rBe; \ + XORQ rDa, rBe; \ + MOVQ _ke(iState), rBi; \ + ROLQ $36, rBe; \ + XORQ rDe, rBi; \ + MOVQ _bu(iState), rBa; \ + ROLQ $10, rBi; \ + MOVQ rBe, rT1; \ + MOVQ _mi(iState), rBo; \ + ANDQ rBi, rT1; \ + XORQ rDu, rBa; \ + MOVQ _so(iState), rBu; \ + ROLQ $27, rBa; \ + XORQ rBa, rT1; \ + MOVQ rT1, _ma(oState); \ + M_RT1_RCA; \ + \ + XORQ rDi, rBo; \ + ROLQ $15, rBo; \ + MOVQ rBi, rT1; \ + ORQ rBo, rT1; \ + XORQ rBe, rT1; \ + MOVQ rT1, _me(oState); \ + M_RT1_RCE; \ + \ + XORQ rDo, rBu; \ + ROLQ $56, rBu; \ + NOTQ rBo; \ + MOVQ rBo, rT1; \ + ORQ rBu, rT1; \ + XORQ rBi, rT1; \ + MOVQ rT1, _mi(oState); \ + \ + ORQ rBa, rBe; \ + XORQ rBu, rBe; \ + MOVQ rBe, _mu(oState); \ + \ + ANDQ rBa, rBu; \ + XORQ rBo, rBu; \ + MOVQ rBu, _mo(oState); \ + M_RBE_RCU; \ + \ + /* Result s */ \ + MOVQ _bi(iState), rBa; \ + MOVQ _go(iState), rBe; \ + MOVQ _ku(iState), rBi; \ + XORQ rDi, rBa; \ + MOVQ _ma(iState), rBo; \ + ROLQ $62, rBa; \ + XORQ rDo, rBe; \ + MOVQ _se(iState), rBu; \ + ROLQ $55, rBe; \ + \ + XORQ rDu, rBi; \ + MOVQ rBa, rDu; \ + XORQ rDe, rBu; \ + ROLQ $2, rBu; \ + ANDQ rBe, rDu; \ + XORQ rBu, rDu; \ + MOVQ rDu, _su(oState); \ + \ + ROLQ $39, rBi; \ + S_RDU_RCU; \ + NOTQ rBe; \ + XORQ rDa, rBo; \ + MOVQ rBe, rDa; \ + ANDQ rBi, rDa; \ + XORQ rBa, rDa; \ + MOVQ rDa, _sa(oState); \ + S_RDA_RCA; \ + \ + ROLQ $41, rBo; \ + MOVQ rBi, rDe; \ + ORQ rBo, rDe; \ + XORQ rBe, rDe; \ + MOVQ rDe, _se(oState); \ + S_RDE_RCE; \ + \ + MOVQ rBo, rDi; \ + MOVQ rBu, rDo; \ + ANDQ rBu, rDi; \ + ORQ rBa, rDo; \ + XORQ rBi, rDi; \ + XORQ rBo, rDo; \ + MOVQ rDi, _si(oState); \ + MOVQ rDo, _so(oState) \ + +// func keccakF1600(state *[25]uint64) +TEXT ·keccakF1600(SB), 0, $200-8 + MOVQ state+0(FP), rpState + + // Convert the user state into an internal state + NOTQ _be(rpState) + NOTQ _bi(rpState) + NOTQ _go(rpState) + NOTQ _ki(rpState) + NOTQ _mi(rpState) + NOTQ _sa(rpState) + + // Execute the KeccakF permutation + MOVQ _ba(rpState), rCa + MOVQ _be(rpState), rCe + MOVQ _bu(rpState), rCu + + XORQ _ga(rpState), rCa + XORQ _ge(rpState), rCe + XORQ _gu(rpState), rCu + + XORQ _ka(rpState), rCa + XORQ _ke(rpState), rCe + XORQ _ku(rpState), rCu + + XORQ _ma(rpState), rCa + XORQ _me(rpState), rCe + XORQ _mu(rpState), rCu + + XORQ _sa(rpState), rCa + XORQ _se(rpState), rCe + MOVQ _si(rpState), rDi + MOVQ _so(rpState), rDo + XORQ _su(rpState), rCu + + mKeccakRound(rpState, rpStack, $0x0000000000000001, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpStack, rpState, $0x0000000000008082, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpState, rpStack, $0x800000000000808a, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpStack, rpState, $0x8000000080008000, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpState, rpStack, $0x000000000000808b, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpStack, rpState, $0x0000000080000001, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpState, rpStack, $0x8000000080008081, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpStack, rpState, $0x8000000000008009, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpState, rpStack, $0x000000000000008a, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpStack, rpState, $0x0000000000000088, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpState, rpStack, $0x0000000080008009, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpStack, rpState, $0x000000008000000a, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpState, rpStack, $0x000000008000808b, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpStack, rpState, $0x800000000000008b, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpState, rpStack, $0x8000000000008089, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpStack, rpState, $0x8000000000008003, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpState, rpStack, $0x8000000000008002, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpStack, rpState, $0x8000000000000080, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpState, rpStack, $0x000000000000800a, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpStack, rpState, $0x800000008000000a, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpState, rpStack, $0x8000000080008081, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpStack, rpState, $0x8000000000008080, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpState, rpStack, $0x0000000080000001, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpStack, rpState, $0x8000000080008008, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP) + + // Revert the internal state to the user state + NOTQ _be(rpState) + NOTQ _bi(rpState) + NOTQ _go(rpState) + NOTQ _ki(rpState) + NOTQ _mi(rpState) + NOTQ _sa(rpState) + + RET diff --git a/vendor/golang.org/x/crypto/sha3/register.go b/vendor/golang.org/x/crypto/sha3/register.go new file mode 100644 index 0000000000..8b4453aac3 --- /dev/null +++ b/vendor/golang.org/x/crypto/sha3/register.go @@ -0,0 +1,19 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build go1.4 +// +build go1.4 + +package sha3 + +import ( + "crypto" +) + +func init() { + crypto.RegisterHash(crypto.SHA3_224, New224) + crypto.RegisterHash(crypto.SHA3_256, New256) + crypto.RegisterHash(crypto.SHA3_384, New384) + crypto.RegisterHash(crypto.SHA3_512, New512) +} diff --git a/vendor/golang.org/x/crypto/sha3/sha3.go b/vendor/golang.org/x/crypto/sha3/sha3.go new file mode 100644 index 0000000000..fa182beb40 --- /dev/null +++ b/vendor/golang.org/x/crypto/sha3/sha3.go @@ -0,0 +1,193 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package sha3 + +// spongeDirection indicates the direction bytes are flowing through the sponge. +type spongeDirection int + +const ( + // spongeAbsorbing indicates that the sponge is absorbing input. + spongeAbsorbing spongeDirection = iota + // spongeSqueezing indicates that the sponge is being squeezed. + spongeSqueezing +) + +const ( + // maxRate is the maximum size of the internal buffer. SHAKE-256 + // currently needs the largest buffer. + maxRate = 168 +) + +type state struct { + // Generic sponge components. + a [25]uint64 // main state of the hash + buf []byte // points into storage + rate int // the number of bytes of state to use + + // dsbyte contains the "domain separation" bits and the first bit of + // the padding. Sections 6.1 and 6.2 of [1] separate the outputs of the + // SHA-3 and SHAKE functions by appending bitstrings to the message. + // Using a little-endian bit-ordering convention, these are "01" for SHA-3 + // and "1111" for SHAKE, or 00000010b and 00001111b, respectively. Then the + // padding rule from section 5.1 is applied to pad the message to a multiple + // of the rate, which involves adding a "1" bit, zero or more "0" bits, and + // a final "1" bit. We merge the first "1" bit from the padding into dsbyte, + // giving 00000110b (0x06) and 00011111b (0x1f). + // [1] http://csrc.nist.gov/publications/drafts/fips-202/fips_202_draft.pdf + // "Draft FIPS 202: SHA-3 Standard: Permutation-Based Hash and + // Extendable-Output Functions (May 2014)" + dsbyte byte + + storage storageBuf + + // Specific to SHA-3 and SHAKE. + outputLen int // the default output size in bytes + state spongeDirection // whether the sponge is absorbing or squeezing +} + +// BlockSize returns the rate of sponge underlying this hash function. +func (d *state) BlockSize() int { return d.rate } + +// Size returns the output size of the hash function in bytes. +func (d *state) Size() int { return d.outputLen } + +// Reset clears the internal state by zeroing the sponge state and +// the byte buffer, and setting Sponge.state to absorbing. +func (d *state) Reset() { + // Zero the permutation's state. + for i := range d.a { + d.a[i] = 0 + } + d.state = spongeAbsorbing + d.buf = d.storage.asBytes()[:0] +} + +func (d *state) clone() *state { + ret := *d + if ret.state == spongeAbsorbing { + ret.buf = ret.storage.asBytes()[:len(ret.buf)] + } else { + ret.buf = ret.storage.asBytes()[d.rate-cap(d.buf) : d.rate] + } + + return &ret +} + +// permute applies the KeccakF-1600 permutation. It handles +// any input-output buffering. +func (d *state) permute() { + switch d.state { + case spongeAbsorbing: + // If we're absorbing, we need to xor the input into the state + // before applying the permutation. + xorIn(d, d.buf) + d.buf = d.storage.asBytes()[:0] + keccakF1600(&d.a) + case spongeSqueezing: + // If we're squeezing, we need to apply the permutation before + // copying more output. + keccakF1600(&d.a) + d.buf = d.storage.asBytes()[:d.rate] + copyOut(d, d.buf) + } +} + +// pads appends the domain separation bits in dsbyte, applies +// the multi-bitrate 10..1 padding rule, and permutes the state. +func (d *state) padAndPermute(dsbyte byte) { + if d.buf == nil { + d.buf = d.storage.asBytes()[:0] + } + // Pad with this instance's domain-separator bits. We know that there's + // at least one byte of space in d.buf because, if it were full, + // permute would have been called to empty it. dsbyte also contains the + // first one bit for the padding. See the comment in the state struct. + d.buf = append(d.buf, dsbyte) + zerosStart := len(d.buf) + d.buf = d.storage.asBytes()[:d.rate] + for i := zerosStart; i < d.rate; i++ { + d.buf[i] = 0 + } + // This adds the final one bit for the padding. Because of the way that + // bits are numbered from the LSB upwards, the final bit is the MSB of + // the last byte. + d.buf[d.rate-1] ^= 0x80 + // Apply the permutation + d.permute() + d.state = spongeSqueezing + d.buf = d.storage.asBytes()[:d.rate] + copyOut(d, d.buf) +} + +// Write absorbs more data into the hash's state. It produces an error +// if more data is written to the ShakeHash after writing +func (d *state) Write(p []byte) (written int, err error) { + if d.state != spongeAbsorbing { + panic("sha3: write to sponge after read") + } + if d.buf == nil { + d.buf = d.storage.asBytes()[:0] + } + written = len(p) + + for len(p) > 0 { + if len(d.buf) == 0 && len(p) >= d.rate { + // The fast path; absorb a full "rate" bytes of input and apply the permutation. + xorIn(d, p[:d.rate]) + p = p[d.rate:] + keccakF1600(&d.a) + } else { + // The slow path; buffer the input until we can fill the sponge, and then xor it in. + todo := d.rate - len(d.buf) + if todo > len(p) { + todo = len(p) + } + d.buf = append(d.buf, p[:todo]...) + p = p[todo:] + + // If the sponge is full, apply the permutation. + if len(d.buf) == d.rate { + d.permute() + } + } + } + + return +} + +// Read squeezes an arbitrary number of bytes from the sponge. +func (d *state) Read(out []byte) (n int, err error) { + // If we're still absorbing, pad and apply the permutation. + if d.state == spongeAbsorbing { + d.padAndPermute(d.dsbyte) + } + + n = len(out) + + // Now, do the squeezing. + for len(out) > 0 { + n := copy(out, d.buf) + d.buf = d.buf[n:] + out = out[n:] + + // Apply the permutation if we've squeezed the sponge dry. + if len(d.buf) == 0 { + d.permute() + } + } + + return +} + +// Sum applies padding to the hash state and then squeezes out the desired +// number of output bytes. +func (d *state) Sum(in []byte) []byte { + // Make a copy of the original hash so that caller can keep writing + // and summing. + dup := d.clone() + hash := make([]byte, dup.outputLen) + dup.Read(hash) + return append(in, hash...) +} diff --git a/vendor/golang.org/x/crypto/sha3/sha3_s390x.go b/vendor/golang.org/x/crypto/sha3/sha3_s390x.go new file mode 100644 index 0000000000..63a3edb4ce --- /dev/null +++ b/vendor/golang.org/x/crypto/sha3/sha3_s390x.go @@ -0,0 +1,287 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build gc && !purego +// +build gc,!purego + +package sha3 + +// This file contains code for using the 'compute intermediate +// message digest' (KIMD) and 'compute last message digest' (KLMD) +// instructions to compute SHA-3 and SHAKE hashes on IBM Z. + +import ( + "hash" + + "golang.org/x/sys/cpu" +) + +// codes represent 7-bit KIMD/KLMD function codes as defined in +// the Principles of Operation. +type code uint64 + +const ( + // function codes for KIMD/KLMD + sha3_224 code = 32 + sha3_256 = 33 + sha3_384 = 34 + sha3_512 = 35 + shake_128 = 36 + shake_256 = 37 + nopad = 0x100 +) + +// kimd is a wrapper for the 'compute intermediate message digest' instruction. +// src must be a multiple of the rate for the given function code. +// +//go:noescape +func kimd(function code, chain *[200]byte, src []byte) + +// klmd is a wrapper for the 'compute last message digest' instruction. +// src padding is handled by the instruction. +// +//go:noescape +func klmd(function code, chain *[200]byte, dst, src []byte) + +type asmState struct { + a [200]byte // 1600 bit state + buf []byte // care must be taken to ensure cap(buf) is a multiple of rate + rate int // equivalent to block size + storage [3072]byte // underlying storage for buf + outputLen int // output length if fixed, 0 if not + function code // KIMD/KLMD function code + state spongeDirection // whether the sponge is absorbing or squeezing +} + +func newAsmState(function code) *asmState { + var s asmState + s.function = function + switch function { + case sha3_224: + s.rate = 144 + s.outputLen = 28 + case sha3_256: + s.rate = 136 + s.outputLen = 32 + case sha3_384: + s.rate = 104 + s.outputLen = 48 + case sha3_512: + s.rate = 72 + s.outputLen = 64 + case shake_128: + s.rate = 168 + case shake_256: + s.rate = 136 + default: + panic("sha3: unrecognized function code") + } + + // limit s.buf size to a multiple of s.rate + s.resetBuf() + return &s +} + +func (s *asmState) clone() *asmState { + c := *s + c.buf = c.storage[:len(s.buf):cap(s.buf)] + return &c +} + +// copyIntoBuf copies b into buf. It will panic if there is not enough space to +// store all of b. +func (s *asmState) copyIntoBuf(b []byte) { + bufLen := len(s.buf) + s.buf = s.buf[:len(s.buf)+len(b)] + copy(s.buf[bufLen:], b) +} + +// resetBuf points buf at storage, sets the length to 0 and sets cap to be a +// multiple of the rate. +func (s *asmState) resetBuf() { + max := (cap(s.storage) / s.rate) * s.rate + s.buf = s.storage[:0:max] +} + +// Write (via the embedded io.Writer interface) adds more data to the running hash. +// It never returns an error. +func (s *asmState) Write(b []byte) (int, error) { + if s.state != spongeAbsorbing { + panic("sha3: write to sponge after read") + } + length := len(b) + for len(b) > 0 { + if len(s.buf) == 0 && len(b) >= cap(s.buf) { + // Hash the data directly and push any remaining bytes + // into the buffer. + remainder := len(b) % s.rate + kimd(s.function, &s.a, b[:len(b)-remainder]) + if remainder != 0 { + s.copyIntoBuf(b[len(b)-remainder:]) + } + return length, nil + } + + if len(s.buf) == cap(s.buf) { + // flush the buffer + kimd(s.function, &s.a, s.buf) + s.buf = s.buf[:0] + } + + // copy as much as we can into the buffer + n := len(b) + if len(b) > cap(s.buf)-len(s.buf) { + n = cap(s.buf) - len(s.buf) + } + s.copyIntoBuf(b[:n]) + b = b[n:] + } + return length, nil +} + +// Read squeezes an arbitrary number of bytes from the sponge. +func (s *asmState) Read(out []byte) (n int, err error) { + n = len(out) + + // need to pad if we were absorbing + if s.state == spongeAbsorbing { + s.state = spongeSqueezing + + // write hash directly into out if possible + if len(out)%s.rate == 0 { + klmd(s.function, &s.a, out, s.buf) // len(out) may be 0 + s.buf = s.buf[:0] + return + } + + // write hash into buffer + max := cap(s.buf) + if max > len(out) { + max = (len(out)/s.rate)*s.rate + s.rate + } + klmd(s.function, &s.a, s.buf[:max], s.buf) + s.buf = s.buf[:max] + } + + for len(out) > 0 { + // flush the buffer + if len(s.buf) != 0 { + c := copy(out, s.buf) + out = out[c:] + s.buf = s.buf[c:] + continue + } + + // write hash directly into out if possible + if len(out)%s.rate == 0 { + klmd(s.function|nopad, &s.a, out, nil) + return + } + + // write hash into buffer + s.resetBuf() + if cap(s.buf) > len(out) { + s.buf = s.buf[:(len(out)/s.rate)*s.rate+s.rate] + } + klmd(s.function|nopad, &s.a, s.buf, nil) + } + return +} + +// Sum appends the current hash to b and returns the resulting slice. +// It does not change the underlying hash state. +func (s *asmState) Sum(b []byte) []byte { + if s.outputLen == 0 { + panic("sha3: cannot call Sum on SHAKE functions") + } + + // Copy the state to preserve the original. + a := s.a + + // Hash the buffer. Note that we don't clear it because we + // aren't updating the state. + klmd(s.function, &a, nil, s.buf) + return append(b, a[:s.outputLen]...) +} + +// Reset resets the Hash to its initial state. +func (s *asmState) Reset() { + for i := range s.a { + s.a[i] = 0 + } + s.resetBuf() + s.state = spongeAbsorbing +} + +// Size returns the number of bytes Sum will return. +func (s *asmState) Size() int { + return s.outputLen +} + +// BlockSize returns the hash's underlying block size. +// The Write method must be able to accept any amount +// of data, but it may operate more efficiently if all writes +// are a multiple of the block size. +func (s *asmState) BlockSize() int { + return s.rate +} + +// Clone returns a copy of the ShakeHash in its current state. +func (s *asmState) Clone() ShakeHash { + return s.clone() +} + +// new224Asm returns an assembly implementation of SHA3-224 if available, +// otherwise it returns nil. +func new224Asm() hash.Hash { + if cpu.S390X.HasSHA3 { + return newAsmState(sha3_224) + } + return nil +} + +// new256Asm returns an assembly implementation of SHA3-256 if available, +// otherwise it returns nil. +func new256Asm() hash.Hash { + if cpu.S390X.HasSHA3 { + return newAsmState(sha3_256) + } + return nil +} + +// new384Asm returns an assembly implementation of SHA3-384 if available, +// otherwise it returns nil. +func new384Asm() hash.Hash { + if cpu.S390X.HasSHA3 { + return newAsmState(sha3_384) + } + return nil +} + +// new512Asm returns an assembly implementation of SHA3-512 if available, +// otherwise it returns nil. +func new512Asm() hash.Hash { + if cpu.S390X.HasSHA3 { + return newAsmState(sha3_512) + } + return nil +} + +// newShake128Asm returns an assembly implementation of SHAKE-128 if available, +// otherwise it returns nil. +func newShake128Asm() ShakeHash { + if cpu.S390X.HasSHA3 { + return newAsmState(shake_128) + } + return nil +} + +// newShake256Asm returns an assembly implementation of SHAKE-256 if available, +// otherwise it returns nil. +func newShake256Asm() ShakeHash { + if cpu.S390X.HasSHA3 { + return newAsmState(shake_256) + } + return nil +} diff --git a/vendor/golang.org/x/crypto/sha3/sha3_s390x.s b/vendor/golang.org/x/crypto/sha3/sha3_s390x.s new file mode 100644 index 0000000000..a0e051b045 --- /dev/null +++ b/vendor/golang.org/x/crypto/sha3/sha3_s390x.s @@ -0,0 +1,34 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build gc && !purego +// +build gc,!purego + +#include "textflag.h" + +// func kimd(function code, chain *[200]byte, src []byte) +TEXT ·kimd(SB), NOFRAME|NOSPLIT, $0-40 + MOVD function+0(FP), R0 + MOVD chain+8(FP), R1 + LMG src+16(FP), R2, R3 // R2=base, R3=len + +continue: + WORD $0xB93E0002 // KIMD --, R2 + BVS continue // continue if interrupted + MOVD $0, R0 // reset R0 for pre-go1.8 compilers + RET + +// func klmd(function code, chain *[200]byte, dst, src []byte) +TEXT ·klmd(SB), NOFRAME|NOSPLIT, $0-64 + // TODO: SHAKE support + MOVD function+0(FP), R0 + MOVD chain+8(FP), R1 + LMG dst+16(FP), R2, R3 // R2=base, R3=len + LMG src+40(FP), R4, R5 // R4=base, R5=len + +continue: + WORD $0xB93F0024 // KLMD R2, R4 + BVS continue // continue if interrupted + MOVD $0, R0 // reset R0 for pre-go1.8 compilers + RET diff --git a/vendor/golang.org/x/crypto/sha3/shake.go b/vendor/golang.org/x/crypto/sha3/shake.go new file mode 100644 index 0000000000..d7be2954ab --- /dev/null +++ b/vendor/golang.org/x/crypto/sha3/shake.go @@ -0,0 +1,173 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package sha3 + +// This file defines the ShakeHash interface, and provides +// functions for creating SHAKE and cSHAKE instances, as well as utility +// functions for hashing bytes to arbitrary-length output. +// +// +// SHAKE implementation is based on FIPS PUB 202 [1] +// cSHAKE implementations is based on NIST SP 800-185 [2] +// +// [1] https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf +// [2] https://doi.org/10.6028/NIST.SP.800-185 + +import ( + "encoding/binary" + "io" +) + +// ShakeHash defines the interface to hash functions that +// support arbitrary-length output. +type ShakeHash interface { + // Write absorbs more data into the hash's state. It panics if input is + // written to it after output has been read from it. + io.Writer + + // Read reads more output from the hash; reading affects the hash's + // state. (ShakeHash.Read is thus very different from Hash.Sum) + // It never returns an error. + io.Reader + + // Clone returns a copy of the ShakeHash in its current state. + Clone() ShakeHash + + // Reset resets the ShakeHash to its initial state. + Reset() +} + +// cSHAKE specific context +type cshakeState struct { + *state // SHA-3 state context and Read/Write operations + + // initBlock is the cSHAKE specific initialization set of bytes. It is initialized + // by newCShake function and stores concatenation of N followed by S, encoded + // by the method specified in 3.3 of [1]. + // It is stored here in order for Reset() to be able to put context into + // initial state. + initBlock []byte +} + +// Consts for configuring initial SHA-3 state +const ( + dsbyteShake = 0x1f + dsbyteCShake = 0x04 + rate128 = 168 + rate256 = 136 +) + +func bytepad(input []byte, w int) []byte { + // leftEncode always returns max 9 bytes + buf := make([]byte, 0, 9+len(input)+w) + buf = append(buf, leftEncode(uint64(w))...) + buf = append(buf, input...) + padlen := w - (len(buf) % w) + return append(buf, make([]byte, padlen)...) +} + +func leftEncode(value uint64) []byte { + var b [9]byte + binary.BigEndian.PutUint64(b[1:], value) + // Trim all but last leading zero bytes + i := byte(1) + for i < 8 && b[i] == 0 { + i++ + } + // Prepend number of encoded bytes + b[i-1] = 9 - i + return b[i-1:] +} + +func newCShake(N, S []byte, rate int, dsbyte byte) ShakeHash { + c := cshakeState{state: &state{rate: rate, dsbyte: dsbyte}} + + // leftEncode returns max 9 bytes + c.initBlock = make([]byte, 0, 9*2+len(N)+len(S)) + c.initBlock = append(c.initBlock, leftEncode(uint64(len(N)*8))...) + c.initBlock = append(c.initBlock, N...) + c.initBlock = append(c.initBlock, leftEncode(uint64(len(S)*8))...) + c.initBlock = append(c.initBlock, S...) + c.Write(bytepad(c.initBlock, c.rate)) + return &c +} + +// Reset resets the hash to initial state. +func (c *cshakeState) Reset() { + c.state.Reset() + c.Write(bytepad(c.initBlock, c.rate)) +} + +// Clone returns copy of a cSHAKE context within its current state. +func (c *cshakeState) Clone() ShakeHash { + b := make([]byte, len(c.initBlock)) + copy(b, c.initBlock) + return &cshakeState{state: c.clone(), initBlock: b} +} + +// Clone returns copy of SHAKE context within its current state. +func (c *state) Clone() ShakeHash { + return c.clone() +} + +// NewShake128 creates a new SHAKE128 variable-output-length ShakeHash. +// Its generic security strength is 128 bits against all attacks if at +// least 32 bytes of its output are used. +func NewShake128() ShakeHash { + if h := newShake128Asm(); h != nil { + return h + } + return &state{rate: rate128, dsbyte: dsbyteShake} +} + +// NewShake256 creates a new SHAKE256 variable-output-length ShakeHash. +// Its generic security strength is 256 bits against all attacks if +// at least 64 bytes of its output are used. +func NewShake256() ShakeHash { + if h := newShake256Asm(); h != nil { + return h + } + return &state{rate: rate256, dsbyte: dsbyteShake} +} + +// NewCShake128 creates a new instance of cSHAKE128 variable-output-length ShakeHash, +// a customizable variant of SHAKE128. +// N is used to define functions based on cSHAKE, it can be empty when plain cSHAKE is +// desired. S is a customization byte string used for domain separation - two cSHAKE +// computations on same input with different S yield unrelated outputs. +// When N and S are both empty, this is equivalent to NewShake128. +func NewCShake128(N, S []byte) ShakeHash { + if len(N) == 0 && len(S) == 0 { + return NewShake128() + } + return newCShake(N, S, rate128, dsbyteCShake) +} + +// NewCShake256 creates a new instance of cSHAKE256 variable-output-length ShakeHash, +// a customizable variant of SHAKE256. +// N is used to define functions based on cSHAKE, it can be empty when plain cSHAKE is +// desired. S is a customization byte string used for domain separation - two cSHAKE +// computations on same input with different S yield unrelated outputs. +// When N and S are both empty, this is equivalent to NewShake256. +func NewCShake256(N, S []byte) ShakeHash { + if len(N) == 0 && len(S) == 0 { + return NewShake256() + } + return newCShake(N, S, rate256, dsbyteCShake) +} + +// ShakeSum128 writes an arbitrary-length digest of data into hash. +func ShakeSum128(hash, data []byte) { + h := NewShake128() + h.Write(data) + h.Read(hash) +} + +// ShakeSum256 writes an arbitrary-length digest of data into hash. +func ShakeSum256(hash, data []byte) { + h := NewShake256() + h.Write(data) + h.Read(hash) +} diff --git a/vendor/golang.org/x/crypto/sha3/shake_generic.go b/vendor/golang.org/x/crypto/sha3/shake_generic.go new file mode 100644 index 0000000000..5c0710ef98 --- /dev/null +++ b/vendor/golang.org/x/crypto/sha3/shake_generic.go @@ -0,0 +1,20 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !gc || purego || !s390x +// +build !gc purego !s390x + +package sha3 + +// newShake128Asm returns an assembly implementation of SHAKE-128 if available, +// otherwise it returns nil. +func newShake128Asm() ShakeHash { + return nil +} + +// newShake256Asm returns an assembly implementation of SHAKE-256 if available, +// otherwise it returns nil. +func newShake256Asm() ShakeHash { + return nil +} diff --git a/vendor/golang.org/x/crypto/sha3/xor.go b/vendor/golang.org/x/crypto/sha3/xor.go new file mode 100644 index 0000000000..59c8eb9418 --- /dev/null +++ b/vendor/golang.org/x/crypto/sha3/xor.go @@ -0,0 +1,24 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build (!amd64 && !386 && !ppc64le) || purego +// +build !amd64,!386,!ppc64le purego + +package sha3 + +// A storageBuf is an aligned array of maxRate bytes. +type storageBuf [maxRate]byte + +func (b *storageBuf) asBytes() *[maxRate]byte { + return (*[maxRate]byte)(b) +} + +var ( + xorIn = xorInGeneric + copyOut = copyOutGeneric + xorInUnaligned = xorInGeneric + copyOutUnaligned = copyOutGeneric +) + +const xorImplementationUnaligned = "generic" diff --git a/vendor/golang.org/x/crypto/sha3/xor_generic.go b/vendor/golang.org/x/crypto/sha3/xor_generic.go new file mode 100644 index 0000000000..8d94771127 --- /dev/null +++ b/vendor/golang.org/x/crypto/sha3/xor_generic.go @@ -0,0 +1,28 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package sha3 + +import "encoding/binary" + +// xorInGeneric xors the bytes in buf into the state; it +// makes no non-portable assumptions about memory layout +// or alignment. +func xorInGeneric(d *state, buf []byte) { + n := len(buf) / 8 + + for i := 0; i < n; i++ { + a := binary.LittleEndian.Uint64(buf) + d.a[i] ^= a + buf = buf[8:] + } +} + +// copyOutGeneric copies uint64s to a byte buffer. +func copyOutGeneric(d *state, b []byte) { + for i := 0; len(b) >= 8; i++ { + binary.LittleEndian.PutUint64(b, d.a[i]) + b = b[8:] + } +} diff --git a/vendor/golang.org/x/crypto/sha3/xor_unaligned.go b/vendor/golang.org/x/crypto/sha3/xor_unaligned.go new file mode 100644 index 0000000000..1ce606246d --- /dev/null +++ b/vendor/golang.org/x/crypto/sha3/xor_unaligned.go @@ -0,0 +1,68 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build (amd64 || 386 || ppc64le) && !purego +// +build amd64 386 ppc64le +// +build !purego + +package sha3 + +import "unsafe" + +// A storageBuf is an aligned array of maxRate bytes. +type storageBuf [maxRate / 8]uint64 + +func (b *storageBuf) asBytes() *[maxRate]byte { + return (*[maxRate]byte)(unsafe.Pointer(b)) +} + +// xorInUnaligned uses unaligned reads and writes to update d.a to contain d.a +// XOR buf. +func xorInUnaligned(d *state, buf []byte) { + n := len(buf) + bw := (*[maxRate / 8]uint64)(unsafe.Pointer(&buf[0]))[: n/8 : n/8] + if n >= 72 { + d.a[0] ^= bw[0] + d.a[1] ^= bw[1] + d.a[2] ^= bw[2] + d.a[3] ^= bw[3] + d.a[4] ^= bw[4] + d.a[5] ^= bw[5] + d.a[6] ^= bw[6] + d.a[7] ^= bw[7] + d.a[8] ^= bw[8] + } + if n >= 104 { + d.a[9] ^= bw[9] + d.a[10] ^= bw[10] + d.a[11] ^= bw[11] + d.a[12] ^= bw[12] + } + if n >= 136 { + d.a[13] ^= bw[13] + d.a[14] ^= bw[14] + d.a[15] ^= bw[15] + d.a[16] ^= bw[16] + } + if n >= 144 { + d.a[17] ^= bw[17] + } + if n >= 168 { + d.a[18] ^= bw[18] + d.a[19] ^= bw[19] + d.a[20] ^= bw[20] + } +} + +func copyOutUnaligned(d *state, buf []byte) { + ab := (*[maxRate]uint8)(unsafe.Pointer(&d.a[0])) + copy(buf, ab[:]) +} + +var ( + xorIn = xorInUnaligned + copyOut = copyOutUnaligned +) + +const xorImplementationUnaligned = "unaligned" diff --git a/vendor/golang.org/x/net/internal/socks/client.go b/vendor/golang.org/x/net/internal/socks/client.go new file mode 100644 index 0000000000..3d6f516a59 --- /dev/null +++ b/vendor/golang.org/x/net/internal/socks/client.go @@ -0,0 +1,168 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package socks + +import ( + "context" + "errors" + "io" + "net" + "strconv" + "time" +) + +var ( + noDeadline = time.Time{} + aLongTimeAgo = time.Unix(1, 0) +) + +func (d *Dialer) connect(ctx context.Context, c net.Conn, address string) (_ net.Addr, ctxErr error) { + host, port, err := splitHostPort(address) + if err != nil { + return nil, err + } + if deadline, ok := ctx.Deadline(); ok && !deadline.IsZero() { + c.SetDeadline(deadline) + defer c.SetDeadline(noDeadline) + } + if ctx != context.Background() { + errCh := make(chan error, 1) + done := make(chan struct{}) + defer func() { + close(done) + if ctxErr == nil { + ctxErr = <-errCh + } + }() + go func() { + select { + case <-ctx.Done(): + c.SetDeadline(aLongTimeAgo) + errCh <- ctx.Err() + case <-done: + errCh <- nil + } + }() + } + + b := make([]byte, 0, 6+len(host)) // the size here is just an estimate + b = append(b, Version5) + if len(d.AuthMethods) == 0 || d.Authenticate == nil { + b = append(b, 1, byte(AuthMethodNotRequired)) + } else { + ams := d.AuthMethods + if len(ams) > 255 { + return nil, errors.New("too many authentication methods") + } + b = append(b, byte(len(ams))) + for _, am := range ams { + b = append(b, byte(am)) + } + } + if _, ctxErr = c.Write(b); ctxErr != nil { + return + } + + if _, ctxErr = io.ReadFull(c, b[:2]); ctxErr != nil { + return + } + if b[0] != Version5 { + return nil, errors.New("unexpected protocol version " + strconv.Itoa(int(b[0]))) + } + am := AuthMethod(b[1]) + if am == AuthMethodNoAcceptableMethods { + return nil, errors.New("no acceptable authentication methods") + } + if d.Authenticate != nil { + if ctxErr = d.Authenticate(ctx, c, am); ctxErr != nil { + return + } + } + + b = b[:0] + b = append(b, Version5, byte(d.cmd), 0) + if ip := net.ParseIP(host); ip != nil { + if ip4 := ip.To4(); ip4 != nil { + b = append(b, AddrTypeIPv4) + b = append(b, ip4...) + } else if ip6 := ip.To16(); ip6 != nil { + b = append(b, AddrTypeIPv6) + b = append(b, ip6...) + } else { + return nil, errors.New("unknown address type") + } + } else { + if len(host) > 255 { + return nil, errors.New("FQDN too long") + } + b = append(b, AddrTypeFQDN) + b = append(b, byte(len(host))) + b = append(b, host...) + } + b = append(b, byte(port>>8), byte(port)) + if _, ctxErr = c.Write(b); ctxErr != nil { + return + } + + if _, ctxErr = io.ReadFull(c, b[:4]); ctxErr != nil { + return + } + if b[0] != Version5 { + return nil, errors.New("unexpected protocol version " + strconv.Itoa(int(b[0]))) + } + if cmdErr := Reply(b[1]); cmdErr != StatusSucceeded { + return nil, errors.New("unknown error " + cmdErr.String()) + } + if b[2] != 0 { + return nil, errors.New("non-zero reserved field") + } + l := 2 + var a Addr + switch b[3] { + case AddrTypeIPv4: + l += net.IPv4len + a.IP = make(net.IP, net.IPv4len) + case AddrTypeIPv6: + l += net.IPv6len + a.IP = make(net.IP, net.IPv6len) + case AddrTypeFQDN: + if _, err := io.ReadFull(c, b[:1]); err != nil { + return nil, err + } + l += int(b[0]) + default: + return nil, errors.New("unknown address type " + strconv.Itoa(int(b[3]))) + } + if cap(b) < l { + b = make([]byte, l) + } else { + b = b[:l] + } + if _, ctxErr = io.ReadFull(c, b); ctxErr != nil { + return + } + if a.IP != nil { + copy(a.IP, b) + } else { + a.Name = string(b[:len(b)-2]) + } + a.Port = int(b[len(b)-2])<<8 | int(b[len(b)-1]) + return &a, nil +} + +func splitHostPort(address string) (string, int, error) { + host, port, err := net.SplitHostPort(address) + if err != nil { + return "", 0, err + } + portnum, err := strconv.Atoi(port) + if err != nil { + return "", 0, err + } + if 1 > portnum || portnum > 0xffff { + return "", 0, errors.New("port number out of range " + port) + } + return host, portnum, nil +} diff --git a/vendor/golang.org/x/net/internal/socks/socks.go b/vendor/golang.org/x/net/internal/socks/socks.go new file mode 100644 index 0000000000..84fcc32b63 --- /dev/null +++ b/vendor/golang.org/x/net/internal/socks/socks.go @@ -0,0 +1,317 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package socks provides a SOCKS version 5 client implementation. +// +// SOCKS protocol version 5 is defined in RFC 1928. +// Username/Password authentication for SOCKS version 5 is defined in +// RFC 1929. +package socks + +import ( + "context" + "errors" + "io" + "net" + "strconv" +) + +// A Command represents a SOCKS command. +type Command int + +func (cmd Command) String() string { + switch cmd { + case CmdConnect: + return "socks connect" + case cmdBind: + return "socks bind" + default: + return "socks " + strconv.Itoa(int(cmd)) + } +} + +// An AuthMethod represents a SOCKS authentication method. +type AuthMethod int + +// A Reply represents a SOCKS command reply code. +type Reply int + +func (code Reply) String() string { + switch code { + case StatusSucceeded: + return "succeeded" + case 0x01: + return "general SOCKS server failure" + case 0x02: + return "connection not allowed by ruleset" + case 0x03: + return "network unreachable" + case 0x04: + return "host unreachable" + case 0x05: + return "connection refused" + case 0x06: + return "TTL expired" + case 0x07: + return "command not supported" + case 0x08: + return "address type not supported" + default: + return "unknown code: " + strconv.Itoa(int(code)) + } +} + +// Wire protocol constants. +const ( + Version5 = 0x05 + + AddrTypeIPv4 = 0x01 + AddrTypeFQDN = 0x03 + AddrTypeIPv6 = 0x04 + + CmdConnect Command = 0x01 // establishes an active-open forward proxy connection + cmdBind Command = 0x02 // establishes a passive-open forward proxy connection + + AuthMethodNotRequired AuthMethod = 0x00 // no authentication required + AuthMethodUsernamePassword AuthMethod = 0x02 // use username/password + AuthMethodNoAcceptableMethods AuthMethod = 0xff // no acceptable authentication methods + + StatusSucceeded Reply = 0x00 +) + +// An Addr represents a SOCKS-specific address. +// Either Name or IP is used exclusively. +type Addr struct { + Name string // fully-qualified domain name + IP net.IP + Port int +} + +func (a *Addr) Network() string { return "socks" } + +func (a *Addr) String() string { + if a == nil { + return "" + } + port := strconv.Itoa(a.Port) + if a.IP == nil { + return net.JoinHostPort(a.Name, port) + } + return net.JoinHostPort(a.IP.String(), port) +} + +// A Conn represents a forward proxy connection. +type Conn struct { + net.Conn + + boundAddr net.Addr +} + +// BoundAddr returns the address assigned by the proxy server for +// connecting to the command target address from the proxy server. +func (c *Conn) BoundAddr() net.Addr { + if c == nil { + return nil + } + return c.boundAddr +} + +// A Dialer holds SOCKS-specific options. +type Dialer struct { + cmd Command // either CmdConnect or cmdBind + proxyNetwork string // network between a proxy server and a client + proxyAddress string // proxy server address + + // ProxyDial specifies the optional dial function for + // establishing the transport connection. + ProxyDial func(context.Context, string, string) (net.Conn, error) + + // AuthMethods specifies the list of request authentication + // methods. + // If empty, SOCKS client requests only AuthMethodNotRequired. + AuthMethods []AuthMethod + + // Authenticate specifies the optional authentication + // function. It must be non-nil when AuthMethods is not empty. + // It must return an error when the authentication is failed. + Authenticate func(context.Context, io.ReadWriter, AuthMethod) error +} + +// DialContext connects to the provided address on the provided +// network. +// +// The returned error value may be a net.OpError. When the Op field of +// net.OpError contains "socks", the Source field contains a proxy +// server address and the Addr field contains a command target +// address. +// +// See func Dial of the net package of standard library for a +// description of the network and address parameters. +func (d *Dialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) { + if err := d.validateTarget(network, address); err != nil { + proxy, dst, _ := d.pathAddrs(address) + return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err} + } + if ctx == nil { + proxy, dst, _ := d.pathAddrs(address) + return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: errors.New("nil context")} + } + var err error + var c net.Conn + if d.ProxyDial != nil { + c, err = d.ProxyDial(ctx, d.proxyNetwork, d.proxyAddress) + } else { + var dd net.Dialer + c, err = dd.DialContext(ctx, d.proxyNetwork, d.proxyAddress) + } + if err != nil { + proxy, dst, _ := d.pathAddrs(address) + return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err} + } + a, err := d.connect(ctx, c, address) + if err != nil { + c.Close() + proxy, dst, _ := d.pathAddrs(address) + return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err} + } + return &Conn{Conn: c, boundAddr: a}, nil +} + +// DialWithConn initiates a connection from SOCKS server to the target +// network and address using the connection c that is already +// connected to the SOCKS server. +// +// It returns the connection's local address assigned by the SOCKS +// server. +func (d *Dialer) DialWithConn(ctx context.Context, c net.Conn, network, address string) (net.Addr, error) { + if err := d.validateTarget(network, address); err != nil { + proxy, dst, _ := d.pathAddrs(address) + return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err} + } + if ctx == nil { + proxy, dst, _ := d.pathAddrs(address) + return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: errors.New("nil context")} + } + a, err := d.connect(ctx, c, address) + if err != nil { + proxy, dst, _ := d.pathAddrs(address) + return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err} + } + return a, nil +} + +// Dial connects to the provided address on the provided network. +// +// Unlike DialContext, it returns a raw transport connection instead +// of a forward proxy connection. +// +// Deprecated: Use DialContext or DialWithConn instead. +func (d *Dialer) Dial(network, address string) (net.Conn, error) { + if err := d.validateTarget(network, address); err != nil { + proxy, dst, _ := d.pathAddrs(address) + return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err} + } + var err error + var c net.Conn + if d.ProxyDial != nil { + c, err = d.ProxyDial(context.Background(), d.proxyNetwork, d.proxyAddress) + } else { + c, err = net.Dial(d.proxyNetwork, d.proxyAddress) + } + if err != nil { + proxy, dst, _ := d.pathAddrs(address) + return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err} + } + if _, err := d.DialWithConn(context.Background(), c, network, address); err != nil { + c.Close() + return nil, err + } + return c, nil +} + +func (d *Dialer) validateTarget(network, address string) error { + switch network { + case "tcp", "tcp6", "tcp4": + default: + return errors.New("network not implemented") + } + switch d.cmd { + case CmdConnect, cmdBind: + default: + return errors.New("command not implemented") + } + return nil +} + +func (d *Dialer) pathAddrs(address string) (proxy, dst net.Addr, err error) { + for i, s := range []string{d.proxyAddress, address} { + host, port, err := splitHostPort(s) + if err != nil { + return nil, nil, err + } + a := &Addr{Port: port} + a.IP = net.ParseIP(host) + if a.IP == nil { + a.Name = host + } + if i == 0 { + proxy = a + } else { + dst = a + } + } + return +} + +// NewDialer returns a new Dialer that dials through the provided +// proxy server's network and address. +func NewDialer(network, address string) *Dialer { + return &Dialer{proxyNetwork: network, proxyAddress: address, cmd: CmdConnect} +} + +const ( + authUsernamePasswordVersion = 0x01 + authStatusSucceeded = 0x00 +) + +// UsernamePassword are the credentials for the username/password +// authentication method. +type UsernamePassword struct { + Username string + Password string +} + +// Authenticate authenticates a pair of username and password with the +// proxy server. +func (up *UsernamePassword) Authenticate(ctx context.Context, rw io.ReadWriter, auth AuthMethod) error { + switch auth { + case AuthMethodNotRequired: + return nil + case AuthMethodUsernamePassword: + if len(up.Username) == 0 || len(up.Username) > 255 || len(up.Password) > 255 { + return errors.New("invalid username/password") + } + b := []byte{authUsernamePasswordVersion} + b = append(b, byte(len(up.Username))) + b = append(b, up.Username...) + b = append(b, byte(len(up.Password))) + b = append(b, up.Password...) + // TODO(mikio): handle IO deadlines and cancelation if + // necessary + if _, err := rw.Write(b); err != nil { + return err + } + if _, err := io.ReadFull(rw, b[:2]); err != nil { + return err + } + if b[0] != authUsernamePasswordVersion { + return errors.New("invalid username/password version") + } + if b[1] != authStatusSucceeded { + return errors.New("username/password authentication failed") + } + return nil + } + return errors.New("unsupported authentication method " + strconv.Itoa(int(auth))) +} diff --git a/vendor/golang.org/x/net/proxy/dial.go b/vendor/golang.org/x/net/proxy/dial.go new file mode 100644 index 0000000000..811c2e4e96 --- /dev/null +++ b/vendor/golang.org/x/net/proxy/dial.go @@ -0,0 +1,54 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package proxy + +import ( + "context" + "net" +) + +// A ContextDialer dials using a context. +type ContextDialer interface { + DialContext(ctx context.Context, network, address string) (net.Conn, error) +} + +// Dial works like DialContext on net.Dialer but using a dialer returned by FromEnvironment. +// +// The passed ctx is only used for returning the Conn, not the lifetime of the Conn. +// +// Custom dialers (registered via RegisterDialerType) that do not implement ContextDialer +// can leak a goroutine for as long as it takes the underlying Dialer implementation to timeout. +// +// A Conn returned from a successful Dial after the context has been cancelled will be immediately closed. +func Dial(ctx context.Context, network, address string) (net.Conn, error) { + d := FromEnvironment() + if xd, ok := d.(ContextDialer); ok { + return xd.DialContext(ctx, network, address) + } + return dialContext(ctx, d, network, address) +} + +// WARNING: this can leak a goroutine for as long as the underlying Dialer implementation takes to timeout +// A Conn returned from a successful Dial after the context has been cancelled will be immediately closed. +func dialContext(ctx context.Context, d Dialer, network, address string) (net.Conn, error) { + var ( + conn net.Conn + done = make(chan struct{}, 1) + err error + ) + go func() { + conn, err = d.Dial(network, address) + close(done) + if conn != nil && ctx.Err() != nil { + conn.Close() + } + }() + select { + case <-ctx.Done(): + err = ctx.Err() + case <-done: + } + return conn, err +} diff --git a/vendor/golang.org/x/net/proxy/direct.go b/vendor/golang.org/x/net/proxy/direct.go new file mode 100644 index 0000000000..3d66bdef9d --- /dev/null +++ b/vendor/golang.org/x/net/proxy/direct.go @@ -0,0 +1,31 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package proxy + +import ( + "context" + "net" +) + +type direct struct{} + +// Direct implements Dialer by making network connections directly using net.Dial or net.DialContext. +var Direct = direct{} + +var ( + _ Dialer = Direct + _ ContextDialer = Direct +) + +// Dial directly invokes net.Dial with the supplied parameters. +func (direct) Dial(network, addr string) (net.Conn, error) { + return net.Dial(network, addr) +} + +// DialContext instantiates a net.Dialer and invokes its DialContext receiver with the supplied parameters. +func (direct) DialContext(ctx context.Context, network, addr string) (net.Conn, error) { + var d net.Dialer + return d.DialContext(ctx, network, addr) +} diff --git a/vendor/golang.org/x/net/proxy/per_host.go b/vendor/golang.org/x/net/proxy/per_host.go new file mode 100644 index 0000000000..573fe79e86 --- /dev/null +++ b/vendor/golang.org/x/net/proxy/per_host.go @@ -0,0 +1,155 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package proxy + +import ( + "context" + "net" + "strings" +) + +// A PerHost directs connections to a default Dialer unless the host name +// requested matches one of a number of exceptions. +type PerHost struct { + def, bypass Dialer + + bypassNetworks []*net.IPNet + bypassIPs []net.IP + bypassZones []string + bypassHosts []string +} + +// NewPerHost returns a PerHost Dialer that directs connections to either +// defaultDialer or bypass, depending on whether the connection matches one of +// the configured rules. +func NewPerHost(defaultDialer, bypass Dialer) *PerHost { + return &PerHost{ + def: defaultDialer, + bypass: bypass, + } +} + +// Dial connects to the address addr on the given network through either +// defaultDialer or bypass. +func (p *PerHost) Dial(network, addr string) (c net.Conn, err error) { + host, _, err := net.SplitHostPort(addr) + if err != nil { + return nil, err + } + + return p.dialerForRequest(host).Dial(network, addr) +} + +// DialContext connects to the address addr on the given network through either +// defaultDialer or bypass. +func (p *PerHost) DialContext(ctx context.Context, network, addr string) (c net.Conn, err error) { + host, _, err := net.SplitHostPort(addr) + if err != nil { + return nil, err + } + d := p.dialerForRequest(host) + if x, ok := d.(ContextDialer); ok { + return x.DialContext(ctx, network, addr) + } + return dialContext(ctx, d, network, addr) +} + +func (p *PerHost) dialerForRequest(host string) Dialer { + if ip := net.ParseIP(host); ip != nil { + for _, net := range p.bypassNetworks { + if net.Contains(ip) { + return p.bypass + } + } + for _, bypassIP := range p.bypassIPs { + if bypassIP.Equal(ip) { + return p.bypass + } + } + return p.def + } + + for _, zone := range p.bypassZones { + if strings.HasSuffix(host, zone) { + return p.bypass + } + if host == zone[1:] { + // For a zone ".example.com", we match "example.com" + // too. + return p.bypass + } + } + for _, bypassHost := range p.bypassHosts { + if bypassHost == host { + return p.bypass + } + } + return p.def +} + +// AddFromString parses a string that contains comma-separated values +// specifying hosts that should use the bypass proxy. Each value is either an +// IP address, a CIDR range, a zone (*.example.com) or a host name +// (localhost). A best effort is made to parse the string and errors are +// ignored. +func (p *PerHost) AddFromString(s string) { + hosts := strings.Split(s, ",") + for _, host := range hosts { + host = strings.TrimSpace(host) + if len(host) == 0 { + continue + } + if strings.Contains(host, "/") { + // We assume that it's a CIDR address like 127.0.0.0/8 + if _, net, err := net.ParseCIDR(host); err == nil { + p.AddNetwork(net) + } + continue + } + if ip := net.ParseIP(host); ip != nil { + p.AddIP(ip) + continue + } + if strings.HasPrefix(host, "*.") { + p.AddZone(host[1:]) + continue + } + p.AddHost(host) + } +} + +// AddIP specifies an IP address that will use the bypass proxy. Note that +// this will only take effect if a literal IP address is dialed. A connection +// to a named host will never match an IP. +func (p *PerHost) AddIP(ip net.IP) { + p.bypassIPs = append(p.bypassIPs, ip) +} + +// AddNetwork specifies an IP range that will use the bypass proxy. Note that +// this will only take effect if a literal IP address is dialed. A connection +// to a named host will never match. +func (p *PerHost) AddNetwork(net *net.IPNet) { + p.bypassNetworks = append(p.bypassNetworks, net) +} + +// AddZone specifies a DNS suffix that will use the bypass proxy. A zone of +// "example.com" matches "example.com" and all of its subdomains. +func (p *PerHost) AddZone(zone string) { + if strings.HasSuffix(zone, ".") { + zone = zone[:len(zone)-1] + } + if !strings.HasPrefix(zone, ".") { + zone = "." + zone + } + p.bypassZones = append(p.bypassZones, zone) +} + +// AddHost specifies a host name that will use the bypass proxy. +func (p *PerHost) AddHost(host string) { + if strings.HasSuffix(host, ".") { + host = host[:len(host)-1] + } + p.bypassHosts = append(p.bypassHosts, host) +} diff --git a/vendor/golang.org/x/net/proxy/proxy.go b/vendor/golang.org/x/net/proxy/proxy.go new file mode 100644 index 0000000000..9ff4b9a776 --- /dev/null +++ b/vendor/golang.org/x/net/proxy/proxy.go @@ -0,0 +1,149 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package proxy provides support for a variety of protocols to proxy network +// data. +package proxy // import "golang.org/x/net/proxy" + +import ( + "errors" + "net" + "net/url" + "os" + "sync" +) + +// A Dialer is a means to establish a connection. +// Custom dialers should also implement ContextDialer. +type Dialer interface { + // Dial connects to the given address via the proxy. + Dial(network, addr string) (c net.Conn, err error) +} + +// Auth contains authentication parameters that specific Dialers may require. +type Auth struct { + User, Password string +} + +// FromEnvironment returns the dialer specified by the proxy-related +// variables in the environment and makes underlying connections +// directly. +func FromEnvironment() Dialer { + return FromEnvironmentUsing(Direct) +} + +// FromEnvironmentUsing returns the dialer specify by the proxy-related +// variables in the environment and makes underlying connections +// using the provided forwarding Dialer (for instance, a *net.Dialer +// with desired configuration). +func FromEnvironmentUsing(forward Dialer) Dialer { + allProxy := allProxyEnv.Get() + if len(allProxy) == 0 { + return forward + } + + proxyURL, err := url.Parse(allProxy) + if err != nil { + return forward + } + proxy, err := FromURL(proxyURL, forward) + if err != nil { + return forward + } + + noProxy := noProxyEnv.Get() + if len(noProxy) == 0 { + return proxy + } + + perHost := NewPerHost(proxy, forward) + perHost.AddFromString(noProxy) + return perHost +} + +// proxySchemes is a map from URL schemes to a function that creates a Dialer +// from a URL with such a scheme. +var proxySchemes map[string]func(*url.URL, Dialer) (Dialer, error) + +// RegisterDialerType takes a URL scheme and a function to generate Dialers from +// a URL with that scheme and a forwarding Dialer. Registered schemes are used +// by FromURL. +func RegisterDialerType(scheme string, f func(*url.URL, Dialer) (Dialer, error)) { + if proxySchemes == nil { + proxySchemes = make(map[string]func(*url.URL, Dialer) (Dialer, error)) + } + proxySchemes[scheme] = f +} + +// FromURL returns a Dialer given a URL specification and an underlying +// Dialer for it to make network requests. +func FromURL(u *url.URL, forward Dialer) (Dialer, error) { + var auth *Auth + if u.User != nil { + auth = new(Auth) + auth.User = u.User.Username() + if p, ok := u.User.Password(); ok { + auth.Password = p + } + } + + switch u.Scheme { + case "socks5", "socks5h": + addr := u.Hostname() + port := u.Port() + if port == "" { + port = "1080" + } + return SOCKS5("tcp", net.JoinHostPort(addr, port), auth, forward) + } + + // If the scheme doesn't match any of the built-in schemes, see if it + // was registered by another package. + if proxySchemes != nil { + if f, ok := proxySchemes[u.Scheme]; ok { + return f(u, forward) + } + } + + return nil, errors.New("proxy: unknown scheme: " + u.Scheme) +} + +var ( + allProxyEnv = &envOnce{ + names: []string{"ALL_PROXY", "all_proxy"}, + } + noProxyEnv = &envOnce{ + names: []string{"NO_PROXY", "no_proxy"}, + } +) + +// envOnce looks up an environment variable (optionally by multiple +// names) once. It mitigates expensive lookups on some platforms +// (e.g. Windows). +// (Borrowed from net/http/transport.go) +type envOnce struct { + names []string + once sync.Once + val string +} + +func (e *envOnce) Get() string { + e.once.Do(e.init) + return e.val +} + +func (e *envOnce) init() { + for _, n := range e.names { + e.val = os.Getenv(n) + if e.val != "" { + return + } + } +} + +// reset is used by tests +func (e *envOnce) reset() { + e.once = sync.Once{} + e.val = "" +} diff --git a/vendor/golang.org/x/net/proxy/socks5.go b/vendor/golang.org/x/net/proxy/socks5.go new file mode 100644 index 0000000000..c91651f96d --- /dev/null +++ b/vendor/golang.org/x/net/proxy/socks5.go @@ -0,0 +1,42 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package proxy + +import ( + "context" + "net" + + "golang.org/x/net/internal/socks" +) + +// SOCKS5 returns a Dialer that makes SOCKSv5 connections to the given +// address with an optional username and password. +// See RFC 1928 and RFC 1929. +func SOCKS5(network, address string, auth *Auth, forward Dialer) (Dialer, error) { + d := socks.NewDialer(network, address) + if forward != nil { + if f, ok := forward.(ContextDialer); ok { + d.ProxyDial = func(ctx context.Context, network string, address string) (net.Conn, error) { + return f.DialContext(ctx, network, address) + } + } else { + d.ProxyDial = func(ctx context.Context, network string, address string) (net.Conn, error) { + return dialContext(ctx, forward, network, address) + } + } + } + if auth != nil { + up := socks.UsernamePassword{ + Username: auth.User, + Password: auth.Password, + } + d.AuthMethods = []socks.AuthMethod{ + socks.AuthMethodNotRequired, + socks.AuthMethodUsernamePassword, + } + d.Authenticate = up.Authenticate + } + return d, nil +} diff --git a/vendor/golang.org/x/sync/syncmap/go19.go b/vendor/golang.org/x/sync/syncmap/go19.go new file mode 100644 index 0000000000..fa04dba91b --- /dev/null +++ b/vendor/golang.org/x/sync/syncmap/go19.go @@ -0,0 +1,18 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build go1.9 +// +build go1.9 + +package syncmap + +import "sync" // home to the standard library's sync.map implementation as of Go 1.9 + +// Map is a concurrent map with amortized-constant-time loads, stores, and deletes. +// It is safe for multiple goroutines to call a Map's methods concurrently. +// +// The zero Map is valid and empty. +// +// A Map must not be copied after first use. +type Map = sync.Map diff --git a/vendor/golang.org/x/sync/syncmap/map.go b/vendor/golang.org/x/sync/syncmap/map.go new file mode 100644 index 0000000000..4b638cb7a8 --- /dev/null +++ b/vendor/golang.org/x/sync/syncmap/map.go @@ -0,0 +1,8 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package syncmap provides a concurrent map implementation. +// This was the prototype for sync.Map which was added to the standard library's +// sync package in Go 1.9. https://golang.org/pkg/sync/#Map. +package syncmap diff --git a/vendor/golang.org/x/sync/syncmap/pre_go19.go b/vendor/golang.org/x/sync/syncmap/pre_go19.go new file mode 100644 index 0000000000..5bba41349c --- /dev/null +++ b/vendor/golang.org/x/sync/syncmap/pre_go19.go @@ -0,0 +1,371 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !go1.9 +// +build !go1.9 + +package syncmap + +import ( + "sync" + "sync/atomic" + "unsafe" +) + +// Map is a concurrent map with amortized-constant-time loads, stores, and deletes. +// It is safe for multiple goroutines to call a Map's methods concurrently. +// +// The zero Map is valid and empty. +// +// A Map must not be copied after first use. +type Map struct { + mu sync.Mutex + + // read contains the portion of the map's contents that are safe for + // concurrent access (with or without mu held). + // + // The read field itself is always safe to load, but must only be stored with + // mu held. + // + // Entries stored in read may be updated concurrently without mu, but updating + // a previously-expunged entry requires that the entry be copied to the dirty + // map and unexpunged with mu held. + read atomic.Value // readOnly + + // dirty contains the portion of the map's contents that require mu to be + // held. To ensure that the dirty map can be promoted to the read map quickly, + // it also includes all of the non-expunged entries in the read map. + // + // Expunged entries are not stored in the dirty map. An expunged entry in the + // clean map must be unexpunged and added to the dirty map before a new value + // can be stored to it. + // + // If the dirty map is nil, the next write to the map will initialize it by + // making a shallow copy of the clean map, omitting stale entries. + dirty map[interface{}]*entry + + // misses counts the number of loads since the read map was last updated that + // needed to lock mu to determine whether the key was present. + // + // Once enough misses have occurred to cover the cost of copying the dirty + // map, the dirty map will be promoted to the read map (in the unamended + // state) and the next store to the map will make a new dirty copy. + misses int +} + +// readOnly is an immutable struct stored atomically in the Map.read field. +type readOnly struct { + m map[interface{}]*entry + amended bool // true if the dirty map contains some key not in m. +} + +// expunged is an arbitrary pointer that marks entries which have been deleted +// from the dirty map. +var expunged = unsafe.Pointer(new(interface{})) + +// An entry is a slot in the map corresponding to a particular key. +type entry struct { + // p points to the interface{} value stored for the entry. + // + // If p == nil, the entry has been deleted and m.dirty == nil. + // + // If p == expunged, the entry has been deleted, m.dirty != nil, and the entry + // is missing from m.dirty. + // + // Otherwise, the entry is valid and recorded in m.read.m[key] and, if m.dirty + // != nil, in m.dirty[key]. + // + // An entry can be deleted by atomic replacement with nil: when m.dirty is + // next created, it will atomically replace nil with expunged and leave + // m.dirty[key] unset. + // + // An entry's associated value can be updated by atomic replacement, provided + // p != expunged. If p == expunged, an entry's associated value can be updated + // only after first setting m.dirty[key] = e so that lookups using the dirty + // map find the entry. + p unsafe.Pointer // *interface{} +} + +func newEntry(i interface{}) *entry { + return &entry{p: unsafe.Pointer(&i)} +} + +// Load returns the value stored in the map for a key, or nil if no +// value is present. +// The ok result indicates whether value was found in the map. +func (m *Map) Load(key interface{}) (value interface{}, ok bool) { + read, _ := m.read.Load().(readOnly) + e, ok := read.m[key] + if !ok && read.amended { + m.mu.Lock() + // Avoid reporting a spurious miss if m.dirty got promoted while we were + // blocked on m.mu. (If further loads of the same key will not miss, it's + // not worth copying the dirty map for this key.) + read, _ = m.read.Load().(readOnly) + e, ok = read.m[key] + if !ok && read.amended { + e, ok = m.dirty[key] + // Regardless of whether the entry was present, record a miss: this key + // will take the slow path until the dirty map is promoted to the read + // map. + m.missLocked() + } + m.mu.Unlock() + } + if !ok { + return nil, false + } + return e.load() +} + +func (e *entry) load() (value interface{}, ok bool) { + p := atomic.LoadPointer(&e.p) + if p == nil || p == expunged { + return nil, false + } + return *(*interface{})(p), true +} + +// Store sets the value for a key. +func (m *Map) Store(key, value interface{}) { + read, _ := m.read.Load().(readOnly) + if e, ok := read.m[key]; ok && e.tryStore(&value) { + return + } + + m.mu.Lock() + read, _ = m.read.Load().(readOnly) + if e, ok := read.m[key]; ok { + if e.unexpungeLocked() { + // The entry was previously expunged, which implies that there is a + // non-nil dirty map and this entry is not in it. + m.dirty[key] = e + } + e.storeLocked(&value) + } else if e, ok := m.dirty[key]; ok { + e.storeLocked(&value) + } else { + if !read.amended { + // We're adding the first new key to the dirty map. + // Make sure it is allocated and mark the read-only map as incomplete. + m.dirtyLocked() + m.read.Store(readOnly{m: read.m, amended: true}) + } + m.dirty[key] = newEntry(value) + } + m.mu.Unlock() +} + +// tryStore stores a value if the entry has not been expunged. +// +// If the entry is expunged, tryStore returns false and leaves the entry +// unchanged. +func (e *entry) tryStore(i *interface{}) bool { + p := atomic.LoadPointer(&e.p) + if p == expunged { + return false + } + for { + if atomic.CompareAndSwapPointer(&e.p, p, unsafe.Pointer(i)) { + return true + } + p = atomic.LoadPointer(&e.p) + if p == expunged { + return false + } + } +} + +// unexpungeLocked ensures that the entry is not marked as expunged. +// +// If the entry was previously expunged, it must be added to the dirty map +// before m.mu is unlocked. +func (e *entry) unexpungeLocked() (wasExpunged bool) { + return atomic.CompareAndSwapPointer(&e.p, expunged, nil) +} + +// storeLocked unconditionally stores a value to the entry. +// +// The entry must be known not to be expunged. +func (e *entry) storeLocked(i *interface{}) { + atomic.StorePointer(&e.p, unsafe.Pointer(i)) +} + +// LoadOrStore returns the existing value for the key if present. +// Otherwise, it stores and returns the given value. +// The loaded result is true if the value was loaded, false if stored. +func (m *Map) LoadOrStore(key, value interface{}) (actual interface{}, loaded bool) { + // Avoid locking if it's a clean hit. + read, _ := m.read.Load().(readOnly) + if e, ok := read.m[key]; ok { + actual, loaded, ok := e.tryLoadOrStore(value) + if ok { + return actual, loaded + } + } + + m.mu.Lock() + read, _ = m.read.Load().(readOnly) + if e, ok := read.m[key]; ok { + if e.unexpungeLocked() { + m.dirty[key] = e + } + actual, loaded, _ = e.tryLoadOrStore(value) + } else if e, ok := m.dirty[key]; ok { + actual, loaded, _ = e.tryLoadOrStore(value) + m.missLocked() + } else { + if !read.amended { + // We're adding the first new key to the dirty map. + // Make sure it is allocated and mark the read-only map as incomplete. + m.dirtyLocked() + m.read.Store(readOnly{m: read.m, amended: true}) + } + m.dirty[key] = newEntry(value) + actual, loaded = value, false + } + m.mu.Unlock() + + return actual, loaded +} + +// tryLoadOrStore atomically loads or stores a value if the entry is not +// expunged. +// +// If the entry is expunged, tryLoadOrStore leaves the entry unchanged and +// returns with ok==false. +func (e *entry) tryLoadOrStore(i interface{}) (actual interface{}, loaded, ok bool) { + p := atomic.LoadPointer(&e.p) + if p == expunged { + return nil, false, false + } + if p != nil { + return *(*interface{})(p), true, true + } + + // Copy the interface after the first load to make this method more amenable + // to escape analysis: if we hit the "load" path or the entry is expunged, we + // shouldn't bother heap-allocating. + ic := i + for { + if atomic.CompareAndSwapPointer(&e.p, nil, unsafe.Pointer(&ic)) { + return i, false, true + } + p = atomic.LoadPointer(&e.p) + if p == expunged { + return nil, false, false + } + if p != nil { + return *(*interface{})(p), true, true + } + } +} + +// Delete deletes the value for a key. +func (m *Map) Delete(key interface{}) { + read, _ := m.read.Load().(readOnly) + e, ok := read.m[key] + if !ok && read.amended { + m.mu.Lock() + read, _ = m.read.Load().(readOnly) + e, ok = read.m[key] + if !ok && read.amended { + delete(m.dirty, key) + } + m.mu.Unlock() + } + if ok { + e.delete() + } +} + +func (e *entry) delete() (hadValue bool) { + for { + p := atomic.LoadPointer(&e.p) + if p == nil || p == expunged { + return false + } + if atomic.CompareAndSwapPointer(&e.p, p, nil) { + return true + } + } +} + +// Range calls f sequentially for each key and value present in the map. +// If f returns false, range stops the iteration. +// +// Range does not necessarily correspond to any consistent snapshot of the Map's +// contents: no key will be visited more than once, but if the value for any key +// is stored or deleted concurrently, Range may reflect any mapping for that key +// from any point during the Range call. +// +// Range may be O(N) with the number of elements in the map even if f returns +// false after a constant number of calls. +func (m *Map) Range(f func(key, value interface{}) bool) { + // We need to be able to iterate over all of the keys that were already + // present at the start of the call to Range. + // If read.amended is false, then read.m satisfies that property without + // requiring us to hold m.mu for a long time. + read, _ := m.read.Load().(readOnly) + if read.amended { + // m.dirty contains keys not in read.m. Fortunately, Range is already O(N) + // (assuming the caller does not break out early), so a call to Range + // amortizes an entire copy of the map: we can promote the dirty copy + // immediately! + m.mu.Lock() + read, _ = m.read.Load().(readOnly) + if read.amended { + read = readOnly{m: m.dirty} + m.read.Store(read) + m.dirty = nil + m.misses = 0 + } + m.mu.Unlock() + } + + for k, e := range read.m { + v, ok := e.load() + if !ok { + continue + } + if !f(k, v) { + break + } + } +} + +func (m *Map) missLocked() { + m.misses++ + if m.misses < len(m.dirty) { + return + } + m.read.Store(readOnly{m: m.dirty}) + m.dirty = nil + m.misses = 0 +} + +func (m *Map) dirtyLocked() { + if m.dirty != nil { + return + } + + read, _ := m.read.Load().(readOnly) + m.dirty = make(map[interface{}]*entry, len(read.m)) + for k, e := range read.m { + if !e.tryExpungeLocked() { + m.dirty[k] = e + } + } +} + +func (e *entry) tryExpungeLocked() (isExpunged bool) { + p := atomic.LoadPointer(&e.p) + for p == nil { + if atomic.CompareAndSwapPointer(&e.p, nil, expunged) { + return true + } + p = atomic.LoadPointer(&e.p) + } + return p == expunged +} diff --git a/vendor/golang.org/x/sys/cpu/asm_aix_ppc64.s b/vendor/golang.org/x/sys/cpu/asm_aix_ppc64.s new file mode 100644 index 0000000000..db9171c2e4 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/asm_aix_ppc64.s @@ -0,0 +1,18 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build gc +// +build gc + +#include "textflag.h" + +// +// System calls for ppc64, AIX are implemented in runtime/syscall_aix.go +// + +TEXT ·syscall6(SB),NOSPLIT,$0-88 + JMP syscall·syscall6(SB) + +TEXT ·rawSyscall6(SB),NOSPLIT,$0-88 + JMP syscall·rawSyscall6(SB) diff --git a/vendor/golang.org/x/sys/cpu/byteorder.go b/vendor/golang.org/x/sys/cpu/byteorder.go new file mode 100644 index 0000000000..271055be0b --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/byteorder.go @@ -0,0 +1,66 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cpu + +import ( + "runtime" +) + +// byteOrder is a subset of encoding/binary.ByteOrder. +type byteOrder interface { + Uint32([]byte) uint32 + Uint64([]byte) uint64 +} + +type littleEndian struct{} +type bigEndian struct{} + +func (littleEndian) Uint32(b []byte) uint32 { + _ = b[3] // bounds check hint to compiler; see golang.org/issue/14808 + return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24 +} + +func (littleEndian) Uint64(b []byte) uint64 { + _ = b[7] // bounds check hint to compiler; see golang.org/issue/14808 + return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | + uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56 +} + +func (bigEndian) Uint32(b []byte) uint32 { + _ = b[3] // bounds check hint to compiler; see golang.org/issue/14808 + return uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24 +} + +func (bigEndian) Uint64(b []byte) uint64 { + _ = b[7] // bounds check hint to compiler; see golang.org/issue/14808 + return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 | + uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56 +} + +// hostByteOrder returns littleEndian on little-endian machines and +// bigEndian on big-endian machines. +func hostByteOrder() byteOrder { + switch runtime.GOARCH { + case "386", "amd64", "amd64p32", + "alpha", + "arm", "arm64", + "loong64", + "mipsle", "mips64le", "mips64p32le", + "nios2", + "ppc64le", + "riscv", "riscv64", + "sh": + return littleEndian{} + case "armbe", "arm64be", + "m68k", + "mips", "mips64", "mips64p32", + "ppc", "ppc64", + "s390", "s390x", + "shbe", + "sparc", "sparc64": + return bigEndian{} + } + panic("unknown architecture") +} diff --git a/vendor/golang.org/x/sys/cpu/cpu.go b/vendor/golang.org/x/sys/cpu/cpu.go new file mode 100644 index 0000000000..83f112c4c8 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu.go @@ -0,0 +1,287 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package cpu implements processor feature detection for +// various CPU architectures. +package cpu + +import ( + "os" + "strings" +) + +// Initialized reports whether the CPU features were initialized. +// +// For some GOOS/GOARCH combinations initialization of the CPU features depends +// on reading an operating specific file, e.g. /proc/self/auxv on linux/arm +// Initialized will report false if reading the file fails. +var Initialized bool + +// CacheLinePad is used to pad structs to avoid false sharing. +type CacheLinePad struct{ _ [cacheLineSize]byte } + +// X86 contains the supported CPU features of the +// current X86/AMD64 platform. If the current platform +// is not X86/AMD64 then all feature flags are false. +// +// X86 is padded to avoid false sharing. Further the HasAVX +// and HasAVX2 are only set if the OS supports XMM and YMM +// registers in addition to the CPUID feature bit being set. +var X86 struct { + _ CacheLinePad + HasAES bool // AES hardware implementation (AES NI) + HasADX bool // Multi-precision add-carry instruction extensions + HasAVX bool // Advanced vector extension + HasAVX2 bool // Advanced vector extension 2 + HasAVX512 bool // Advanced vector extension 512 + HasAVX512F bool // Advanced vector extension 512 Foundation Instructions + HasAVX512CD bool // Advanced vector extension 512 Conflict Detection Instructions + HasAVX512ER bool // Advanced vector extension 512 Exponential and Reciprocal Instructions + HasAVX512PF bool // Advanced vector extension 512 Prefetch Instructions Instructions + HasAVX512VL bool // Advanced vector extension 512 Vector Length Extensions + HasAVX512BW bool // Advanced vector extension 512 Byte and Word Instructions + HasAVX512DQ bool // Advanced vector extension 512 Doubleword and Quadword Instructions + HasAVX512IFMA bool // Advanced vector extension 512 Integer Fused Multiply Add + HasAVX512VBMI bool // Advanced vector extension 512 Vector Byte Manipulation Instructions + HasAVX5124VNNIW bool // Advanced vector extension 512 Vector Neural Network Instructions Word variable precision + HasAVX5124FMAPS bool // Advanced vector extension 512 Fused Multiply Accumulation Packed Single precision + HasAVX512VPOPCNTDQ bool // Advanced vector extension 512 Double and quad word population count instructions + HasAVX512VPCLMULQDQ bool // Advanced vector extension 512 Vector carry-less multiply operations + HasAVX512VNNI bool // Advanced vector extension 512 Vector Neural Network Instructions + HasAVX512GFNI bool // Advanced vector extension 512 Galois field New Instructions + HasAVX512VAES bool // Advanced vector extension 512 Vector AES instructions + HasAVX512VBMI2 bool // Advanced vector extension 512 Vector Byte Manipulation Instructions 2 + HasAVX512BITALG bool // Advanced vector extension 512 Bit Algorithms + HasAVX512BF16 bool // Advanced vector extension 512 BFloat16 Instructions + HasBMI1 bool // Bit manipulation instruction set 1 + HasBMI2 bool // Bit manipulation instruction set 2 + HasCX16 bool // Compare and exchange 16 Bytes + HasERMS bool // Enhanced REP for MOVSB and STOSB + HasFMA bool // Fused-multiply-add instructions + HasOSXSAVE bool // OS supports XSAVE/XRESTOR for saving/restoring XMM registers. + HasPCLMULQDQ bool // PCLMULQDQ instruction - most often used for AES-GCM + HasPOPCNT bool // Hamming weight instruction POPCNT. + HasRDRAND bool // RDRAND instruction (on-chip random number generator) + HasRDSEED bool // RDSEED instruction (on-chip random number generator) + HasSSE2 bool // Streaming SIMD extension 2 (always available on amd64) + HasSSE3 bool // Streaming SIMD extension 3 + HasSSSE3 bool // Supplemental streaming SIMD extension 3 + HasSSE41 bool // Streaming SIMD extension 4 and 4.1 + HasSSE42 bool // Streaming SIMD extension 4 and 4.2 + _ CacheLinePad +} + +// ARM64 contains the supported CPU features of the +// current ARMv8(aarch64) platform. If the current platform +// is not arm64 then all feature flags are false. +var ARM64 struct { + _ CacheLinePad + HasFP bool // Floating-point instruction set (always available) + HasASIMD bool // Advanced SIMD (always available) + HasEVTSTRM bool // Event stream support + HasAES bool // AES hardware implementation + HasPMULL bool // Polynomial multiplication instruction set + HasSHA1 bool // SHA1 hardware implementation + HasSHA2 bool // SHA2 hardware implementation + HasCRC32 bool // CRC32 hardware implementation + HasATOMICS bool // Atomic memory operation instruction set + HasFPHP bool // Half precision floating-point instruction set + HasASIMDHP bool // Advanced SIMD half precision instruction set + HasCPUID bool // CPUID identification scheme registers + HasASIMDRDM bool // Rounding double multiply add/subtract instruction set + HasJSCVT bool // Javascript conversion from floating-point to integer + HasFCMA bool // Floating-point multiplication and addition of complex numbers + HasLRCPC bool // Release Consistent processor consistent support + HasDCPOP bool // Persistent memory support + HasSHA3 bool // SHA3 hardware implementation + HasSM3 bool // SM3 hardware implementation + HasSM4 bool // SM4 hardware implementation + HasASIMDDP bool // Advanced SIMD double precision instruction set + HasSHA512 bool // SHA512 hardware implementation + HasSVE bool // Scalable Vector Extensions + HasASIMDFHM bool // Advanced SIMD multiplication FP16 to FP32 + _ CacheLinePad +} + +// ARM contains the supported CPU features of the current ARM (32-bit) platform. +// All feature flags are false if: +// 1. the current platform is not arm, or +// 2. the current operating system is not Linux. +var ARM struct { + _ CacheLinePad + HasSWP bool // SWP instruction support + HasHALF bool // Half-word load and store support + HasTHUMB bool // ARM Thumb instruction set + Has26BIT bool // Address space limited to 26-bits + HasFASTMUL bool // 32-bit operand, 64-bit result multiplication support + HasFPA bool // Floating point arithmetic support + HasVFP bool // Vector floating point support + HasEDSP bool // DSP Extensions support + HasJAVA bool // Java instruction set + HasIWMMXT bool // Intel Wireless MMX technology support + HasCRUNCH bool // MaverickCrunch context switching and handling + HasTHUMBEE bool // Thumb EE instruction set + HasNEON bool // NEON instruction set + HasVFPv3 bool // Vector floating point version 3 support + HasVFPv3D16 bool // Vector floating point version 3 D8-D15 + HasTLS bool // Thread local storage support + HasVFPv4 bool // Vector floating point version 4 support + HasIDIVA bool // Integer divide instruction support in ARM mode + HasIDIVT bool // Integer divide instruction support in Thumb mode + HasVFPD32 bool // Vector floating point version 3 D15-D31 + HasLPAE bool // Large Physical Address Extensions + HasEVTSTRM bool // Event stream support + HasAES bool // AES hardware implementation + HasPMULL bool // Polynomial multiplication instruction set + HasSHA1 bool // SHA1 hardware implementation + HasSHA2 bool // SHA2 hardware implementation + HasCRC32 bool // CRC32 hardware implementation + _ CacheLinePad +} + +// MIPS64X contains the supported CPU features of the current mips64/mips64le +// platforms. If the current platform is not mips64/mips64le or the current +// operating system is not Linux then all feature flags are false. +var MIPS64X struct { + _ CacheLinePad + HasMSA bool // MIPS SIMD architecture + _ CacheLinePad +} + +// PPC64 contains the supported CPU features of the current ppc64/ppc64le platforms. +// If the current platform is not ppc64/ppc64le then all feature flags are false. +// +// For ppc64/ppc64le, it is safe to check only for ISA level starting on ISA v3.00, +// since there are no optional categories. There are some exceptions that also +// require kernel support to work (DARN, SCV), so there are feature bits for +// those as well. The struct is padded to avoid false sharing. +var PPC64 struct { + _ CacheLinePad + HasDARN bool // Hardware random number generator (requires kernel enablement) + HasSCV bool // Syscall vectored (requires kernel enablement) + IsPOWER8 bool // ISA v2.07 (POWER8) + IsPOWER9 bool // ISA v3.00 (POWER9), implies IsPOWER8 + _ CacheLinePad +} + +// S390X contains the supported CPU features of the current IBM Z +// (s390x) platform. If the current platform is not IBM Z then all +// feature flags are false. +// +// S390X is padded to avoid false sharing. Further HasVX is only set +// if the OS supports vector registers in addition to the STFLE +// feature bit being set. +var S390X struct { + _ CacheLinePad + HasZARCH bool // z/Architecture mode is active [mandatory] + HasSTFLE bool // store facility list extended + HasLDISP bool // long (20-bit) displacements + HasEIMM bool // 32-bit immediates + HasDFP bool // decimal floating point + HasETF3EH bool // ETF-3 enhanced + HasMSA bool // message security assist (CPACF) + HasAES bool // KM-AES{128,192,256} functions + HasAESCBC bool // KMC-AES{128,192,256} functions + HasAESCTR bool // KMCTR-AES{128,192,256} functions + HasAESGCM bool // KMA-GCM-AES{128,192,256} functions + HasGHASH bool // KIMD-GHASH function + HasSHA1 bool // K{I,L}MD-SHA-1 functions + HasSHA256 bool // K{I,L}MD-SHA-256 functions + HasSHA512 bool // K{I,L}MD-SHA-512 functions + HasSHA3 bool // K{I,L}MD-SHA3-{224,256,384,512} and K{I,L}MD-SHAKE-{128,256} functions + HasVX bool // vector facility + HasVXE bool // vector-enhancements facility 1 + _ CacheLinePad +} + +func init() { + archInit() + initOptions() + processOptions() +} + +// options contains the cpu debug options that can be used in GODEBUG. +// Options are arch dependent and are added by the arch specific initOptions functions. +// Features that are mandatory for the specific GOARCH should have the Required field set +// (e.g. SSE2 on amd64). +var options []option + +// Option names should be lower case. e.g. avx instead of AVX. +type option struct { + Name string + Feature *bool + Specified bool // whether feature value was specified in GODEBUG + Enable bool // whether feature should be enabled + Required bool // whether feature is mandatory and can not be disabled +} + +func processOptions() { + env := os.Getenv("GODEBUG") +field: + for env != "" { + field := "" + i := strings.IndexByte(env, ',') + if i < 0 { + field, env = env, "" + } else { + field, env = env[:i], env[i+1:] + } + if len(field) < 4 || field[:4] != "cpu." { + continue + } + i = strings.IndexByte(field, '=') + if i < 0 { + print("GODEBUG sys/cpu: no value specified for \"", field, "\"\n") + continue + } + key, value := field[4:i], field[i+1:] // e.g. "SSE2", "on" + + var enable bool + switch value { + case "on": + enable = true + case "off": + enable = false + default: + print("GODEBUG sys/cpu: value \"", value, "\" not supported for cpu option \"", key, "\"\n") + continue field + } + + if key == "all" { + for i := range options { + options[i].Specified = true + options[i].Enable = enable || options[i].Required + } + continue field + } + + for i := range options { + if options[i].Name == key { + options[i].Specified = true + options[i].Enable = enable + continue field + } + } + + print("GODEBUG sys/cpu: unknown cpu feature \"", key, "\"\n") + } + + for _, o := range options { + if !o.Specified { + continue + } + + if o.Enable && !*o.Feature { + print("GODEBUG sys/cpu: can not enable \"", o.Name, "\", missing CPU support\n") + continue + } + + if !o.Enable && o.Required { + print("GODEBUG sys/cpu: can not disable \"", o.Name, "\", required CPU feature\n") + continue + } + + *o.Feature = o.Enable + } +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_aix.go b/vendor/golang.org/x/sys/cpu/cpu_aix.go new file mode 100644 index 0000000000..8aaeef545a --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_aix.go @@ -0,0 +1,34 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build aix +// +build aix + +package cpu + +const ( + // getsystemcfg constants + _SC_IMPL = 2 + _IMPL_POWER8 = 0x10000 + _IMPL_POWER9 = 0x20000 +) + +func archInit() { + impl := getsystemcfg(_SC_IMPL) + if impl&_IMPL_POWER8 != 0 { + PPC64.IsPOWER8 = true + } + if impl&_IMPL_POWER9 != 0 { + PPC64.IsPOWER8 = true + PPC64.IsPOWER9 = true + } + + Initialized = true +} + +func getsystemcfg(label int) (n uint64) { + r0, _ := callgetsystemcfg(label) + n = uint64(r0) + return +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_arm.go b/vendor/golang.org/x/sys/cpu/cpu_arm.go new file mode 100644 index 0000000000..301b752e9c --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_arm.go @@ -0,0 +1,73 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cpu + +const cacheLineSize = 32 + +// HWCAP/HWCAP2 bits. +// These are specific to Linux. +const ( + hwcap_SWP = 1 << 0 + hwcap_HALF = 1 << 1 + hwcap_THUMB = 1 << 2 + hwcap_26BIT = 1 << 3 + hwcap_FAST_MULT = 1 << 4 + hwcap_FPA = 1 << 5 + hwcap_VFP = 1 << 6 + hwcap_EDSP = 1 << 7 + hwcap_JAVA = 1 << 8 + hwcap_IWMMXT = 1 << 9 + hwcap_CRUNCH = 1 << 10 + hwcap_THUMBEE = 1 << 11 + hwcap_NEON = 1 << 12 + hwcap_VFPv3 = 1 << 13 + hwcap_VFPv3D16 = 1 << 14 + hwcap_TLS = 1 << 15 + hwcap_VFPv4 = 1 << 16 + hwcap_IDIVA = 1 << 17 + hwcap_IDIVT = 1 << 18 + hwcap_VFPD32 = 1 << 19 + hwcap_LPAE = 1 << 20 + hwcap_EVTSTRM = 1 << 21 + + hwcap2_AES = 1 << 0 + hwcap2_PMULL = 1 << 1 + hwcap2_SHA1 = 1 << 2 + hwcap2_SHA2 = 1 << 3 + hwcap2_CRC32 = 1 << 4 +) + +func initOptions() { + options = []option{ + {Name: "pmull", Feature: &ARM.HasPMULL}, + {Name: "sha1", Feature: &ARM.HasSHA1}, + {Name: "sha2", Feature: &ARM.HasSHA2}, + {Name: "swp", Feature: &ARM.HasSWP}, + {Name: "thumb", Feature: &ARM.HasTHUMB}, + {Name: "thumbee", Feature: &ARM.HasTHUMBEE}, + {Name: "tls", Feature: &ARM.HasTLS}, + {Name: "vfp", Feature: &ARM.HasVFP}, + {Name: "vfpd32", Feature: &ARM.HasVFPD32}, + {Name: "vfpv3", Feature: &ARM.HasVFPv3}, + {Name: "vfpv3d16", Feature: &ARM.HasVFPv3D16}, + {Name: "vfpv4", Feature: &ARM.HasVFPv4}, + {Name: "half", Feature: &ARM.HasHALF}, + {Name: "26bit", Feature: &ARM.Has26BIT}, + {Name: "fastmul", Feature: &ARM.HasFASTMUL}, + {Name: "fpa", Feature: &ARM.HasFPA}, + {Name: "edsp", Feature: &ARM.HasEDSP}, + {Name: "java", Feature: &ARM.HasJAVA}, + {Name: "iwmmxt", Feature: &ARM.HasIWMMXT}, + {Name: "crunch", Feature: &ARM.HasCRUNCH}, + {Name: "neon", Feature: &ARM.HasNEON}, + {Name: "idivt", Feature: &ARM.HasIDIVT}, + {Name: "idiva", Feature: &ARM.HasIDIVA}, + {Name: "lpae", Feature: &ARM.HasLPAE}, + {Name: "evtstrm", Feature: &ARM.HasEVTSTRM}, + {Name: "aes", Feature: &ARM.HasAES}, + {Name: "crc32", Feature: &ARM.HasCRC32}, + } + +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_arm64.go b/vendor/golang.org/x/sys/cpu/cpu_arm64.go new file mode 100644 index 0000000000..f3eb993bf2 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_arm64.go @@ -0,0 +1,172 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cpu + +import "runtime" + +// cacheLineSize is used to prevent false sharing of cache lines. +// We choose 128 because Apple Silicon, a.k.a. M1, has 128-byte cache line size. +// It doesn't cost much and is much more future-proof. +const cacheLineSize = 128 + +func initOptions() { + options = []option{ + {Name: "fp", Feature: &ARM64.HasFP}, + {Name: "asimd", Feature: &ARM64.HasASIMD}, + {Name: "evstrm", Feature: &ARM64.HasEVTSTRM}, + {Name: "aes", Feature: &ARM64.HasAES}, + {Name: "fphp", Feature: &ARM64.HasFPHP}, + {Name: "jscvt", Feature: &ARM64.HasJSCVT}, + {Name: "lrcpc", Feature: &ARM64.HasLRCPC}, + {Name: "pmull", Feature: &ARM64.HasPMULL}, + {Name: "sha1", Feature: &ARM64.HasSHA1}, + {Name: "sha2", Feature: &ARM64.HasSHA2}, + {Name: "sha3", Feature: &ARM64.HasSHA3}, + {Name: "sha512", Feature: &ARM64.HasSHA512}, + {Name: "sm3", Feature: &ARM64.HasSM3}, + {Name: "sm4", Feature: &ARM64.HasSM4}, + {Name: "sve", Feature: &ARM64.HasSVE}, + {Name: "crc32", Feature: &ARM64.HasCRC32}, + {Name: "atomics", Feature: &ARM64.HasATOMICS}, + {Name: "asimdhp", Feature: &ARM64.HasASIMDHP}, + {Name: "cpuid", Feature: &ARM64.HasCPUID}, + {Name: "asimrdm", Feature: &ARM64.HasASIMDRDM}, + {Name: "fcma", Feature: &ARM64.HasFCMA}, + {Name: "dcpop", Feature: &ARM64.HasDCPOP}, + {Name: "asimddp", Feature: &ARM64.HasASIMDDP}, + {Name: "asimdfhm", Feature: &ARM64.HasASIMDFHM}, + } +} + +func archInit() { + switch runtime.GOOS { + case "freebsd": + readARM64Registers() + case "linux", "netbsd", "openbsd": + doinit() + default: + // Many platforms don't seem to allow reading these registers. + setMinimalFeatures() + } +} + +// setMinimalFeatures fakes the minimal ARM64 features expected by +// TestARM64minimalFeatures. +func setMinimalFeatures() { + ARM64.HasASIMD = true + ARM64.HasFP = true +} + +func readARM64Registers() { + Initialized = true + + parseARM64SystemRegisters(getisar0(), getisar1(), getpfr0()) +} + +func parseARM64SystemRegisters(isar0, isar1, pfr0 uint64) { + // ID_AA64ISAR0_EL1 + switch extractBits(isar0, 4, 7) { + case 1: + ARM64.HasAES = true + case 2: + ARM64.HasAES = true + ARM64.HasPMULL = true + } + + switch extractBits(isar0, 8, 11) { + case 1: + ARM64.HasSHA1 = true + } + + switch extractBits(isar0, 12, 15) { + case 1: + ARM64.HasSHA2 = true + case 2: + ARM64.HasSHA2 = true + ARM64.HasSHA512 = true + } + + switch extractBits(isar0, 16, 19) { + case 1: + ARM64.HasCRC32 = true + } + + switch extractBits(isar0, 20, 23) { + case 2: + ARM64.HasATOMICS = true + } + + switch extractBits(isar0, 28, 31) { + case 1: + ARM64.HasASIMDRDM = true + } + + switch extractBits(isar0, 32, 35) { + case 1: + ARM64.HasSHA3 = true + } + + switch extractBits(isar0, 36, 39) { + case 1: + ARM64.HasSM3 = true + } + + switch extractBits(isar0, 40, 43) { + case 1: + ARM64.HasSM4 = true + } + + switch extractBits(isar0, 44, 47) { + case 1: + ARM64.HasASIMDDP = true + } + + // ID_AA64ISAR1_EL1 + switch extractBits(isar1, 0, 3) { + case 1: + ARM64.HasDCPOP = true + } + + switch extractBits(isar1, 12, 15) { + case 1: + ARM64.HasJSCVT = true + } + + switch extractBits(isar1, 16, 19) { + case 1: + ARM64.HasFCMA = true + } + + switch extractBits(isar1, 20, 23) { + case 1: + ARM64.HasLRCPC = true + } + + // ID_AA64PFR0_EL1 + switch extractBits(pfr0, 16, 19) { + case 0: + ARM64.HasFP = true + case 1: + ARM64.HasFP = true + ARM64.HasFPHP = true + } + + switch extractBits(pfr0, 20, 23) { + case 0: + ARM64.HasASIMD = true + case 1: + ARM64.HasASIMD = true + ARM64.HasASIMDHP = true + } + + switch extractBits(pfr0, 32, 35) { + case 1: + ARM64.HasSVE = true + } +} + +func extractBits(data uint64, start, end uint) uint { + return (uint)(data>>start) & ((1 << (end - start + 1)) - 1) +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_arm64.s b/vendor/golang.org/x/sys/cpu/cpu_arm64.s new file mode 100644 index 0000000000..c61f95a05a --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_arm64.s @@ -0,0 +1,32 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build gc +// +build gc + +#include "textflag.h" + +// func getisar0() uint64 +TEXT ·getisar0(SB),NOSPLIT,$0-8 + // get Instruction Set Attributes 0 into x0 + // mrs x0, ID_AA64ISAR0_EL1 = d5380600 + WORD $0xd5380600 + MOVD R0, ret+0(FP) + RET + +// func getisar1() uint64 +TEXT ·getisar1(SB),NOSPLIT,$0-8 + // get Instruction Set Attributes 1 into x0 + // mrs x0, ID_AA64ISAR1_EL1 = d5380620 + WORD $0xd5380620 + MOVD R0, ret+0(FP) + RET + +// func getpfr0() uint64 +TEXT ·getpfr0(SB),NOSPLIT,$0-8 + // get Processor Feature Register 0 into x0 + // mrs x0, ID_AA64PFR0_EL1 = d5380400 + WORD $0xd5380400 + MOVD R0, ret+0(FP) + RET diff --git a/vendor/golang.org/x/sys/cpu/cpu_gc_arm64.go b/vendor/golang.org/x/sys/cpu/cpu_gc_arm64.go new file mode 100644 index 0000000000..ccf542a73d --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_gc_arm64.go @@ -0,0 +1,12 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build gc +// +build gc + +package cpu + +func getisar0() uint64 +func getisar1() uint64 +func getpfr0() uint64 diff --git a/vendor/golang.org/x/sys/cpu/cpu_gc_s390x.go b/vendor/golang.org/x/sys/cpu/cpu_gc_s390x.go new file mode 100644 index 0000000000..0af2f24841 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_gc_s390x.go @@ -0,0 +1,22 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build gc +// +build gc + +package cpu + +// haveAsmFunctions reports whether the other functions in this file can +// be safely called. +func haveAsmFunctions() bool { return true } + +// The following feature detection functions are defined in cpu_s390x.s. +// They are likely to be expensive to call so the results should be cached. +func stfle() facilityList +func kmQuery() queryResult +func kmcQuery() queryResult +func kmctrQuery() queryResult +func kmaQuery() queryResult +func kimdQuery() queryResult +func klmdQuery() queryResult diff --git a/vendor/golang.org/x/sys/cpu/cpu_gc_x86.go b/vendor/golang.org/x/sys/cpu/cpu_gc_x86.go new file mode 100644 index 0000000000..fa7cdb9bcd --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_gc_x86.go @@ -0,0 +1,17 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build (386 || amd64 || amd64p32) && gc +// +build 386 amd64 amd64p32 +// +build gc + +package cpu + +// cpuid is implemented in cpu_x86.s for gc compiler +// and in cpu_gccgo.c for gccgo. +func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32) + +// xgetbv with ecx = 0 is implemented in cpu_x86.s for gc compiler +// and in cpu_gccgo.c for gccgo. +func xgetbv() (eax, edx uint32) diff --git a/vendor/golang.org/x/sys/cpu/cpu_gccgo_arm64.go b/vendor/golang.org/x/sys/cpu/cpu_gccgo_arm64.go new file mode 100644 index 0000000000..2aff318911 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_gccgo_arm64.go @@ -0,0 +1,12 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build gccgo +// +build gccgo + +package cpu + +func getisar0() uint64 { return 0 } +func getisar1() uint64 { return 0 } +func getpfr0() uint64 { return 0 } diff --git a/vendor/golang.org/x/sys/cpu/cpu_gccgo_s390x.go b/vendor/golang.org/x/sys/cpu/cpu_gccgo_s390x.go new file mode 100644 index 0000000000..4bfbda6199 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_gccgo_s390x.go @@ -0,0 +1,23 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build gccgo +// +build gccgo + +package cpu + +// haveAsmFunctions reports whether the other functions in this file can +// be safely called. +func haveAsmFunctions() bool { return false } + +// TODO(mundaym): the following feature detection functions are currently +// stubs. See https://golang.org/cl/162887 for how to fix this. +// They are likely to be expensive to call so the results should be cached. +func stfle() facilityList { panic("not implemented for gccgo") } +func kmQuery() queryResult { panic("not implemented for gccgo") } +func kmcQuery() queryResult { panic("not implemented for gccgo") } +func kmctrQuery() queryResult { panic("not implemented for gccgo") } +func kmaQuery() queryResult { panic("not implemented for gccgo") } +func kimdQuery() queryResult { panic("not implemented for gccgo") } +func klmdQuery() queryResult { panic("not implemented for gccgo") } diff --git a/vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.c b/vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.c new file mode 100644 index 0000000000..6cc73109f5 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.c @@ -0,0 +1,39 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build (386 || amd64 || amd64p32) && gccgo +// +build 386 amd64 amd64p32 +// +build gccgo + +#include +#include +#include + +// Need to wrap __get_cpuid_count because it's declared as static. +int +gccgoGetCpuidCount(uint32_t leaf, uint32_t subleaf, + uint32_t *eax, uint32_t *ebx, + uint32_t *ecx, uint32_t *edx) +{ + return __get_cpuid_count(leaf, subleaf, eax, ebx, ecx, edx); +} + +#pragma GCC diagnostic ignored "-Wunknown-pragmas" +#pragma GCC push_options +#pragma GCC target("xsave") +#pragma clang attribute push (__attribute__((target("xsave"))), apply_to=function) + +// xgetbv reads the contents of an XCR (Extended Control Register) +// specified in the ECX register into registers EDX:EAX. +// Currently, the only supported value for XCR is 0. +void +gccgoXgetbv(uint32_t *eax, uint32_t *edx) +{ + uint64_t v = _xgetbv(0); + *eax = v & 0xffffffff; + *edx = v >> 32; +} + +#pragma clang attribute pop +#pragma GCC pop_options diff --git a/vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.go b/vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.go new file mode 100644 index 0000000000..863d415ab4 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.go @@ -0,0 +1,33 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build (386 || amd64 || amd64p32) && gccgo +// +build 386 amd64 amd64p32 +// +build gccgo + +package cpu + +//extern gccgoGetCpuidCount +func gccgoGetCpuidCount(eaxArg, ecxArg uint32, eax, ebx, ecx, edx *uint32) + +func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32) { + var a, b, c, d uint32 + gccgoGetCpuidCount(eaxArg, ecxArg, &a, &b, &c, &d) + return a, b, c, d +} + +//extern gccgoXgetbv +func gccgoXgetbv(eax, edx *uint32) + +func xgetbv() (eax, edx uint32) { + var a, d uint32 + gccgoXgetbv(&a, &d) + return a, d +} + +// gccgo doesn't build on Darwin, per: +// https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/gcc.rb#L76 +func darwinSupportsAVX512() bool { + return false +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_linux.go b/vendor/golang.org/x/sys/cpu/cpu_linux.go new file mode 100644 index 0000000000..159a686f6f --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_linux.go @@ -0,0 +1,16 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !386 && !amd64 && !amd64p32 && !arm64 +// +build !386,!amd64,!amd64p32,!arm64 + +package cpu + +func archInit() { + if err := readHWCAP(); err != nil { + return + } + doinit() + Initialized = true +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_linux_arm.go b/vendor/golang.org/x/sys/cpu/cpu_linux_arm.go new file mode 100644 index 0000000000..2057006dce --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_linux_arm.go @@ -0,0 +1,39 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cpu + +func doinit() { + ARM.HasSWP = isSet(hwCap, hwcap_SWP) + ARM.HasHALF = isSet(hwCap, hwcap_HALF) + ARM.HasTHUMB = isSet(hwCap, hwcap_THUMB) + ARM.Has26BIT = isSet(hwCap, hwcap_26BIT) + ARM.HasFASTMUL = isSet(hwCap, hwcap_FAST_MULT) + ARM.HasFPA = isSet(hwCap, hwcap_FPA) + ARM.HasVFP = isSet(hwCap, hwcap_VFP) + ARM.HasEDSP = isSet(hwCap, hwcap_EDSP) + ARM.HasJAVA = isSet(hwCap, hwcap_JAVA) + ARM.HasIWMMXT = isSet(hwCap, hwcap_IWMMXT) + ARM.HasCRUNCH = isSet(hwCap, hwcap_CRUNCH) + ARM.HasTHUMBEE = isSet(hwCap, hwcap_THUMBEE) + ARM.HasNEON = isSet(hwCap, hwcap_NEON) + ARM.HasVFPv3 = isSet(hwCap, hwcap_VFPv3) + ARM.HasVFPv3D16 = isSet(hwCap, hwcap_VFPv3D16) + ARM.HasTLS = isSet(hwCap, hwcap_TLS) + ARM.HasVFPv4 = isSet(hwCap, hwcap_VFPv4) + ARM.HasIDIVA = isSet(hwCap, hwcap_IDIVA) + ARM.HasIDIVT = isSet(hwCap, hwcap_IDIVT) + ARM.HasVFPD32 = isSet(hwCap, hwcap_VFPD32) + ARM.HasLPAE = isSet(hwCap, hwcap_LPAE) + ARM.HasEVTSTRM = isSet(hwCap, hwcap_EVTSTRM) + ARM.HasAES = isSet(hwCap2, hwcap2_AES) + ARM.HasPMULL = isSet(hwCap2, hwcap2_PMULL) + ARM.HasSHA1 = isSet(hwCap2, hwcap2_SHA1) + ARM.HasSHA2 = isSet(hwCap2, hwcap2_SHA2) + ARM.HasCRC32 = isSet(hwCap2, hwcap2_CRC32) +} + +func isSet(hwc uint, value uint) bool { + return hwc&value != 0 +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_linux_arm64.go b/vendor/golang.org/x/sys/cpu/cpu_linux_arm64.go new file mode 100644 index 0000000000..a968b80fa6 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_linux_arm64.go @@ -0,0 +1,111 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cpu + +import ( + "strings" + "syscall" +) + +// HWCAP/HWCAP2 bits. These are exposed by Linux. +const ( + hwcap_FP = 1 << 0 + hwcap_ASIMD = 1 << 1 + hwcap_EVTSTRM = 1 << 2 + hwcap_AES = 1 << 3 + hwcap_PMULL = 1 << 4 + hwcap_SHA1 = 1 << 5 + hwcap_SHA2 = 1 << 6 + hwcap_CRC32 = 1 << 7 + hwcap_ATOMICS = 1 << 8 + hwcap_FPHP = 1 << 9 + hwcap_ASIMDHP = 1 << 10 + hwcap_CPUID = 1 << 11 + hwcap_ASIMDRDM = 1 << 12 + hwcap_JSCVT = 1 << 13 + hwcap_FCMA = 1 << 14 + hwcap_LRCPC = 1 << 15 + hwcap_DCPOP = 1 << 16 + hwcap_SHA3 = 1 << 17 + hwcap_SM3 = 1 << 18 + hwcap_SM4 = 1 << 19 + hwcap_ASIMDDP = 1 << 20 + hwcap_SHA512 = 1 << 21 + hwcap_SVE = 1 << 22 + hwcap_ASIMDFHM = 1 << 23 +) + +// linuxKernelCanEmulateCPUID reports whether we're running +// on Linux 4.11+. Ideally we'd like to ask the question about +// whether the current kernel contains +// https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=77c97b4ee21290f5f083173d957843b615abbff2 +// but the version number will have to do. +func linuxKernelCanEmulateCPUID() bool { + var un syscall.Utsname + syscall.Uname(&un) + var sb strings.Builder + for _, b := range un.Release[:] { + if b == 0 { + break + } + sb.WriteByte(byte(b)) + } + major, minor, _, ok := parseRelease(sb.String()) + return ok && (major > 4 || major == 4 && minor >= 11) +} + +func doinit() { + if err := readHWCAP(); err != nil { + // We failed to read /proc/self/auxv. This can happen if the binary has + // been given extra capabilities(7) with /bin/setcap. + // + // When this happens, we have two options. If the Linux kernel is new + // enough (4.11+), we can read the arm64 registers directly which'll + // trap into the kernel and then return back to userspace. + // + // But on older kernels, such as Linux 4.4.180 as used on many Synology + // devices, calling readARM64Registers (specifically getisar0) will + // cause a SIGILL and we'll die. So for older kernels, parse /proc/cpuinfo + // instead. + // + // See golang/go#57336. + if linuxKernelCanEmulateCPUID() { + readARM64Registers() + } else { + readLinuxProcCPUInfo() + } + return + } + + // HWCAP feature bits + ARM64.HasFP = isSet(hwCap, hwcap_FP) + ARM64.HasASIMD = isSet(hwCap, hwcap_ASIMD) + ARM64.HasEVTSTRM = isSet(hwCap, hwcap_EVTSTRM) + ARM64.HasAES = isSet(hwCap, hwcap_AES) + ARM64.HasPMULL = isSet(hwCap, hwcap_PMULL) + ARM64.HasSHA1 = isSet(hwCap, hwcap_SHA1) + ARM64.HasSHA2 = isSet(hwCap, hwcap_SHA2) + ARM64.HasCRC32 = isSet(hwCap, hwcap_CRC32) + ARM64.HasATOMICS = isSet(hwCap, hwcap_ATOMICS) + ARM64.HasFPHP = isSet(hwCap, hwcap_FPHP) + ARM64.HasASIMDHP = isSet(hwCap, hwcap_ASIMDHP) + ARM64.HasCPUID = isSet(hwCap, hwcap_CPUID) + ARM64.HasASIMDRDM = isSet(hwCap, hwcap_ASIMDRDM) + ARM64.HasJSCVT = isSet(hwCap, hwcap_JSCVT) + ARM64.HasFCMA = isSet(hwCap, hwcap_FCMA) + ARM64.HasLRCPC = isSet(hwCap, hwcap_LRCPC) + ARM64.HasDCPOP = isSet(hwCap, hwcap_DCPOP) + ARM64.HasSHA3 = isSet(hwCap, hwcap_SHA3) + ARM64.HasSM3 = isSet(hwCap, hwcap_SM3) + ARM64.HasSM4 = isSet(hwCap, hwcap_SM4) + ARM64.HasASIMDDP = isSet(hwCap, hwcap_ASIMDDP) + ARM64.HasSHA512 = isSet(hwCap, hwcap_SHA512) + ARM64.HasSVE = isSet(hwCap, hwcap_SVE) + ARM64.HasASIMDFHM = isSet(hwCap, hwcap_ASIMDFHM) +} + +func isSet(hwc uint, value uint) bool { + return hwc&value != 0 +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_linux_mips64x.go b/vendor/golang.org/x/sys/cpu/cpu_linux_mips64x.go new file mode 100644 index 0000000000..6000db4cdd --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_linux_mips64x.go @@ -0,0 +1,24 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build linux && (mips64 || mips64le) +// +build linux +// +build mips64 mips64le + +package cpu + +// HWCAP bits. These are exposed by the Linux kernel 5.4. +const ( + // CPU features + hwcap_MIPS_MSA = 1 << 1 +) + +func doinit() { + // HWCAP feature bits + MIPS64X.HasMSA = isSet(hwCap, hwcap_MIPS_MSA) +} + +func isSet(hwc uint, value uint) bool { + return hwc&value != 0 +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_linux_noinit.go b/vendor/golang.org/x/sys/cpu/cpu_linux_noinit.go new file mode 100644 index 0000000000..f4992b1a59 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_linux_noinit.go @@ -0,0 +1,10 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build linux && !arm && !arm64 && !mips64 && !mips64le && !ppc64 && !ppc64le && !s390x +// +build linux,!arm,!arm64,!mips64,!mips64le,!ppc64,!ppc64le,!s390x + +package cpu + +func doinit() {} diff --git a/vendor/golang.org/x/sys/cpu/cpu_linux_ppc64x.go b/vendor/golang.org/x/sys/cpu/cpu_linux_ppc64x.go new file mode 100644 index 0000000000..021356d6de --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_linux_ppc64x.go @@ -0,0 +1,32 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build linux && (ppc64 || ppc64le) +// +build linux +// +build ppc64 ppc64le + +package cpu + +// HWCAP/HWCAP2 bits. These are exposed by the kernel. +const ( + // ISA Level + _PPC_FEATURE2_ARCH_2_07 = 0x80000000 + _PPC_FEATURE2_ARCH_3_00 = 0x00800000 + + // CPU features + _PPC_FEATURE2_DARN = 0x00200000 + _PPC_FEATURE2_SCV = 0x00100000 +) + +func doinit() { + // HWCAP2 feature bits + PPC64.IsPOWER8 = isSet(hwCap2, _PPC_FEATURE2_ARCH_2_07) + PPC64.IsPOWER9 = isSet(hwCap2, _PPC_FEATURE2_ARCH_3_00) + PPC64.HasDARN = isSet(hwCap2, _PPC_FEATURE2_DARN) + PPC64.HasSCV = isSet(hwCap2, _PPC_FEATURE2_SCV) +} + +func isSet(hwc uint, value uint) bool { + return hwc&value != 0 +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_linux_s390x.go b/vendor/golang.org/x/sys/cpu/cpu_linux_s390x.go new file mode 100644 index 0000000000..1517ac61d3 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_linux_s390x.go @@ -0,0 +1,40 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cpu + +const ( + // bit mask values from /usr/include/bits/hwcap.h + hwcap_ZARCH = 2 + hwcap_STFLE = 4 + hwcap_MSA = 8 + hwcap_LDISP = 16 + hwcap_EIMM = 32 + hwcap_DFP = 64 + hwcap_ETF3EH = 256 + hwcap_VX = 2048 + hwcap_VXE = 8192 +) + +func initS390Xbase() { + // test HWCAP bit vector + has := func(featureMask uint) bool { + return hwCap&featureMask == featureMask + } + + // mandatory + S390X.HasZARCH = has(hwcap_ZARCH) + + // optional + S390X.HasSTFLE = has(hwcap_STFLE) + S390X.HasLDISP = has(hwcap_LDISP) + S390X.HasEIMM = has(hwcap_EIMM) + S390X.HasETF3EH = has(hwcap_ETF3EH) + S390X.HasDFP = has(hwcap_DFP) + S390X.HasMSA = has(hwcap_MSA) + S390X.HasVX = has(hwcap_VX) + if S390X.HasVX { + S390X.HasVXE = has(hwcap_VXE) + } +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_loong64.go b/vendor/golang.org/x/sys/cpu/cpu_loong64.go new file mode 100644 index 0000000000..0f57b05bdb --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_loong64.go @@ -0,0 +1,13 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build loong64 +// +build loong64 + +package cpu + +const cacheLineSize = 64 + +func initOptions() { +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_mips64x.go b/vendor/golang.org/x/sys/cpu/cpu_mips64x.go new file mode 100644 index 0000000000..f4063c6642 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_mips64x.go @@ -0,0 +1,16 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build mips64 || mips64le +// +build mips64 mips64le + +package cpu + +const cacheLineSize = 32 + +func initOptions() { + options = []option{ + {Name: "msa", Feature: &MIPS64X.HasMSA}, + } +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_mipsx.go b/vendor/golang.org/x/sys/cpu/cpu_mipsx.go new file mode 100644 index 0000000000..07c4e36d8f --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_mipsx.go @@ -0,0 +1,12 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build mips || mipsle +// +build mips mipsle + +package cpu + +const cacheLineSize = 32 + +func initOptions() {} diff --git a/vendor/golang.org/x/sys/cpu/cpu_netbsd_arm64.go b/vendor/golang.org/x/sys/cpu/cpu_netbsd_arm64.go new file mode 100644 index 0000000000..ebfb3fc8e7 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_netbsd_arm64.go @@ -0,0 +1,173 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cpu + +import ( + "syscall" + "unsafe" +) + +// Minimal copy of functionality from x/sys/unix so the cpu package can call +// sysctl without depending on x/sys/unix. + +const ( + _CTL_QUERY = -2 + + _SYSCTL_VERS_1 = 0x1000000 +) + +var _zero uintptr + +func sysctl(mib []int32, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) { + var _p0 unsafe.Pointer + if len(mib) > 0 { + _p0 = unsafe.Pointer(&mib[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, errno := syscall.Syscall6( + syscall.SYS___SYSCTL, + uintptr(_p0), + uintptr(len(mib)), + uintptr(unsafe.Pointer(old)), + uintptr(unsafe.Pointer(oldlen)), + uintptr(unsafe.Pointer(new)), + uintptr(newlen)) + if errno != 0 { + return errno + } + return nil +} + +type sysctlNode struct { + Flags uint32 + Num int32 + Name [32]int8 + Ver uint32 + __rsvd uint32 + Un [16]byte + _sysctl_size [8]byte + _sysctl_func [8]byte + _sysctl_parent [8]byte + _sysctl_desc [8]byte +} + +func sysctlNodes(mib []int32) ([]sysctlNode, error) { + var olen uintptr + + // Get a list of all sysctl nodes below the given MIB by performing + // a sysctl for the given MIB with CTL_QUERY appended. + mib = append(mib, _CTL_QUERY) + qnode := sysctlNode{Flags: _SYSCTL_VERS_1} + qp := (*byte)(unsafe.Pointer(&qnode)) + sz := unsafe.Sizeof(qnode) + if err := sysctl(mib, nil, &olen, qp, sz); err != nil { + return nil, err + } + + // Now that we know the size, get the actual nodes. + nodes := make([]sysctlNode, olen/sz) + np := (*byte)(unsafe.Pointer(&nodes[0])) + if err := sysctl(mib, np, &olen, qp, sz); err != nil { + return nil, err + } + + return nodes, nil +} + +func nametomib(name string) ([]int32, error) { + // Split name into components. + var parts []string + last := 0 + for i := 0; i < len(name); i++ { + if name[i] == '.' { + parts = append(parts, name[last:i]) + last = i + 1 + } + } + parts = append(parts, name[last:]) + + mib := []int32{} + // Discover the nodes and construct the MIB OID. + for partno, part := range parts { + nodes, err := sysctlNodes(mib) + if err != nil { + return nil, err + } + for _, node := range nodes { + n := make([]byte, 0) + for i := range node.Name { + if node.Name[i] != 0 { + n = append(n, byte(node.Name[i])) + } + } + if string(n) == part { + mib = append(mib, int32(node.Num)) + break + } + } + if len(mib) != partno+1 { + return nil, err + } + } + + return mib, nil +} + +// aarch64SysctlCPUID is struct aarch64_sysctl_cpu_id from NetBSD's +type aarch64SysctlCPUID struct { + midr uint64 /* Main ID Register */ + revidr uint64 /* Revision ID Register */ + mpidr uint64 /* Multiprocessor Affinity Register */ + aa64dfr0 uint64 /* A64 Debug Feature Register 0 */ + aa64dfr1 uint64 /* A64 Debug Feature Register 1 */ + aa64isar0 uint64 /* A64 Instruction Set Attribute Register 0 */ + aa64isar1 uint64 /* A64 Instruction Set Attribute Register 1 */ + aa64mmfr0 uint64 /* A64 Memory Model Feature Register 0 */ + aa64mmfr1 uint64 /* A64 Memory Model Feature Register 1 */ + aa64mmfr2 uint64 /* A64 Memory Model Feature Register 2 */ + aa64pfr0 uint64 /* A64 Processor Feature Register 0 */ + aa64pfr1 uint64 /* A64 Processor Feature Register 1 */ + aa64zfr0 uint64 /* A64 SVE Feature ID Register 0 */ + mvfr0 uint32 /* Media and VFP Feature Register 0 */ + mvfr1 uint32 /* Media and VFP Feature Register 1 */ + mvfr2 uint32 /* Media and VFP Feature Register 2 */ + pad uint32 + clidr uint64 /* Cache Level ID Register */ + ctr uint64 /* Cache Type Register */ +} + +func sysctlCPUID(name string) (*aarch64SysctlCPUID, error) { + mib, err := nametomib(name) + if err != nil { + return nil, err + } + + out := aarch64SysctlCPUID{} + n := unsafe.Sizeof(out) + _, _, errno := syscall.Syscall6( + syscall.SYS___SYSCTL, + uintptr(unsafe.Pointer(&mib[0])), + uintptr(len(mib)), + uintptr(unsafe.Pointer(&out)), + uintptr(unsafe.Pointer(&n)), + uintptr(0), + uintptr(0)) + if errno != 0 { + return nil, errno + } + return &out, nil +} + +func doinit() { + cpuid, err := sysctlCPUID("machdep.cpu0.cpu_id") + if err != nil { + setMinimalFeatures() + return + } + parseARM64SystemRegisters(cpuid.aa64isar0, cpuid.aa64isar1, cpuid.aa64pfr0) + + Initialized = true +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_openbsd_arm64.go b/vendor/golang.org/x/sys/cpu/cpu_openbsd_arm64.go new file mode 100644 index 0000000000..85b64d5ccb --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_openbsd_arm64.go @@ -0,0 +1,65 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cpu + +import ( + "syscall" + "unsafe" +) + +// Minimal copy of functionality from x/sys/unix so the cpu package can call +// sysctl without depending on x/sys/unix. + +const ( + // From OpenBSD's sys/sysctl.h. + _CTL_MACHDEP = 7 + + // From OpenBSD's machine/cpu.h. + _CPU_ID_AA64ISAR0 = 2 + _CPU_ID_AA64ISAR1 = 3 +) + +// Implemented in the runtime package (runtime/sys_openbsd3.go) +func syscall_syscall6(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err syscall.Errno) + +//go:linkname syscall_syscall6 syscall.syscall6 + +func sysctl(mib []uint32, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) { + _, _, errno := syscall_syscall6(libc_sysctl_trampoline_addr, uintptr(unsafe.Pointer(&mib[0])), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen)) + if errno != 0 { + return errno + } + return nil +} + +var libc_sysctl_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_sysctl sysctl "libc.so" + +func sysctlUint64(mib []uint32) (uint64, bool) { + var out uint64 + nout := unsafe.Sizeof(out) + if err := sysctl(mib, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0); err != nil { + return 0, false + } + return out, true +} + +func doinit() { + setMinimalFeatures() + + // Get ID_AA64ISAR0 and ID_AA64ISAR1 from sysctl. + isar0, ok := sysctlUint64([]uint32{_CTL_MACHDEP, _CPU_ID_AA64ISAR0}) + if !ok { + return + } + isar1, ok := sysctlUint64([]uint32{_CTL_MACHDEP, _CPU_ID_AA64ISAR1}) + if !ok { + return + } + parseARM64SystemRegisters(isar0, isar1, 0) + + Initialized = true +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_openbsd_arm64.s b/vendor/golang.org/x/sys/cpu/cpu_openbsd_arm64.s new file mode 100644 index 0000000000..054ba05d60 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_openbsd_arm64.s @@ -0,0 +1,11 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "textflag.h" + +TEXT libc_sysctl_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_sysctl(SB) + +GLOBL ·libc_sysctl_trampoline_addr(SB), RODATA, $8 +DATA ·libc_sysctl_trampoline_addr(SB)/8, $libc_sysctl_trampoline<>(SB) diff --git a/vendor/golang.org/x/sys/cpu/cpu_other_arm.go b/vendor/golang.org/x/sys/cpu/cpu_other_arm.go new file mode 100644 index 0000000000..d7b4fb4ccc --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_other_arm.go @@ -0,0 +1,10 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !linux && arm +// +build !linux,arm + +package cpu + +func archInit() {} diff --git a/vendor/golang.org/x/sys/cpu/cpu_other_arm64.go b/vendor/golang.org/x/sys/cpu/cpu_other_arm64.go new file mode 100644 index 0000000000..f3cde129b6 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_other_arm64.go @@ -0,0 +1,10 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !linux && !netbsd && !openbsd && arm64 +// +build !linux,!netbsd,!openbsd,arm64 + +package cpu + +func doinit() {} diff --git a/vendor/golang.org/x/sys/cpu/cpu_other_mips64x.go b/vendor/golang.org/x/sys/cpu/cpu_other_mips64x.go new file mode 100644 index 0000000000..0dafe9644a --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_other_mips64x.go @@ -0,0 +1,13 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !linux && (mips64 || mips64le) +// +build !linux +// +build mips64 mips64le + +package cpu + +func archInit() { + Initialized = true +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_other_ppc64x.go b/vendor/golang.org/x/sys/cpu/cpu_other_ppc64x.go new file mode 100644 index 0000000000..060d46b6ea --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_other_ppc64x.go @@ -0,0 +1,15 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !aix && !linux && (ppc64 || ppc64le) +// +build !aix +// +build !linux +// +build ppc64 ppc64le + +package cpu + +func archInit() { + PPC64.IsPOWER8 = true + Initialized = true +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_other_riscv64.go b/vendor/golang.org/x/sys/cpu/cpu_other_riscv64.go new file mode 100644 index 0000000000..dd10eb79fe --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_other_riscv64.go @@ -0,0 +1,12 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !linux && riscv64 +// +build !linux,riscv64 + +package cpu + +func archInit() { + Initialized = true +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_ppc64x.go b/vendor/golang.org/x/sys/cpu/cpu_ppc64x.go new file mode 100644 index 0000000000..4e8acd1658 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_ppc64x.go @@ -0,0 +1,17 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build ppc64 || ppc64le +// +build ppc64 ppc64le + +package cpu + +const cacheLineSize = 128 + +func initOptions() { + options = []option{ + {Name: "darn", Feature: &PPC64.HasDARN}, + {Name: "scv", Feature: &PPC64.HasSCV}, + } +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_riscv64.go b/vendor/golang.org/x/sys/cpu/cpu_riscv64.go new file mode 100644 index 0000000000..bd6c128af9 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_riscv64.go @@ -0,0 +1,12 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build riscv64 +// +build riscv64 + +package cpu + +const cacheLineSize = 32 + +func initOptions() {} diff --git a/vendor/golang.org/x/sys/cpu/cpu_s390x.go b/vendor/golang.org/x/sys/cpu/cpu_s390x.go new file mode 100644 index 0000000000..5881b8833f --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_s390x.go @@ -0,0 +1,172 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cpu + +const cacheLineSize = 256 + +func initOptions() { + options = []option{ + {Name: "zarch", Feature: &S390X.HasZARCH, Required: true}, + {Name: "stfle", Feature: &S390X.HasSTFLE, Required: true}, + {Name: "ldisp", Feature: &S390X.HasLDISP, Required: true}, + {Name: "eimm", Feature: &S390X.HasEIMM, Required: true}, + {Name: "dfp", Feature: &S390X.HasDFP}, + {Name: "etf3eh", Feature: &S390X.HasETF3EH}, + {Name: "msa", Feature: &S390X.HasMSA}, + {Name: "aes", Feature: &S390X.HasAES}, + {Name: "aescbc", Feature: &S390X.HasAESCBC}, + {Name: "aesctr", Feature: &S390X.HasAESCTR}, + {Name: "aesgcm", Feature: &S390X.HasAESGCM}, + {Name: "ghash", Feature: &S390X.HasGHASH}, + {Name: "sha1", Feature: &S390X.HasSHA1}, + {Name: "sha256", Feature: &S390X.HasSHA256}, + {Name: "sha3", Feature: &S390X.HasSHA3}, + {Name: "sha512", Feature: &S390X.HasSHA512}, + {Name: "vx", Feature: &S390X.HasVX}, + {Name: "vxe", Feature: &S390X.HasVXE}, + } +} + +// bitIsSet reports whether the bit at index is set. The bit index +// is in big endian order, so bit index 0 is the leftmost bit. +func bitIsSet(bits []uint64, index uint) bool { + return bits[index/64]&((1<<63)>>(index%64)) != 0 +} + +// facility is a bit index for the named facility. +type facility uint8 + +const ( + // mandatory facilities + zarch facility = 1 // z architecture mode is active + stflef facility = 7 // store-facility-list-extended + ldisp facility = 18 // long-displacement + eimm facility = 21 // extended-immediate + + // miscellaneous facilities + dfp facility = 42 // decimal-floating-point + etf3eh facility = 30 // extended-translation 3 enhancement + + // cryptography facilities + msa facility = 17 // message-security-assist + msa3 facility = 76 // message-security-assist extension 3 + msa4 facility = 77 // message-security-assist extension 4 + msa5 facility = 57 // message-security-assist extension 5 + msa8 facility = 146 // message-security-assist extension 8 + msa9 facility = 155 // message-security-assist extension 9 + + // vector facilities + vx facility = 129 // vector facility + vxe facility = 135 // vector-enhancements 1 + vxe2 facility = 148 // vector-enhancements 2 +) + +// facilityList contains the result of an STFLE call. +// Bits are numbered in big endian order so the +// leftmost bit (the MSB) is at index 0. +type facilityList struct { + bits [4]uint64 +} + +// Has reports whether the given facilities are present. +func (s *facilityList) Has(fs ...facility) bool { + if len(fs) == 0 { + panic("no facility bits provided") + } + for _, f := range fs { + if !bitIsSet(s.bits[:], uint(f)) { + return false + } + } + return true +} + +// function is the code for the named cryptographic function. +type function uint8 + +const ( + // KM{,A,C,CTR} function codes + aes128 function = 18 // AES-128 + aes192 function = 19 // AES-192 + aes256 function = 20 // AES-256 + + // K{I,L}MD function codes + sha1 function = 1 // SHA-1 + sha256 function = 2 // SHA-256 + sha512 function = 3 // SHA-512 + sha3_224 function = 32 // SHA3-224 + sha3_256 function = 33 // SHA3-256 + sha3_384 function = 34 // SHA3-384 + sha3_512 function = 35 // SHA3-512 + shake128 function = 36 // SHAKE-128 + shake256 function = 37 // SHAKE-256 + + // KLMD function codes + ghash function = 65 // GHASH +) + +// queryResult contains the result of a Query function +// call. Bits are numbered in big endian order so the +// leftmost bit (the MSB) is at index 0. +type queryResult struct { + bits [2]uint64 +} + +// Has reports whether the given functions are present. +func (q *queryResult) Has(fns ...function) bool { + if len(fns) == 0 { + panic("no function codes provided") + } + for _, f := range fns { + if !bitIsSet(q.bits[:], uint(f)) { + return false + } + } + return true +} + +func doinit() { + initS390Xbase() + + // We need implementations of stfle, km and so on + // to detect cryptographic features. + if !haveAsmFunctions() { + return + } + + // optional cryptographic functions + if S390X.HasMSA { + aes := []function{aes128, aes192, aes256} + + // cipher message + km, kmc := kmQuery(), kmcQuery() + S390X.HasAES = km.Has(aes...) + S390X.HasAESCBC = kmc.Has(aes...) + if S390X.HasSTFLE { + facilities := stfle() + if facilities.Has(msa4) { + kmctr := kmctrQuery() + S390X.HasAESCTR = kmctr.Has(aes...) + } + if facilities.Has(msa8) { + kma := kmaQuery() + S390X.HasAESGCM = kma.Has(aes...) + } + } + + // compute message digest + kimd := kimdQuery() // intermediate (no padding) + klmd := klmdQuery() // last (padding) + S390X.HasSHA1 = kimd.Has(sha1) && klmd.Has(sha1) + S390X.HasSHA256 = kimd.Has(sha256) && klmd.Has(sha256) + S390X.HasSHA512 = kimd.Has(sha512) && klmd.Has(sha512) + S390X.HasGHASH = kimd.Has(ghash) // KLMD-GHASH does not exist + sha3 := []function{ + sha3_224, sha3_256, sha3_384, sha3_512, + shake128, shake256, + } + S390X.HasSHA3 = kimd.Has(sha3...) && klmd.Has(sha3...) + } +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_s390x.s b/vendor/golang.org/x/sys/cpu/cpu_s390x.s new file mode 100644 index 0000000000..96f81e2097 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_s390x.s @@ -0,0 +1,58 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build gc +// +build gc + +#include "textflag.h" + +// func stfle() facilityList +TEXT ·stfle(SB), NOSPLIT|NOFRAME, $0-32 + MOVD $ret+0(FP), R1 + MOVD $3, R0 // last doubleword index to store + XC $32, (R1), (R1) // clear 4 doublewords (32 bytes) + WORD $0xb2b01000 // store facility list extended (STFLE) + RET + +// func kmQuery() queryResult +TEXT ·kmQuery(SB), NOSPLIT|NOFRAME, $0-16 + MOVD $0, R0 // set function code to 0 (KM-Query) + MOVD $ret+0(FP), R1 // address of 16-byte return value + WORD $0xB92E0024 // cipher message (KM) + RET + +// func kmcQuery() queryResult +TEXT ·kmcQuery(SB), NOSPLIT|NOFRAME, $0-16 + MOVD $0, R0 // set function code to 0 (KMC-Query) + MOVD $ret+0(FP), R1 // address of 16-byte return value + WORD $0xB92F0024 // cipher message with chaining (KMC) + RET + +// func kmctrQuery() queryResult +TEXT ·kmctrQuery(SB), NOSPLIT|NOFRAME, $0-16 + MOVD $0, R0 // set function code to 0 (KMCTR-Query) + MOVD $ret+0(FP), R1 // address of 16-byte return value + WORD $0xB92D4024 // cipher message with counter (KMCTR) + RET + +// func kmaQuery() queryResult +TEXT ·kmaQuery(SB), NOSPLIT|NOFRAME, $0-16 + MOVD $0, R0 // set function code to 0 (KMA-Query) + MOVD $ret+0(FP), R1 // address of 16-byte return value + WORD $0xb9296024 // cipher message with authentication (KMA) + RET + +// func kimdQuery() queryResult +TEXT ·kimdQuery(SB), NOSPLIT|NOFRAME, $0-16 + MOVD $0, R0 // set function code to 0 (KIMD-Query) + MOVD $ret+0(FP), R1 // address of 16-byte return value + WORD $0xB93E0024 // compute intermediate message digest (KIMD) + RET + +// func klmdQuery() queryResult +TEXT ·klmdQuery(SB), NOSPLIT|NOFRAME, $0-16 + MOVD $0, R0 // set function code to 0 (KLMD-Query) + MOVD $ret+0(FP), R1 // address of 16-byte return value + WORD $0xB93F0024 // compute last message digest (KLMD) + RET diff --git a/vendor/golang.org/x/sys/cpu/cpu_wasm.go b/vendor/golang.org/x/sys/cpu/cpu_wasm.go new file mode 100644 index 0000000000..7747d888a6 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_wasm.go @@ -0,0 +1,18 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build wasm +// +build wasm + +package cpu + +// We're compiling the cpu package for an unknown (software-abstracted) CPU. +// Make CacheLinePad an empty struct and hope that the usual struct alignment +// rules are good enough. + +const cacheLineSize = 0 + +func initOptions() {} + +func archInit() {} diff --git a/vendor/golang.org/x/sys/cpu/cpu_x86.go b/vendor/golang.org/x/sys/cpu/cpu_x86.go new file mode 100644 index 0000000000..f5aacfc825 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_x86.go @@ -0,0 +1,145 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build 386 || amd64 || amd64p32 +// +build 386 amd64 amd64p32 + +package cpu + +import "runtime" + +const cacheLineSize = 64 + +func initOptions() { + options = []option{ + {Name: "adx", Feature: &X86.HasADX}, + {Name: "aes", Feature: &X86.HasAES}, + {Name: "avx", Feature: &X86.HasAVX}, + {Name: "avx2", Feature: &X86.HasAVX2}, + {Name: "avx512", Feature: &X86.HasAVX512}, + {Name: "avx512f", Feature: &X86.HasAVX512F}, + {Name: "avx512cd", Feature: &X86.HasAVX512CD}, + {Name: "avx512er", Feature: &X86.HasAVX512ER}, + {Name: "avx512pf", Feature: &X86.HasAVX512PF}, + {Name: "avx512vl", Feature: &X86.HasAVX512VL}, + {Name: "avx512bw", Feature: &X86.HasAVX512BW}, + {Name: "avx512dq", Feature: &X86.HasAVX512DQ}, + {Name: "avx512ifma", Feature: &X86.HasAVX512IFMA}, + {Name: "avx512vbmi", Feature: &X86.HasAVX512VBMI}, + {Name: "avx512vnniw", Feature: &X86.HasAVX5124VNNIW}, + {Name: "avx5124fmaps", Feature: &X86.HasAVX5124FMAPS}, + {Name: "avx512vpopcntdq", Feature: &X86.HasAVX512VPOPCNTDQ}, + {Name: "avx512vpclmulqdq", Feature: &X86.HasAVX512VPCLMULQDQ}, + {Name: "avx512vnni", Feature: &X86.HasAVX512VNNI}, + {Name: "avx512gfni", Feature: &X86.HasAVX512GFNI}, + {Name: "avx512vaes", Feature: &X86.HasAVX512VAES}, + {Name: "avx512vbmi2", Feature: &X86.HasAVX512VBMI2}, + {Name: "avx512bitalg", Feature: &X86.HasAVX512BITALG}, + {Name: "avx512bf16", Feature: &X86.HasAVX512BF16}, + {Name: "bmi1", Feature: &X86.HasBMI1}, + {Name: "bmi2", Feature: &X86.HasBMI2}, + {Name: "cx16", Feature: &X86.HasCX16}, + {Name: "erms", Feature: &X86.HasERMS}, + {Name: "fma", Feature: &X86.HasFMA}, + {Name: "osxsave", Feature: &X86.HasOSXSAVE}, + {Name: "pclmulqdq", Feature: &X86.HasPCLMULQDQ}, + {Name: "popcnt", Feature: &X86.HasPOPCNT}, + {Name: "rdrand", Feature: &X86.HasRDRAND}, + {Name: "rdseed", Feature: &X86.HasRDSEED}, + {Name: "sse3", Feature: &X86.HasSSE3}, + {Name: "sse41", Feature: &X86.HasSSE41}, + {Name: "sse42", Feature: &X86.HasSSE42}, + {Name: "ssse3", Feature: &X86.HasSSSE3}, + + // These capabilities should always be enabled on amd64: + {Name: "sse2", Feature: &X86.HasSSE2, Required: runtime.GOARCH == "amd64"}, + } +} + +func archInit() { + + Initialized = true + + maxID, _, _, _ := cpuid(0, 0) + + if maxID < 1 { + return + } + + _, _, ecx1, edx1 := cpuid(1, 0) + X86.HasSSE2 = isSet(26, edx1) + + X86.HasSSE3 = isSet(0, ecx1) + X86.HasPCLMULQDQ = isSet(1, ecx1) + X86.HasSSSE3 = isSet(9, ecx1) + X86.HasFMA = isSet(12, ecx1) + X86.HasCX16 = isSet(13, ecx1) + X86.HasSSE41 = isSet(19, ecx1) + X86.HasSSE42 = isSet(20, ecx1) + X86.HasPOPCNT = isSet(23, ecx1) + X86.HasAES = isSet(25, ecx1) + X86.HasOSXSAVE = isSet(27, ecx1) + X86.HasRDRAND = isSet(30, ecx1) + + var osSupportsAVX, osSupportsAVX512 bool + // For XGETBV, OSXSAVE bit is required and sufficient. + if X86.HasOSXSAVE { + eax, _ := xgetbv() + // Check if XMM and YMM registers have OS support. + osSupportsAVX = isSet(1, eax) && isSet(2, eax) + + if runtime.GOOS == "darwin" { + // Darwin doesn't save/restore AVX-512 mask registers correctly across signal handlers. + // Since users can't rely on mask register contents, let's not advertise AVX-512 support. + // See issue 49233. + osSupportsAVX512 = false + } else { + // Check if OPMASK and ZMM registers have OS support. + osSupportsAVX512 = osSupportsAVX && isSet(5, eax) && isSet(6, eax) && isSet(7, eax) + } + } + + X86.HasAVX = isSet(28, ecx1) && osSupportsAVX + + if maxID < 7 { + return + } + + _, ebx7, ecx7, edx7 := cpuid(7, 0) + X86.HasBMI1 = isSet(3, ebx7) + X86.HasAVX2 = isSet(5, ebx7) && osSupportsAVX + X86.HasBMI2 = isSet(8, ebx7) + X86.HasERMS = isSet(9, ebx7) + X86.HasRDSEED = isSet(18, ebx7) + X86.HasADX = isSet(19, ebx7) + + X86.HasAVX512 = isSet(16, ebx7) && osSupportsAVX512 // Because avx-512 foundation is the core required extension + if X86.HasAVX512 { + X86.HasAVX512F = true + X86.HasAVX512CD = isSet(28, ebx7) + X86.HasAVX512ER = isSet(27, ebx7) + X86.HasAVX512PF = isSet(26, ebx7) + X86.HasAVX512VL = isSet(31, ebx7) + X86.HasAVX512BW = isSet(30, ebx7) + X86.HasAVX512DQ = isSet(17, ebx7) + X86.HasAVX512IFMA = isSet(21, ebx7) + X86.HasAVX512VBMI = isSet(1, ecx7) + X86.HasAVX5124VNNIW = isSet(2, edx7) + X86.HasAVX5124FMAPS = isSet(3, edx7) + X86.HasAVX512VPOPCNTDQ = isSet(14, ecx7) + X86.HasAVX512VPCLMULQDQ = isSet(10, ecx7) + X86.HasAVX512VNNI = isSet(11, ecx7) + X86.HasAVX512GFNI = isSet(8, ecx7) + X86.HasAVX512VAES = isSet(9, ecx7) + X86.HasAVX512VBMI2 = isSet(6, ecx7) + X86.HasAVX512BITALG = isSet(12, ecx7) + + eax71, _, _, _ := cpuid(7, 1) + X86.HasAVX512BF16 = isSet(5, eax71) + } +} + +func isSet(bitpos uint, value uint32) bool { + return value&(1<> 63)) +) + +// For those platforms don't have a 'cpuid' equivalent we use HWCAP/HWCAP2 +// These are initialized in cpu_$GOARCH.go +// and should not be changed after they are initialized. +var hwCap uint +var hwCap2 uint + +func readHWCAP() error { + // For Go 1.21+, get auxv from the Go runtime. + if a := getAuxv(); len(a) > 0 { + for len(a) >= 2 { + tag, val := a[0], uint(a[1]) + a = a[2:] + switch tag { + case _AT_HWCAP: + hwCap = val + case _AT_HWCAP2: + hwCap2 = val + } + } + return nil + } + + buf, err := ioutil.ReadFile(procAuxv) + if err != nil { + // e.g. on android /proc/self/auxv is not accessible, so silently + // ignore the error and leave Initialized = false. On some + // architectures (e.g. arm64) doinit() implements a fallback + // readout and will set Initialized = true again. + return err + } + bo := hostByteOrder() + for len(buf) >= 2*(uintSize/8) { + var tag, val uint + switch uintSize { + case 32: + tag = uint(bo.Uint32(buf[0:])) + val = uint(bo.Uint32(buf[4:])) + buf = buf[8:] + case 64: + tag = uint(bo.Uint64(buf[0:])) + val = uint(bo.Uint64(buf[8:])) + buf = buf[16:] + } + switch tag { + case _AT_HWCAP: + hwCap = val + case _AT_HWCAP2: + hwCap2 = val + } + } + return nil +} diff --git a/vendor/golang.org/x/sys/cpu/parse.go b/vendor/golang.org/x/sys/cpu/parse.go new file mode 100644 index 0000000000..762b63d688 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/parse.go @@ -0,0 +1,43 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cpu + +import "strconv" + +// parseRelease parses a dot-separated version number. It follows the semver +// syntax, but allows the minor and patch versions to be elided. +// +// This is a copy of the Go runtime's parseRelease from +// https://golang.org/cl/209597. +func parseRelease(rel string) (major, minor, patch int, ok bool) { + // Strip anything after a dash or plus. + for i := 0; i < len(rel); i++ { + if rel[i] == '-' || rel[i] == '+' { + rel = rel[:i] + break + } + } + + next := func() (int, bool) { + for i := 0; i < len(rel); i++ { + if rel[i] == '.' { + ver, err := strconv.Atoi(rel[:i]) + rel = rel[i+1:] + return ver, err == nil + } + } + ver, err := strconv.Atoi(rel) + rel = "" + return ver, err == nil + } + if major, ok = next(); !ok || rel == "" { + return + } + if minor, ok = next(); !ok || rel == "" { + return + } + patch, ok = next() + return +} diff --git a/vendor/golang.org/x/sys/cpu/proc_cpuinfo_linux.go b/vendor/golang.org/x/sys/cpu/proc_cpuinfo_linux.go new file mode 100644 index 0000000000..d87bd6b3eb --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/proc_cpuinfo_linux.go @@ -0,0 +1,54 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build linux && arm64 +// +build linux,arm64 + +package cpu + +import ( + "errors" + "io" + "os" + "strings" +) + +func readLinuxProcCPUInfo() error { + f, err := os.Open("/proc/cpuinfo") + if err != nil { + return err + } + defer f.Close() + + var buf [1 << 10]byte // enough for first CPU + n, err := io.ReadFull(f, buf[:]) + if err != nil && err != io.ErrUnexpectedEOF { + return err + } + in := string(buf[:n]) + const features = "\nFeatures : " + i := strings.Index(in, features) + if i == -1 { + return errors.New("no CPU features found") + } + in = in[i+len(features):] + if i := strings.Index(in, "\n"); i != -1 { + in = in[:i] + } + m := map[string]*bool{} + + initOptions() // need it early here; it's harmless to call twice + for _, o := range options { + m[o.Name] = o.Feature + } + // The EVTSTRM field has alias "evstrm" in Go, but Linux calls it "evtstrm". + m["evtstrm"] = &ARM64.HasEVTSTRM + + for _, f := range strings.Fields(in) { + if p, ok := m[f]; ok { + *p = true + } + } + return nil +} diff --git a/vendor/golang.org/x/sys/cpu/runtime_auxv.go b/vendor/golang.org/x/sys/cpu/runtime_auxv.go new file mode 100644 index 0000000000..5f92ac9a2e --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/runtime_auxv.go @@ -0,0 +1,16 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cpu + +// getAuxvFn is non-nil on Go 1.21+ (via runtime_auxv_go121.go init) +// on platforms that use auxv. +var getAuxvFn func() []uintptr + +func getAuxv() []uintptr { + if getAuxvFn == nil { + return nil + } + return getAuxvFn() +} diff --git a/vendor/golang.org/x/sys/cpu/runtime_auxv_go121.go b/vendor/golang.org/x/sys/cpu/runtime_auxv_go121.go new file mode 100644 index 0000000000..b975ea2a04 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/runtime_auxv_go121.go @@ -0,0 +1,19 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build go1.21 +// +build go1.21 + +package cpu + +import ( + _ "unsafe" // for linkname +) + +//go:linkname runtime_getAuxv runtime.getAuxv +func runtime_getAuxv() []uintptr + +func init() { + getAuxvFn = runtime_getAuxv +} diff --git a/vendor/golang.org/x/sys/cpu/syscall_aix_gccgo.go b/vendor/golang.org/x/sys/cpu/syscall_aix_gccgo.go new file mode 100644 index 0000000000..96134157a1 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/syscall_aix_gccgo.go @@ -0,0 +1,27 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Recreate a getsystemcfg syscall handler instead of +// using the one provided by x/sys/unix to avoid having +// the dependency between them. (See golang.org/issue/32102) +// Moreover, this file will be used during the building of +// gccgo's libgo and thus must not used a CGo method. + +//go:build aix && gccgo +// +build aix,gccgo + +package cpu + +import ( + "syscall" +) + +//extern getsystemcfg +func gccgoGetsystemcfg(label uint32) (r uint64) + +func callgetsystemcfg(label int) (r1 uintptr, e1 syscall.Errno) { + r1 = uintptr(gccgoGetsystemcfg(uint32(label))) + e1 = syscall.GetErrno() + return +} diff --git a/vendor/golang.org/x/sys/cpu/syscall_aix_ppc64_gc.go b/vendor/golang.org/x/sys/cpu/syscall_aix_ppc64_gc.go new file mode 100644 index 0000000000..904be42ffd --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/syscall_aix_ppc64_gc.go @@ -0,0 +1,36 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Minimal copy of x/sys/unix so the cpu package can make a +// system call on AIX without depending on x/sys/unix. +// (See golang.org/issue/32102) + +//go:build aix && ppc64 && gc +// +build aix,ppc64,gc + +package cpu + +import ( + "syscall" + "unsafe" +) + +//go:cgo_import_dynamic libc_getsystemcfg getsystemcfg "libc.a/shr_64.o" + +//go:linkname libc_getsystemcfg libc_getsystemcfg + +type syscallFunc uintptr + +var libc_getsystemcfg syscallFunc + +type errno = syscall.Errno + +// Implemented in runtime/syscall_aix.go. +func rawSyscall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err errno) +func syscall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err errno) + +func callgetsystemcfg(label int) (r1 uintptr, e1 errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_getsystemcfg)), 1, uintptr(label), 0, 0, 0, 0, 0) + return +} diff --git a/vendor/golang.org/x/tools/cmd/stringer/stringer.go b/vendor/golang.org/x/tools/cmd/stringer/stringer.go new file mode 100644 index 0000000000..998d1a51bf --- /dev/null +++ b/vendor/golang.org/x/tools/cmd/stringer/stringer.go @@ -0,0 +1,657 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Stringer is a tool to automate the creation of methods that satisfy the fmt.Stringer +// interface. Given the name of a (signed or unsigned) integer type T that has constants +// defined, stringer will create a new self-contained Go source file implementing +// +// func (t T) String() string +// +// The file is created in the same package and directory as the package that defines T. +// It has helpful defaults designed for use with go generate. +// +// Stringer works best with constants that are consecutive values such as created using iota, +// but creates good code regardless. In the future it might also provide custom support for +// constant sets that are bit patterns. +// +// For example, given this snippet, +// +// package painkiller +// +// type Pill int +// +// const ( +// Placebo Pill = iota +// Aspirin +// Ibuprofen +// Paracetamol +// Acetaminophen = Paracetamol +// ) +// +// running this command +// +// stringer -type=Pill +// +// in the same directory will create the file pill_string.go, in package painkiller, +// containing a definition of +// +// func (Pill) String() string +// +// That method will translate the value of a Pill constant to the string representation +// of the respective constant name, so that the call fmt.Print(painkiller.Aspirin) will +// print the string "Aspirin". +// +// Typically this process would be run using go generate, like this: +// +// //go:generate stringer -type=Pill +// +// If multiple constants have the same value, the lexically first matching name will +// be used (in the example, Acetaminophen will print as "Paracetamol"). +// +// With no arguments, it processes the package in the current directory. +// Otherwise, the arguments must name a single directory holding a Go package +// or a set of Go source files that represent a single Go package. +// +// The -type flag accepts a comma-separated list of types so a single run can +// generate methods for multiple types. The default output file is t_string.go, +// where t is the lower-cased name of the first type listed. It can be overridden +// with the -output flag. +// +// The -linecomment flag tells stringer to generate the text of any line comment, trimmed +// of leading spaces, instead of the constant name. For instance, if the constants above had a +// Pill prefix, one could write +// +// PillAspirin // Aspirin +// +// to suppress it in the output. +package main // import "golang.org/x/tools/cmd/stringer" + +import ( + "bytes" + "flag" + "fmt" + "go/ast" + "go/constant" + "go/format" + "go/token" + "go/types" + "log" + "os" + "path/filepath" + "sort" + "strings" + + "golang.org/x/tools/go/packages" +) + +var ( + typeNames = flag.String("type", "", "comma-separated list of type names; must be set") + output = flag.String("output", "", "output file name; default srcdir/_string.go") + trimprefix = flag.String("trimprefix", "", "trim the `prefix` from the generated constant names") + linecomment = flag.Bool("linecomment", false, "use line comment text as printed text when present") + buildTags = flag.String("tags", "", "comma-separated list of build tags to apply") +) + +// Usage is a replacement usage function for the flags package. +func Usage() { + fmt.Fprintf(os.Stderr, "Usage of stringer:\n") + fmt.Fprintf(os.Stderr, "\tstringer [flags] -type T [directory]\n") + fmt.Fprintf(os.Stderr, "\tstringer [flags] -type T files... # Must be a single package\n") + fmt.Fprintf(os.Stderr, "For more information, see:\n") + fmt.Fprintf(os.Stderr, "\thttps://pkg.go.dev/golang.org/x/tools/cmd/stringer\n") + fmt.Fprintf(os.Stderr, "Flags:\n") + flag.PrintDefaults() +} + +func main() { + log.SetFlags(0) + log.SetPrefix("stringer: ") + flag.Usage = Usage + flag.Parse() + if len(*typeNames) == 0 { + flag.Usage() + os.Exit(2) + } + types := strings.Split(*typeNames, ",") + var tags []string + if len(*buildTags) > 0 { + tags = strings.Split(*buildTags, ",") + } + + // We accept either one directory or a list of files. Which do we have? + args := flag.Args() + if len(args) == 0 { + // Default: process whole package in current directory. + args = []string{"."} + } + + // Parse the package once. + var dir string + g := Generator{ + trimPrefix: *trimprefix, + lineComment: *linecomment, + } + // TODO(suzmue): accept other patterns for packages (directories, list of files, import paths, etc). + if len(args) == 1 && isDirectory(args[0]) { + dir = args[0] + } else { + if len(tags) != 0 { + log.Fatal("-tags option applies only to directories, not when files are specified") + } + dir = filepath.Dir(args[0]) + } + + g.parsePackage(args, tags) + + // Print the header and package clause. + g.Printf("// Code generated by \"stringer %s\"; DO NOT EDIT.\n", strings.Join(os.Args[1:], " ")) + g.Printf("\n") + g.Printf("package %s", g.pkg.name) + g.Printf("\n") + g.Printf("import \"strconv\"\n") // Used by all methods. + + // Run generate for each type. + for _, typeName := range types { + g.generate(typeName) + } + + // Format the output. + src := g.format() + + // Write to file. + outputName := *output + if outputName == "" { + baseName := fmt.Sprintf("%s_string.go", types[0]) + outputName = filepath.Join(dir, strings.ToLower(baseName)) + } + err := os.WriteFile(outputName, src, 0644) + if err != nil { + log.Fatalf("writing output: %s", err) + } +} + +// isDirectory reports whether the named file is a directory. +func isDirectory(name string) bool { + info, err := os.Stat(name) + if err != nil { + log.Fatal(err) + } + return info.IsDir() +} + +// Generator holds the state of the analysis. Primarily used to buffer +// the output for format.Source. +type Generator struct { + buf bytes.Buffer // Accumulated output. + pkg *Package // Package we are scanning. + + trimPrefix string + lineComment bool +} + +func (g *Generator) Printf(format string, args ...interface{}) { + fmt.Fprintf(&g.buf, format, args...) +} + +// File holds a single parsed file and associated data. +type File struct { + pkg *Package // Package to which this file belongs. + file *ast.File // Parsed AST. + // These fields are reset for each type being generated. + typeName string // Name of the constant type. + values []Value // Accumulator for constant values of that type. + + trimPrefix string + lineComment bool +} + +type Package struct { + name string + defs map[*ast.Ident]types.Object + files []*File +} + +// parsePackage analyzes the single package constructed from the patterns and tags. +// parsePackage exits if there is an error. +func (g *Generator) parsePackage(patterns []string, tags []string) { + cfg := &packages.Config{ + Mode: packages.NeedName | packages.NeedTypes | packages.NeedTypesInfo | packages.NeedSyntax, + // TODO: Need to think about constants in test files. Maybe write type_string_test.go + // in a separate pass? For later. + Tests: false, + BuildFlags: []string{fmt.Sprintf("-tags=%s", strings.Join(tags, " "))}, + } + pkgs, err := packages.Load(cfg, patterns...) + if err != nil { + log.Fatal(err) + } + if len(pkgs) != 1 { + log.Fatalf("error: %d packages found", len(pkgs)) + } + g.addPackage(pkgs[0]) +} + +// addPackage adds a type checked Package and its syntax files to the generator. +func (g *Generator) addPackage(pkg *packages.Package) { + g.pkg = &Package{ + name: pkg.Name, + defs: pkg.TypesInfo.Defs, + files: make([]*File, len(pkg.Syntax)), + } + + for i, file := range pkg.Syntax { + g.pkg.files[i] = &File{ + file: file, + pkg: g.pkg, + trimPrefix: g.trimPrefix, + lineComment: g.lineComment, + } + } +} + +// generate produces the String method for the named type. +func (g *Generator) generate(typeName string) { + values := make([]Value, 0, 100) + for _, file := range g.pkg.files { + // Set the state for this run of the walker. + file.typeName = typeName + file.values = nil + if file.file != nil { + ast.Inspect(file.file, file.genDecl) + values = append(values, file.values...) + } + } + + if len(values) == 0 { + log.Fatalf("no values defined for type %s", typeName) + } + // Generate code that will fail if the constants change value. + g.Printf("func _() {\n") + g.Printf("\t// An \"invalid array index\" compiler error signifies that the constant values have changed.\n") + g.Printf("\t// Re-run the stringer command to generate them again.\n") + g.Printf("\tvar x [1]struct{}\n") + for _, v := range values { + g.Printf("\t_ = x[%s - %s]\n", v.originalName, v.str) + } + g.Printf("}\n") + runs := splitIntoRuns(values) + // The decision of which pattern to use depends on the number of + // runs in the numbers. If there's only one, it's easy. For more than + // one, there's a tradeoff between complexity and size of the data + // and code vs. the simplicity of a map. A map takes more space, + // but so does the code. The decision here (crossover at 10) is + // arbitrary, but considers that for large numbers of runs the cost + // of the linear scan in the switch might become important, and + // rather than use yet another algorithm such as binary search, + // we punt and use a map. In any case, the likelihood of a map + // being necessary for any realistic example other than bitmasks + // is very low. And bitmasks probably deserve their own analysis, + // to be done some other day. + switch { + case len(runs) == 1: + g.buildOneRun(runs, typeName) + case len(runs) <= 10: + g.buildMultipleRuns(runs, typeName) + default: + g.buildMap(runs, typeName) + } +} + +// splitIntoRuns breaks the values into runs of contiguous sequences. +// For example, given 1,2,3,5,6,7 it returns {1,2,3},{5,6,7}. +// The input slice is known to be non-empty. +func splitIntoRuns(values []Value) [][]Value { + // We use stable sort so the lexically first name is chosen for equal elements. + sort.Stable(byValue(values)) + // Remove duplicates. Stable sort has put the one we want to print first, + // so use that one. The String method won't care about which named constant + // was the argument, so the first name for the given value is the only one to keep. + // We need to do this because identical values would cause the switch or map + // to fail to compile. + j := 1 + for i := 1; i < len(values); i++ { + if values[i].value != values[i-1].value { + values[j] = values[i] + j++ + } + } + values = values[:j] + runs := make([][]Value, 0, 10) + for len(values) > 0 { + // One contiguous sequence per outer loop. + i := 1 + for i < len(values) && values[i].value == values[i-1].value+1 { + i++ + } + runs = append(runs, values[:i]) + values = values[i:] + } + return runs +} + +// format returns the gofmt-ed contents of the Generator's buffer. +func (g *Generator) format() []byte { + src, err := format.Source(g.buf.Bytes()) + if err != nil { + // Should never happen, but can arise when developing this code. + // The user can compile the output to see the error. + log.Printf("warning: internal error: invalid Go generated: %s", err) + log.Printf("warning: compile the package to analyze the error") + return g.buf.Bytes() + } + return src +} + +// Value represents a declared constant. +type Value struct { + originalName string // The name of the constant. + name string // The name with trimmed prefix. + // The value is stored as a bit pattern alone. The boolean tells us + // whether to interpret it as an int64 or a uint64; the only place + // this matters is when sorting. + // Much of the time the str field is all we need; it is printed + // by Value.String. + value uint64 // Will be converted to int64 when needed. + signed bool // Whether the constant is a signed type. + str string // The string representation given by the "go/constant" package. +} + +func (v *Value) String() string { + return v.str +} + +// byValue lets us sort the constants into increasing order. +// We take care in the Less method to sort in signed or unsigned order, +// as appropriate. +type byValue []Value + +func (b byValue) Len() int { return len(b) } +func (b byValue) Swap(i, j int) { b[i], b[j] = b[j], b[i] } +func (b byValue) Less(i, j int) bool { + if b[i].signed { + return int64(b[i].value) < int64(b[j].value) + } + return b[i].value < b[j].value +} + +// genDecl processes one declaration clause. +func (f *File) genDecl(node ast.Node) bool { + decl, ok := node.(*ast.GenDecl) + if !ok || decl.Tok != token.CONST { + // We only care about const declarations. + return true + } + // The name of the type of the constants we are declaring. + // Can change if this is a multi-element declaration. + typ := "" + // Loop over the elements of the declaration. Each element is a ValueSpec: + // a list of names possibly followed by a type, possibly followed by values. + // If the type and value are both missing, we carry down the type (and value, + // but the "go/types" package takes care of that). + for _, spec := range decl.Specs { + vspec := spec.(*ast.ValueSpec) // Guaranteed to succeed as this is CONST. + if vspec.Type == nil && len(vspec.Values) > 0 { + // "X = 1". With no type but a value. If the constant is untyped, + // skip this vspec and reset the remembered type. + typ = "" + + // If this is a simple type conversion, remember the type. + // We don't mind if this is actually a call; a qualified call won't + // be matched (that will be SelectorExpr, not Ident), and only unusual + // situations will result in a function call that appears to be + // a type conversion. + ce, ok := vspec.Values[0].(*ast.CallExpr) + if !ok { + continue + } + id, ok := ce.Fun.(*ast.Ident) + if !ok { + continue + } + typ = id.Name + } + if vspec.Type != nil { + // "X T". We have a type. Remember it. + ident, ok := vspec.Type.(*ast.Ident) + if !ok { + continue + } + typ = ident.Name + } + if typ != f.typeName { + // This is not the type we're looking for. + continue + } + // We now have a list of names (from one line of source code) all being + // declared with the desired type. + // Grab their names and actual values and store them in f.values. + for _, name := range vspec.Names { + if name.Name == "_" { + continue + } + // This dance lets the type checker find the values for us. It's a + // bit tricky: look up the object declared by the name, find its + // types.Const, and extract its value. + obj, ok := f.pkg.defs[name] + if !ok { + log.Fatalf("no value for constant %s", name) + } + info := obj.Type().Underlying().(*types.Basic).Info() + if info&types.IsInteger == 0 { + log.Fatalf("can't handle non-integer constant type %s", typ) + } + value := obj.(*types.Const).Val() // Guaranteed to succeed as this is CONST. + if value.Kind() != constant.Int { + log.Fatalf("can't happen: constant is not an integer %s", name) + } + i64, isInt := constant.Int64Val(value) + u64, isUint := constant.Uint64Val(value) + if !isInt && !isUint { + log.Fatalf("internal error: value of %s is not an integer: %s", name, value.String()) + } + if !isInt { + u64 = uint64(i64) + } + v := Value{ + originalName: name.Name, + value: u64, + signed: info&types.IsUnsigned == 0, + str: value.String(), + } + if c := vspec.Comment; f.lineComment && c != nil && len(c.List) == 1 { + v.name = strings.TrimSpace(c.Text()) + } else { + v.name = strings.TrimPrefix(v.originalName, f.trimPrefix) + } + f.values = append(f.values, v) + } + } + return false +} + +// Helpers + +// usize returns the number of bits of the smallest unsigned integer +// type that will hold n. Used to create the smallest possible slice of +// integers to use as indexes into the concatenated strings. +func usize(n int) int { + switch { + case n < 1<<8: + return 8 + case n < 1<<16: + return 16 + default: + // 2^32 is enough constants for anyone. + return 32 + } +} + +// declareIndexAndNameVars declares the index slices and concatenated names +// strings representing the runs of values. +func (g *Generator) declareIndexAndNameVars(runs [][]Value, typeName string) { + var indexes, names []string + for i, run := range runs { + index, name := g.createIndexAndNameDecl(run, typeName, fmt.Sprintf("_%d", i)) + if len(run) != 1 { + indexes = append(indexes, index) + } + names = append(names, name) + } + g.Printf("const (\n") + for _, name := range names { + g.Printf("\t%s\n", name) + } + g.Printf(")\n\n") + + if len(indexes) > 0 { + g.Printf("var (") + for _, index := range indexes { + g.Printf("\t%s\n", index) + } + g.Printf(")\n\n") + } +} + +// declareIndexAndNameVar is the single-run version of declareIndexAndNameVars +func (g *Generator) declareIndexAndNameVar(run []Value, typeName string) { + index, name := g.createIndexAndNameDecl(run, typeName, "") + g.Printf("const %s\n", name) + g.Printf("var %s\n", index) +} + +// createIndexAndNameDecl returns the pair of declarations for the run. The caller will add "const" and "var". +func (g *Generator) createIndexAndNameDecl(run []Value, typeName string, suffix string) (string, string) { + b := new(bytes.Buffer) + indexes := make([]int, len(run)) + for i := range run { + b.WriteString(run[i].name) + indexes[i] = b.Len() + } + nameConst := fmt.Sprintf("_%s_name%s = %q", typeName, suffix, b.String()) + nameLen := b.Len() + b.Reset() + fmt.Fprintf(b, "_%s_index%s = [...]uint%d{0, ", typeName, suffix, usize(nameLen)) + for i, v := range indexes { + if i > 0 { + fmt.Fprintf(b, ", ") + } + fmt.Fprintf(b, "%d", v) + } + fmt.Fprintf(b, "}") + return b.String(), nameConst +} + +// declareNameVars declares the concatenated names string representing all the values in the runs. +func (g *Generator) declareNameVars(runs [][]Value, typeName string, suffix string) { + g.Printf("const _%s_name%s = \"", typeName, suffix) + for _, run := range runs { + for i := range run { + g.Printf("%s", run[i].name) + } + } + g.Printf("\"\n") +} + +// buildOneRun generates the variables and String method for a single run of contiguous values. +func (g *Generator) buildOneRun(runs [][]Value, typeName string) { + values := runs[0] + g.Printf("\n") + g.declareIndexAndNameVar(values, typeName) + // The generated code is simple enough to write as a Printf format. + lessThanZero := "" + if values[0].signed { + lessThanZero = "i < 0 || " + } + if values[0].value == 0 { // Signed or unsigned, 0 is still 0. + g.Printf(stringOneRun, typeName, usize(len(values)), lessThanZero) + } else { + g.Printf(stringOneRunWithOffset, typeName, values[0].String(), usize(len(values)), lessThanZero) + } +} + +// Arguments to format are: +// +// [1]: type name +// [2]: size of index element (8 for uint8 etc.) +// [3]: less than zero check (for signed types) +const stringOneRun = `func (i %[1]s) String() string { + if %[3]si >= %[1]s(len(_%[1]s_index)-1) { + return "%[1]s(" + strconv.FormatInt(int64(i), 10) + ")" + } + return _%[1]s_name[_%[1]s_index[i]:_%[1]s_index[i+1]] +} +` + +// Arguments to format are: +// [1]: type name +// [2]: lowest defined value for type, as a string +// [3]: size of index element (8 for uint8 etc.) +// [4]: less than zero check (for signed types) +/* + */ +const stringOneRunWithOffset = `func (i %[1]s) String() string { + i -= %[2]s + if %[4]si >= %[1]s(len(_%[1]s_index)-1) { + return "%[1]s(" + strconv.FormatInt(int64(i + %[2]s), 10) + ")" + } + return _%[1]s_name[_%[1]s_index[i] : _%[1]s_index[i+1]] +} +` + +// buildMultipleRuns generates the variables and String method for multiple runs of contiguous values. +// For this pattern, a single Printf format won't do. +func (g *Generator) buildMultipleRuns(runs [][]Value, typeName string) { + g.Printf("\n") + g.declareIndexAndNameVars(runs, typeName) + g.Printf("func (i %s) String() string {\n", typeName) + g.Printf("\tswitch {\n") + for i, values := range runs { + if len(values) == 1 { + g.Printf("\tcase i == %s:\n", &values[0]) + g.Printf("\t\treturn _%s_name_%d\n", typeName, i) + continue + } + if values[0].value == 0 && !values[0].signed { + // For an unsigned lower bound of 0, "0 <= i" would be redundant. + g.Printf("\tcase i <= %s:\n", &values[len(values)-1]) + } else { + g.Printf("\tcase %s <= i && i <= %s:\n", &values[0], &values[len(values)-1]) + } + if values[0].value != 0 { + g.Printf("\t\ti -= %s\n", &values[0]) + } + g.Printf("\t\treturn _%s_name_%d[_%s_index_%d[i]:_%s_index_%d[i+1]]\n", + typeName, i, typeName, i, typeName, i) + } + g.Printf("\tdefault:\n") + g.Printf("\t\treturn \"%s(\" + strconv.FormatInt(int64(i), 10) + \")\"\n", typeName) + g.Printf("\t}\n") + g.Printf("}\n") +} + +// buildMap handles the case where the space is so sparse a map is a reasonable fallback. +// It's a rare situation but has simple code. +func (g *Generator) buildMap(runs [][]Value, typeName string) { + g.Printf("\n") + g.declareNameVars(runs, typeName, "") + g.Printf("\nvar _%s_map = map[%s]string{\n", typeName, typeName) + n := 0 + for _, values := range runs { + for _, value := range values { + g.Printf("\t%s: _%s_name[%d:%d],\n", &value, typeName, n, n+len(value.name)) + n += len(value.name) + } + } + g.Printf("}\n\n") + g.Printf(stringMap, typeName) +} + +// Argument to format is the type name. +const stringMap = `func (i %[1]s) String() string { + if str, ok := _%[1]s_map[i]; ok { + return str + } + return "%[1]s(" + strconv.FormatInt(int64(i), 10) + ")" +} +` diff --git a/vendor/google.golang.org/grpc/attributes/attributes.go b/vendor/google.golang.org/grpc/attributes/attributes.go index ae13ddac14..02f5dc5318 100644 --- a/vendor/google.golang.org/grpc/attributes/attributes.go +++ b/vendor/google.golang.org/grpc/attributes/attributes.go @@ -19,7 +19,7 @@ // Package attributes defines a generic key/value store used in various gRPC // components. // -// Experimental +// # Experimental // // Notice: This package is EXPERIMENTAL and may be changed or removed in a // later release. diff --git a/vendor/google.golang.org/grpc/backoff.go b/vendor/google.golang.org/grpc/backoff.go index 542594f5cc..29475e31c9 100644 --- a/vendor/google.golang.org/grpc/backoff.go +++ b/vendor/google.golang.org/grpc/backoff.go @@ -48,7 +48,7 @@ type BackoffConfig struct { // here for more details: // https://github.com/grpc/grpc/blob/master/doc/connection-backoff.md. // -// Experimental +// # Experimental // // Notice: This type is EXPERIMENTAL and may be changed or removed in a // later release. diff --git a/vendor/google.golang.org/grpc/balancer/balancer.go b/vendor/google.golang.org/grpc/balancer/balancer.go index 2571390807..392b21fb2d 100644 --- a/vendor/google.golang.org/grpc/balancer/balancer.go +++ b/vendor/google.golang.org/grpc/balancer/balancer.go @@ -110,6 +110,11 @@ type SubConn interface { UpdateAddresses([]resolver.Address) // Connect starts the connecting for this SubConn. Connect() + // GetOrBuildProducer returns a reference to the existing Producer for this + // ProducerBuilder in this SubConn, or, if one does not currently exist, + // creates a new one and returns it. Returns a close function which must + // be called when the Producer is no longer needed. + GetOrBuildProducer(ProducerBuilder) (p Producer, close func()) } // NewSubConnOptions contains options to create new SubConn. @@ -244,7 +249,7 @@ type DoneInfo struct { // ServerLoad is the load received from server. It's usually sent as part of // trailing metadata. // - // The only supported type now is *orca_v1.LoadReport. + // The only supported type now is *orca_v3.LoadReport. ServerLoad interface{} } @@ -371,3 +376,21 @@ type ClientConnState struct { // ErrBadResolverState may be returned by UpdateClientConnState to indicate a // problem with the provided name resolver data. var ErrBadResolverState = errors.New("bad resolver state") + +// A ProducerBuilder is a simple constructor for a Producer. It is used by the +// SubConn to create producers when needed. +type ProducerBuilder interface { + // Build creates a Producer. The first parameter is always a + // grpc.ClientConnInterface (a type to allow creating RPCs/streams on the + // associated SubConn), but is declared as interface{} to avoid a + // dependency cycle. Should also return a close function that will be + // called when all references to the Producer have been given up. + Build(grpcClientConnInterface interface{}) (p Producer, close func()) +} + +// A Producer is a type shared among potentially many consumers. It is +// associated with a SubConn, and an implementation will typically contain +// other methods to provide additional functionality, e.g. configuration or +// subscription registration. +type Producer interface { +} diff --git a/vendor/google.golang.org/grpc/balancer/base/balancer.go b/vendor/google.golang.org/grpc/balancer/base/balancer.go index e8dfc828aa..3929c26d31 100644 --- a/vendor/google.golang.org/grpc/balancer/base/balancer.go +++ b/vendor/google.golang.org/grpc/balancer/base/balancer.go @@ -157,8 +157,8 @@ func (b *baseBalancer) mergeErrors() error { // regeneratePicker takes a snapshot of the balancer, and generates a picker // from it. The picker is -// - errPicker if the balancer is in TransientFailure, -// - built by the pickerBuilder with all READY SubConns otherwise. +// - errPicker if the balancer is in TransientFailure, +// - built by the pickerBuilder with all READY SubConns otherwise. func (b *baseBalancer) regeneratePicker() { if b.state == connectivity.TransientFailure { b.picker = NewErrPicker(b.mergeErrors()) diff --git a/vendor/google.golang.org/grpc/balancer/conn_state_evaluator.go b/vendor/google.golang.org/grpc/balancer/conn_state_evaluator.go index a87b6809af..c334135810 100644 --- a/vendor/google.golang.org/grpc/balancer/conn_state_evaluator.go +++ b/vendor/google.golang.org/grpc/balancer/conn_state_evaluator.go @@ -34,10 +34,10 @@ type ConnectivityStateEvaluator struct { // RecordTransition records state change happening in subConn and based on that // it evaluates what aggregated state should be. // -// - If at least one SubConn in Ready, the aggregated state is Ready; -// - Else if at least one SubConn in Connecting, the aggregated state is Connecting; -// - Else if at least one SubConn is Idle, the aggregated state is Idle; -// - Else if at least one SubConn is TransientFailure (or there are no SubConns), the aggregated state is Transient Failure. +// - If at least one SubConn in Ready, the aggregated state is Ready; +// - Else if at least one SubConn in Connecting, the aggregated state is Connecting; +// - Else if at least one SubConn is Idle, the aggregated state is Idle; +// - Else if at least one SubConn is TransientFailure (or there are no SubConns), the aggregated state is Transient Failure. // // Shutdown is not considered. func (cse *ConnectivityStateEvaluator) RecordTransition(oldState, newState connectivity.State) connectivity.State { @@ -55,7 +55,11 @@ func (cse *ConnectivityStateEvaluator) RecordTransition(oldState, newState conne cse.numIdle += updateVal } } + return cse.CurrentState() +} +// CurrentState returns the current aggregate conn state by evaluating the counters +func (cse *ConnectivityStateEvaluator) CurrentState() connectivity.State { // Evaluate. if cse.numReady > 0 { return connectivity.Ready diff --git a/vendor/google.golang.org/grpc/balancer/roundrobin/roundrobin.go b/vendor/google.golang.org/grpc/balancer/roundrobin/roundrobin.go index 274eb2f858..f7031ad225 100644 --- a/vendor/google.golang.org/grpc/balancer/roundrobin/roundrobin.go +++ b/vendor/google.golang.org/grpc/balancer/roundrobin/roundrobin.go @@ -22,7 +22,7 @@ package roundrobin import ( - "sync" + "sync/atomic" "google.golang.org/grpc/balancer" "google.golang.org/grpc/balancer/base" @@ -60,7 +60,7 @@ func (*rrPickerBuilder) Build(info base.PickerBuildInfo) balancer.Picker { // Start at a random index, as the same RR balancer rebuilds a new // picker when SubConn states change, and we don't want to apply excess // load to the first server in the list. - next: grpcrand.Intn(len(scs)), + next: uint32(grpcrand.Intn(len(scs))), } } @@ -69,15 +69,13 @@ type rrPicker struct { // created. The slice is immutable. Each Get() will do a round robin // selection from it and return the selected SubConn. subConns []balancer.SubConn - - mu sync.Mutex - next int + next uint32 } func (p *rrPicker) Pick(balancer.PickInfo) (balancer.PickResult, error) { - p.mu.Lock() - sc := p.subConns[p.next] - p.next = (p.next + 1) % len(p.subConns) - p.mu.Unlock() + subConnsLen := uint32(len(p.subConns)) + nextIndex := atomic.AddUint32(&p.next, 1) + + sc := p.subConns[nextIndex%subConnsLen] return balancer.PickResult{SubConn: sc}, nil } diff --git a/vendor/google.golang.org/grpc/balancer_conn_wrappers.go b/vendor/google.golang.org/grpc/balancer_conn_wrappers.go index b1c23eaae0..0359956d36 100644 --- a/vendor/google.golang.org/grpc/balancer_conn_wrappers.go +++ b/vendor/google.golang.org/grpc/balancer_conn_wrappers.go @@ -19,17 +19,20 @@ package grpc import ( + "context" "fmt" "strings" "sync" "google.golang.org/grpc/balancer" + "google.golang.org/grpc/codes" "google.golang.org/grpc/connectivity" "google.golang.org/grpc/internal/balancer/gracefulswitch" "google.golang.org/grpc/internal/buffer" "google.golang.org/grpc/internal/channelz" "google.golang.org/grpc/internal/grpcsync" "google.golang.org/grpc/resolver" + "google.golang.org/grpc/status" ) // ccBalancerWrapper sits between the ClientConn and the Balancer. @@ -305,7 +308,7 @@ func (ccb *ccBalancerWrapper) NewSubConn(addrs []resolver.Address, opts balancer channelz.Warningf(logger, ccb.cc.channelzID, "acBalancerWrapper: NewSubConn: failed to newAddrConn: %v", err) return nil, err } - acbw := &acBalancerWrapper{ac: ac} + acbw := &acBalancerWrapper{ac: ac, producers: make(map[balancer.ProducerBuilder]*refCountedProducer)} acbw.ac.mu.Lock() ac.acbw = acbw acbw.ac.mu.Unlock() @@ -359,8 +362,9 @@ func (ccb *ccBalancerWrapper) Target() string { // acBalancerWrapper is a wrapper on top of ac for balancers. // It implements balancer.SubConn interface. type acBalancerWrapper struct { - mu sync.Mutex - ac *addrConn + mu sync.Mutex + ac *addrConn + producers map[balancer.ProducerBuilder]*refCountedProducer } func (acbw *acBalancerWrapper) UpdateAddresses(addrs []resolver.Address) { @@ -414,3 +418,64 @@ func (acbw *acBalancerWrapper) getAddrConn() *addrConn { defer acbw.mu.Unlock() return acbw.ac } + +var errSubConnNotReady = status.Error(codes.Unavailable, "SubConn not currently connected") + +// NewStream begins a streaming RPC on the addrConn. If the addrConn is not +// ready, returns errSubConnNotReady. +func (acbw *acBalancerWrapper) NewStream(ctx context.Context, desc *StreamDesc, method string, opts ...CallOption) (ClientStream, error) { + transport := acbw.ac.getReadyTransport() + if transport == nil { + return nil, errSubConnNotReady + } + return newNonRetryClientStream(ctx, desc, method, transport, acbw.ac, opts...) +} + +// Invoke performs a unary RPC. If the addrConn is not ready, returns +// errSubConnNotReady. +func (acbw *acBalancerWrapper) Invoke(ctx context.Context, method string, args interface{}, reply interface{}, opts ...CallOption) error { + cs, err := acbw.NewStream(ctx, unaryStreamDesc, method, opts...) + if err != nil { + return err + } + if err := cs.SendMsg(args); err != nil { + return err + } + return cs.RecvMsg(reply) +} + +type refCountedProducer struct { + producer balancer.Producer + refs int // number of current refs to the producer + close func() // underlying producer's close function +} + +func (acbw *acBalancerWrapper) GetOrBuildProducer(pb balancer.ProducerBuilder) (balancer.Producer, func()) { + acbw.mu.Lock() + defer acbw.mu.Unlock() + + // Look up existing producer from this builder. + pData := acbw.producers[pb] + if pData == nil { + // Not found; create a new one and add it to the producers map. + p, close := pb.Build(acbw) + pData = &refCountedProducer{producer: p, close: close} + acbw.producers[pb] = pData + } + // Account for this new reference. + pData.refs++ + + // Return a cleanup function wrapped in a OnceFunc to remove this reference + // and delete the refCountedProducer from the map if the total reference + // count goes to zero. + unref := func() { + acbw.mu.Lock() + pData.refs-- + if pData.refs == 0 { + defer pData.close() // Run outside the acbw mutex + delete(acbw.producers, pb) + } + acbw.mu.Unlock() + } + return pData.producer, grpcsync.OnceFunc(unref) +} diff --git a/vendor/google.golang.org/grpc/binarylog/grpc_binarylog_v1/binarylog.pb.go b/vendor/google.golang.org/grpc/binarylog/grpc_binarylog_v1/binarylog.pb.go index ed75290cdf..64a232f281 100644 --- a/vendor/google.golang.org/grpc/binarylog/grpc_binarylog_v1/binarylog.pb.go +++ b/vendor/google.golang.org/grpc/binarylog/grpc_binarylog_v1/binarylog.pb.go @@ -261,6 +261,7 @@ type GrpcLogEntry struct { // according to the type of the log entry. // // Types that are assignable to Payload: + // // *GrpcLogEntry_ClientHeader // *GrpcLogEntry_ServerHeader // *GrpcLogEntry_Message @@ -694,12 +695,12 @@ func (x *Message) GetData() []byte { // Header keys added by gRPC are omitted. To be more specific, // implementations will not log the following entries, and this is // not to be treated as a truncation: -// - entries handled by grpc that are not user visible, such as those -// that begin with 'grpc-' (with exception of grpc-trace-bin) -// or keys like 'lb-token' -// - transport specific entries, including but not limited to: -// ':path', ':authority', 'content-encoding', 'user-agent', 'te', etc -// - entries added for call credentials +// - entries handled by grpc that are not user visible, such as those +// that begin with 'grpc-' (with exception of grpc-trace-bin) +// or keys like 'lb-token' +// - transport specific entries, including but not limited to: +// ':path', ':authority', 'content-encoding', 'user-agent', 'te', etc +// - entries added for call credentials // // Implementations must always log grpc-trace-bin if it is present. // Practically speaking it will only be visible on server side because diff --git a/vendor/google.golang.org/grpc/channelz/channelz.go b/vendor/google.golang.org/grpc/channelz/channelz.go index a220c47c59..32b7fa5794 100644 --- a/vendor/google.golang.org/grpc/channelz/channelz.go +++ b/vendor/google.golang.org/grpc/channelz/channelz.go @@ -23,7 +23,7 @@ // https://github.com/grpc/proposal/blob/master/A14-channelz.md, is provided by // the `internal/channelz` package. // -// Experimental +// # Experimental // // Notice: All APIs in this package are experimental and may be removed in a // later release. diff --git a/vendor/google.golang.org/grpc/clientconn.go b/vendor/google.golang.org/grpc/clientconn.go index 779b03bca1..422639c79d 100644 --- a/vendor/google.golang.org/grpc/clientconn.go +++ b/vendor/google.golang.org/grpc/clientconn.go @@ -503,7 +503,7 @@ type ClientConn struct { // WaitForStateChange waits until the connectivity.State of ClientConn changes from sourceState or // ctx expires. A true value is returned in former case and false in latter. // -// Experimental +// # Experimental // // Notice: This API is EXPERIMENTAL and may be changed or removed in a // later release. @@ -522,7 +522,7 @@ func (cc *ClientConn) WaitForStateChange(ctx context.Context, sourceState connec // GetState returns the connectivity.State of ClientConn. // -// Experimental +// # Experimental // // Notice: This API is EXPERIMENTAL and may be changed or removed in a later // release. @@ -534,7 +534,7 @@ func (cc *ClientConn) GetState() connectivity.State { // the channel is idle. Does not wait for the connection attempts to begin // before returning. // -// Experimental +// # Experimental // // Notice: This API is EXPERIMENTAL and may be changed or removed in a later // release. @@ -761,7 +761,7 @@ func (cc *ClientConn) channelzMetric() *channelz.ChannelInternalMetric { // Target returns the target string of the ClientConn. // -// Experimental +// # Experimental // // Notice: This API is EXPERIMENTAL and may be changed or removed in a // later release. @@ -831,9 +831,9 @@ func equalAddresses(a, b []resolver.Address) bool { // // If ac is Ready, it checks whether current connected address of ac is in the // new addrs list. -// - If true, it updates ac.addrs and returns true. The ac will keep using -// the existing connection. -// - If false, it does nothing and returns false. +// - If true, it updates ac.addrs and returns true. The ac will keep using +// the existing connection. +// - If false, it does nothing and returns false. func (ac *addrConn) tryUpdateAddrs(addrs []resolver.Address) bool { ac.mu.Lock() defer ac.mu.Unlock() @@ -998,7 +998,7 @@ func (cc *ClientConn) resolveNow(o resolver.ResolveNowOptions) { // However, if a previously unavailable network becomes available, this may be // used to trigger an immediate reconnect. // -// Experimental +// # Experimental // // Notice: This API is EXPERIMENTAL and may be changed or removed in a // later release. @@ -1228,38 +1228,33 @@ func (ac *addrConn) tryAllAddrs(addrs []resolver.Address, connectDeadline time.T // address was not successfully connected, or updates ac appropriately with the // new transport. func (ac *addrConn) createTransport(addr resolver.Address, copts transport.ConnectOptions, connectDeadline time.Time) error { - // TODO: Delete prefaceReceived and move the logic to wait for it into the - // transport. - prefaceReceived := grpcsync.NewEvent() - connClosed := grpcsync.NewEvent() - addr.ServerName = ac.cc.getServerName(addr) hctx, hcancel := context.WithCancel(ac.ctx) - hcStarted := false // protected by ac.mu - onClose := func() { + onClose := grpcsync.OnceFunc(func() { ac.mu.Lock() defer ac.mu.Unlock() - defer connClosed.Fire() - defer hcancel() - if !hcStarted || hctx.Err() != nil { - // We didn't start the health check or set the state to READY, so - // no need to do anything else here. - // - // OR, we have already cancelled the health check context, meaning - // we have already called onClose once for this transport. In this - // case it would be dangerous to clear the transport and update the - // state, since there may be a new transport in this addrConn. + if ac.state == connectivity.Shutdown { + // Already shut down. tearDown() already cleared the transport and + // canceled hctx via ac.ctx, and we expected this connection to be + // closed, so do nothing here. + return + } + hcancel() + if ac.transport == nil { + // We're still connecting to this address, which could error. Do + // not update the connectivity state or resolve; these will happen + // at the end of the tryAllAddrs connection loop in the event of an + // error. return } ac.transport = nil - // Refresh the name resolver + // Refresh the name resolver on any connection loss. ac.cc.resolveNow(resolver.ResolveNowOptions{}) - if ac.state != connectivity.Shutdown { - ac.updateConnectivityState(connectivity.Idle, nil) - } - } - + // Always go idle and wait for the LB policy to initiate a new + // connection attempt. + ac.updateConnectivityState(connectivity.Idle, nil) + }) onGoAway := func(r transport.GoAwayReason) { ac.mu.Lock() ac.adjustParams(r) @@ -1271,7 +1266,7 @@ func (ac *addrConn) createTransport(addr resolver.Address, copts transport.Conne defer cancel() copts.ChannelzParentID = ac.channelzID - newTr, err := transport.NewClientTransport(connectCtx, ac.cc.ctx, addr, copts, func() { prefaceReceived.Fire() }, onGoAway, onClose) + newTr, err := transport.NewClientTransport(connectCtx, ac.cc.ctx, addr, copts, onGoAway, onClose) if err != nil { // newTr is either nil, or closed. hcancel() @@ -1279,60 +1274,34 @@ func (ac *addrConn) createTransport(addr resolver.Address, copts transport.Conne return err } - select { - case <-connectCtx.Done(): - // We didn't get the preface in time. + ac.mu.Lock() + defer ac.mu.Unlock() + if ac.state == connectivity.Shutdown { + // This can happen if the subConn was removed while in `Connecting` + // state. tearDown() would have set the state to `Shutdown`, but + // would not have closed the transport since ac.transport would not + // have been set at that point. + // + // We run this in a goroutine because newTr.Close() calls onClose() + // inline, which requires locking ac.mu. + // // The error we pass to Close() is immaterial since there are no open // streams at this point, so no trailers with error details will be sent // out. We just need to pass a non-nil error. - newTr.Close(transport.ErrConnClosing) - if connectCtx.Err() == context.DeadlineExceeded { - err := errors.New("failed to receive server preface within timeout") - channelz.Warningf(logger, ac.channelzID, "grpc: addrConn.createTransport failed to connect to %s: %v", addr, err) - return err - } + go newTr.Close(transport.ErrConnClosing) return nil - case <-prefaceReceived.Done(): - // We got the preface - huzzah! things are good. - ac.mu.Lock() - defer ac.mu.Unlock() - if connClosed.HasFired() { - // onClose called first; go idle but do nothing else. - if ac.state != connectivity.Shutdown { - ac.updateConnectivityState(connectivity.Idle, nil) - } - return nil - } - if ac.state == connectivity.Shutdown { - // This can happen if the subConn was removed while in `Connecting` - // state. tearDown() would have set the state to `Shutdown`, but - // would not have closed the transport since ac.transport would not - // been set at that point. - // - // We run this in a goroutine because newTr.Close() calls onClose() - // inline, which requires locking ac.mu. - // - // The error we pass to Close() is immaterial since there are no open - // streams at this point, so no trailers with error details will be sent - // out. We just need to pass a non-nil error. - go newTr.Close(transport.ErrConnClosing) - return nil - } - ac.curAddr = addr - ac.transport = newTr - hcStarted = true - ac.startHealthCheck(hctx) // Will set state to READY if appropriate. + } + if hctx.Err() != nil { + // onClose was already called for this connection, but the connection + // was successfully established first. Consider it a success and set + // the new state to Idle. + ac.updateConnectivityState(connectivity.Idle, nil) return nil - case <-connClosed.Done(): - // The transport has already closed. If we received the preface, too, - // this is not an error. - select { - case <-prefaceReceived.Done(): - return nil - default: - return errors.New("connection closed before server preface received") - } } + ac.curAddr = addr + ac.transport = newTr + ac.startHealthCheck(hctx) // Will set state to READY if appropriate. + return nil } // startHealthCheck starts the health checking stream (RPC) to watch the health @@ -1583,7 +1552,7 @@ func (cc *ClientConn) parseTargetAndFindResolver() (resolver.Builder, error) { channelz.Infof(logger, cc.channelzID, "dial target %q parse failed: %v", cc.target, err) } else { channelz.Infof(logger, cc.channelzID, "parsed dial target is: %+v", parsedTarget) - rb = cc.getResolver(parsedTarget.Scheme) + rb = cc.getResolver(parsedTarget.URL.Scheme) if rb != nil { cc.parsedTarget = parsedTarget return rb, nil @@ -1604,9 +1573,9 @@ func (cc *ClientConn) parseTargetAndFindResolver() (resolver.Builder, error) { return nil, err } channelz.Infof(logger, cc.channelzID, "parsed dial target is: %+v", parsedTarget) - rb = cc.getResolver(parsedTarget.Scheme) + rb = cc.getResolver(parsedTarget.URL.Scheme) if rb == nil { - return nil, fmt.Errorf("could not get resolver for default scheme: %q", parsedTarget.Scheme) + return nil, fmt.Errorf("could not get resolver for default scheme: %q", parsedTarget.URL.Scheme) } cc.parsedTarget = parsedTarget return rb, nil diff --git a/vendor/google.golang.org/grpc/credentials/credentials.go b/vendor/google.golang.org/grpc/credentials/credentials.go index 96ff1877e7..5feac3aa0e 100644 --- a/vendor/google.golang.org/grpc/credentials/credentials.go +++ b/vendor/google.golang.org/grpc/credentials/credentials.go @@ -36,16 +36,16 @@ import ( // PerRPCCredentials defines the common interface for the credentials which need to // attach security information to every RPC (e.g., oauth2). type PerRPCCredentials interface { - // GetRequestMetadata gets the current request metadata, refreshing - // tokens if required. This should be called by the transport layer on - // each request, and the data should be populated in headers or other - // context. If a status code is returned, it will be used as the status - // for the RPC. uri is the URI of the entry point for the request. - // When supported by the underlying implementation, ctx can be used for - // timeout and cancellation. Additionally, RequestInfo data will be - // available via ctx to this call. - // TODO(zhaoq): Define the set of the qualified keys instead of leaving - // it as an arbitrary string. + // GetRequestMetadata gets the current request metadata, refreshing tokens + // if required. This should be called by the transport layer on each + // request, and the data should be populated in headers or other + // context. If a status code is returned, it will be used as the status for + // the RPC (restricted to an allowable set of codes as defined by gRFC + // A54). uri is the URI of the entry point for the request. When supported + // by the underlying implementation, ctx can be used for timeout and + // cancellation. Additionally, RequestInfo data will be available via ctx + // to this call. TODO(zhaoq): Define the set of the qualified keys instead + // of leaving it as an arbitrary string. GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) // RequireTransportSecurity indicates whether the credentials requires // transport security. diff --git a/vendor/google.golang.org/grpc/credentials/tls.go b/vendor/google.golang.org/grpc/credentials/tls.go index 784822d056..ce2bbc10a1 100644 --- a/vendor/google.golang.org/grpc/credentials/tls.go +++ b/vendor/google.golang.org/grpc/credentials/tls.go @@ -195,7 +195,7 @@ func NewServerTLSFromFile(certFile, keyFile string) (TransportCredentials, error // TLSChannelzSecurityValue defines the struct that TLS protocol should return // from GetSecurityValue(), containing security info like cipher and certificate used. // -// Experimental +// # Experimental // // Notice: This type is EXPERIMENTAL and may be changed or removed in a // later release. diff --git a/vendor/google.golang.org/grpc/dialoptions.go b/vendor/google.golang.org/grpc/dialoptions.go index 60403bc160..9372dc322e 100644 --- a/vendor/google.golang.org/grpc/dialoptions.go +++ b/vendor/google.golang.org/grpc/dialoptions.go @@ -29,6 +29,7 @@ import ( "google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/internal" internalbackoff "google.golang.org/grpc/internal/backoff" + "google.golang.org/grpc/internal/binarylog" "google.golang.org/grpc/internal/transport" "google.golang.org/grpc/keepalive" "google.golang.org/grpc/resolver" @@ -36,12 +37,13 @@ import ( ) func init() { - internal.AddExtraDialOptions = func(opt ...DialOption) { + internal.AddGlobalDialOptions = func(opt ...DialOption) { extraDialOptions = append(extraDialOptions, opt...) } - internal.ClearExtraDialOptions = func() { + internal.ClearGlobalDialOptions = func() { extraDialOptions = nil } + internal.WithBinaryLogger = withBinaryLogger } // dialOptions configure a Dial call. dialOptions are set by the DialOption @@ -61,6 +63,7 @@ type dialOptions struct { timeout time.Duration scChan <-chan ServiceConfig authority string + binaryLogger binarylog.Logger copts transport.ConnectOptions callOptions []CallOption channelzParentID *channelz.Identifier @@ -401,6 +404,14 @@ func WithStatsHandler(h stats.Handler) DialOption { }) } +// withBinaryLogger returns a DialOption that specifies the binary logger for +// this ClientConn. +func withBinaryLogger(bl binarylog.Logger) DialOption { + return newFuncDialOption(func(o *dialOptions) { + o.binaryLogger = bl + }) +} + // FailOnNonTempDialError returns a DialOption that specifies if gRPC fails on // non-temporary dial errors. If f is true, and dialer returns a non-temporary // error, gRPC will fail the connection to the network address and won't try to diff --git a/vendor/google.golang.org/grpc/encoding/encoding.go b/vendor/google.golang.org/grpc/encoding/encoding.go index 18e530fc90..711763d54f 100644 --- a/vendor/google.golang.org/grpc/encoding/encoding.go +++ b/vendor/google.golang.org/grpc/encoding/encoding.go @@ -19,7 +19,7 @@ // Package encoding defines the interface for the compressor and codec, and // functions to register and retrieve compressors and codecs. // -// Experimental +// # Experimental // // Notice: This package is EXPERIMENTAL and may be changed or removed in a // later release. @@ -28,6 +28,8 @@ package encoding import ( "io" "strings" + + "google.golang.org/grpc/internal/grpcutil" ) // Identity specifies the optional encoding for uncompressed streams. @@ -73,6 +75,7 @@ var registeredCompressor = make(map[string]Compressor) // registered with the same name, the one registered last will take effect. func RegisterCompressor(c Compressor) { registeredCompressor[c.Name()] = c + grpcutil.RegisteredCompressorNames = append(grpcutil.RegisteredCompressorNames, c.Name()) } // GetCompressor returns Compressor for the given compressor name. diff --git a/vendor/google.golang.org/grpc/grpclog/loggerv2.go b/vendor/google.golang.org/grpc/grpclog/loggerv2.go index 7c1f664090..b5560b47ec 100644 --- a/vendor/google.golang.org/grpc/grpclog/loggerv2.go +++ b/vendor/google.golang.org/grpc/grpclog/loggerv2.go @@ -242,7 +242,7 @@ func (g *loggerT) V(l int) bool { // DepthLoggerV2, the below functions will be called with the appropriate stack // depth set for trivial functions the logger may ignore. // -// Experimental +// # Experimental // // Notice: This type is EXPERIMENTAL and may be changed or removed in a // later release. diff --git a/vendor/google.golang.org/grpc/internal/binarylog/binarylog.go b/vendor/google.golang.org/grpc/internal/binarylog/binarylog.go index e3dfe204f9..809d73ccaf 100644 --- a/vendor/google.golang.org/grpc/internal/binarylog/binarylog.go +++ b/vendor/google.golang.org/grpc/internal/binarylog/binarylog.go @@ -37,7 +37,7 @@ type Logger interface { // binLogger is the global binary logger for the binary. One of this should be // built at init time from the configuration (environment variable or flags). // -// It is used to get a methodLogger for each individual method. +// It is used to get a MethodLogger for each individual method. var binLogger Logger var grpclogLogger = grpclog.Component("binarylog") @@ -56,11 +56,11 @@ func GetLogger() Logger { return binLogger } -// GetMethodLogger returns the methodLogger for the given methodName. +// GetMethodLogger returns the MethodLogger for the given methodName. // // methodName should be in the format of "/service/method". // -// Each methodLogger returned by this method is a new instance. This is to +// Each MethodLogger returned by this method is a new instance. This is to // generate sequence id within the call. func GetMethodLogger(methodName string) MethodLogger { if binLogger == nil { @@ -117,7 +117,7 @@ func (l *logger) setDefaultMethodLogger(ml *MethodLoggerConfig) error { // Set method logger for "service/*". // -// New methodLogger with same service overrides the old one. +// New MethodLogger with same service overrides the old one. func (l *logger) setServiceMethodLogger(service string, ml *MethodLoggerConfig) error { if _, ok := l.config.Services[service]; ok { return fmt.Errorf("conflicting service rules for service %v found", service) @@ -131,7 +131,7 @@ func (l *logger) setServiceMethodLogger(service string, ml *MethodLoggerConfig) // Set method logger for "service/method". // -// New methodLogger with same method overrides the old one. +// New MethodLogger with same method overrides the old one. func (l *logger) setMethodMethodLogger(method string, ml *MethodLoggerConfig) error { if _, ok := l.config.Blacklist[method]; ok { return fmt.Errorf("conflicting blacklist rules for method %v found", method) @@ -161,11 +161,11 @@ func (l *logger) setBlacklist(method string) error { return nil } -// getMethodLogger returns the methodLogger for the given methodName. +// getMethodLogger returns the MethodLogger for the given methodName. // // methodName should be in the format of "/service/method". // -// Each methodLogger returned by this method is a new instance. This is to +// Each MethodLogger returned by this method is a new instance. This is to // generate sequence id within the call. func (l *logger) GetMethodLogger(methodName string) MethodLogger { s, m, err := grpcutil.ParseMethod(methodName) @@ -174,16 +174,16 @@ func (l *logger) GetMethodLogger(methodName string) MethodLogger { return nil } if ml, ok := l.config.Methods[s+"/"+m]; ok { - return newMethodLogger(ml.Header, ml.Message) + return NewTruncatingMethodLogger(ml.Header, ml.Message) } if _, ok := l.config.Blacklist[s+"/"+m]; ok { return nil } if ml, ok := l.config.Services[s]; ok { - return newMethodLogger(ml.Header, ml.Message) + return NewTruncatingMethodLogger(ml.Header, ml.Message) } if l.config.All == nil { return nil } - return newMethodLogger(l.config.All.Header, l.config.All.Message) + return NewTruncatingMethodLogger(l.config.All.Header, l.config.All.Message) } diff --git a/vendor/google.golang.org/grpc/internal/binarylog/env_config.go b/vendor/google.golang.org/grpc/internal/binarylog/env_config.go index ab589a76bf..f9e80e27ab 100644 --- a/vendor/google.golang.org/grpc/internal/binarylog/env_config.go +++ b/vendor/google.golang.org/grpc/internal/binarylog/env_config.go @@ -30,15 +30,15 @@ import ( // to build a new logger and assign it to binarylog.Logger. // // Example filter config strings: -// - "" Nothing will be logged -// - "*" All headers and messages will be fully logged. -// - "*{h}" Only headers will be logged. -// - "*{m:256}" Only the first 256 bytes of each message will be logged. -// - "Foo/*" Logs every method in service Foo -// - "Foo/*,-Foo/Bar" Logs every method in service Foo except method /Foo/Bar -// - "Foo/*,Foo/Bar{m:256}" Logs the first 256 bytes of each message in method -// /Foo/Bar, logs all headers and messages in every other method in service -// Foo. +// - "" Nothing will be logged +// - "*" All headers and messages will be fully logged. +// - "*{h}" Only headers will be logged. +// - "*{m:256}" Only the first 256 bytes of each message will be logged. +// - "Foo/*" Logs every method in service Foo +// - "Foo/*,-Foo/Bar" Logs every method in service Foo except method /Foo/Bar +// - "Foo/*,Foo/Bar{m:256}" Logs the first 256 bytes of each message in method +// /Foo/Bar, logs all headers and messages in every other method in service +// Foo. // // If two configs exist for one certain method or service, the one specified // later overrides the previous config. @@ -57,7 +57,7 @@ func NewLoggerFromConfigString(s string) Logger { return l } -// fillMethodLoggerWithConfigString parses config, creates methodLogger and adds +// fillMethodLoggerWithConfigString parses config, creates TruncatingMethodLogger and adds // it to the right map in the logger. func (l *logger) fillMethodLoggerWithConfigString(config string) error { // "" is invalid. diff --git a/vendor/google.golang.org/grpc/internal/binarylog/method_logger.go b/vendor/google.golang.org/grpc/internal/binarylog/method_logger.go index 24df0a1a0c..179f4a26d1 100644 --- a/vendor/google.golang.org/grpc/internal/binarylog/method_logger.go +++ b/vendor/google.golang.org/grpc/internal/binarylog/method_logger.go @@ -52,7 +52,9 @@ type MethodLogger interface { Log(LogEntryConfig) } -type methodLogger struct { +// TruncatingMethodLogger is a method logger that truncates headers and messages +// based on configured fields. +type TruncatingMethodLogger struct { headerMaxLen, messageMaxLen uint64 callID uint64 @@ -61,8 +63,9 @@ type methodLogger struct { sink Sink // TODO(blog): make this plugable. } -func newMethodLogger(h, m uint64) *methodLogger { - return &methodLogger{ +// NewTruncatingMethodLogger returns a new truncating method logger. +func NewTruncatingMethodLogger(h, m uint64) *TruncatingMethodLogger { + return &TruncatingMethodLogger{ headerMaxLen: h, messageMaxLen: m, @@ -75,8 +78,8 @@ func newMethodLogger(h, m uint64) *methodLogger { // Build is an internal only method for building the proto message out of the // input event. It's made public to enable other library to reuse as much logic -// in methodLogger as possible. -func (ml *methodLogger) Build(c LogEntryConfig) *pb.GrpcLogEntry { +// in TruncatingMethodLogger as possible. +func (ml *TruncatingMethodLogger) Build(c LogEntryConfig) *pb.GrpcLogEntry { m := c.toProto() timestamp, _ := ptypes.TimestampProto(time.Now()) m.Timestamp = timestamp @@ -95,11 +98,11 @@ func (ml *methodLogger) Build(c LogEntryConfig) *pb.GrpcLogEntry { } // Log creates a proto binary log entry, and logs it to the sink. -func (ml *methodLogger) Log(c LogEntryConfig) { +func (ml *TruncatingMethodLogger) Log(c LogEntryConfig) { ml.sink.Write(ml.Build(c)) } -func (ml *methodLogger) truncateMetadata(mdPb *pb.Metadata) (truncated bool) { +func (ml *TruncatingMethodLogger) truncateMetadata(mdPb *pb.Metadata) (truncated bool) { if ml.headerMaxLen == maxUInt { return false } @@ -129,7 +132,7 @@ func (ml *methodLogger) truncateMetadata(mdPb *pb.Metadata) (truncated bool) { return truncated } -func (ml *methodLogger) truncateMessage(msgPb *pb.Message) (truncated bool) { +func (ml *TruncatingMethodLogger) truncateMessage(msgPb *pb.Message) (truncated bool) { if ml.messageMaxLen == maxUInt { return false } diff --git a/vendor/google.golang.org/grpc/internal/channelz/types.go b/vendor/google.golang.org/grpc/internal/channelz/types.go index ad0ce4dabf..7b2f350e2e 100644 --- a/vendor/google.golang.org/grpc/internal/channelz/types.go +++ b/vendor/google.golang.org/grpc/internal/channelz/types.go @@ -273,10 +273,10 @@ func (c *channel) deleteSelfFromMap() (delete bool) { // deleteSelfIfReady tries to delete the channel itself from the channelz database. // The delete process includes two steps: -// 1. delete the channel from the entry relation tree, i.e. delete the channel reference from its -// parent's child list. -// 2. delete the channel from the map, i.e. delete the channel entirely from channelz. Lookup by id -// will return entry not found error. +// 1. delete the channel from the entry relation tree, i.e. delete the channel reference from its +// parent's child list. +// 2. delete the channel from the map, i.e. delete the channel entirely from channelz. Lookup by id +// will return entry not found error. func (c *channel) deleteSelfIfReady() { if !c.deleteSelfFromTree() { return @@ -381,10 +381,10 @@ func (sc *subChannel) deleteSelfFromMap() (delete bool) { // deleteSelfIfReady tries to delete the subchannel itself from the channelz database. // The delete process includes two steps: -// 1. delete the subchannel from the entry relation tree, i.e. delete the subchannel reference from -// its parent's child list. -// 2. delete the subchannel from the map, i.e. delete the subchannel entirely from channelz. Lookup -// by id will return entry not found error. +// 1. delete the subchannel from the entry relation tree, i.e. delete the subchannel reference from +// its parent's child list. +// 2. delete the subchannel from the map, i.e. delete the subchannel entirely from channelz. Lookup +// by id will return entry not found error. func (sc *subChannel) deleteSelfIfReady() { if !sc.deleteSelfFromTree() { return diff --git a/vendor/google.golang.org/grpc/internal/envconfig/envconfig.go b/vendor/google.golang.org/grpc/internal/envconfig/envconfig.go index 6f02725431..7edd196bd3 100644 --- a/vendor/google.golang.org/grpc/internal/envconfig/envconfig.go +++ b/vendor/google.golang.org/grpc/internal/envconfig/envconfig.go @@ -25,11 +25,15 @@ import ( ) const ( - prefix = "GRPC_GO_" - txtErrIgnoreStr = prefix + "IGNORE_TXT_ERRORS" + prefix = "GRPC_GO_" + txtErrIgnoreStr = prefix + "IGNORE_TXT_ERRORS" + advertiseCompressorsStr = prefix + "ADVERTISE_COMPRESSORS" ) var ( // TXTErrIgnore is set if TXT errors should be ignored ("GRPC_GO_IGNORE_TXT_ERRORS" is not "false"). TXTErrIgnore = !strings.EqualFold(os.Getenv(txtErrIgnoreStr), "false") + // AdvertiseCompressors is set if registered compressor should be advertised + // ("GRPC_GO_ADVERTISE_COMPRESSORS" is not "false"). + AdvertiseCompressors = !strings.EqualFold(os.Getenv(advertiseCompressorsStr), "false") ) diff --git a/vendor/google.golang.org/grpc/internal/envconfig/observability.go b/vendor/google.golang.org/grpc/internal/envconfig/observability.go new file mode 100644 index 0000000000..821dd0a7c1 --- /dev/null +++ b/vendor/google.golang.org/grpc/internal/envconfig/observability.go @@ -0,0 +1,36 @@ +/* + * + * Copyright 2022 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package envconfig + +import "os" + +const ( + envObservabilityConfig = "GRPC_GCP_OBSERVABILITY_CONFIG" + envObservabilityConfigFile = "GRPC_GCP_OBSERVABILITY_CONFIG_FILE" +) + +var ( + // ObservabilityConfig is the json configuration for the gcp/observability + // package specified directly in the envObservabilityConfig env var. + ObservabilityConfig = os.Getenv(envObservabilityConfig) + // ObservabilityConfigFile is the json configuration for the + // gcp/observability specified in a file with the location specified in + // envObservabilityConfigFile env var. + ObservabilityConfigFile = os.Getenv(envObservabilityConfigFile) +) diff --git a/vendor/google.golang.org/grpc/internal/envconfig/xds.go b/vendor/google.golang.org/grpc/internal/envconfig/xds.go index a83b26bb86..af09711a3e 100644 --- a/vendor/google.golang.org/grpc/internal/envconfig/xds.go +++ b/vendor/google.golang.org/grpc/internal/envconfig/xds.go @@ -41,6 +41,7 @@ const ( clientSideSecuritySupportEnv = "GRPC_XDS_EXPERIMENTAL_SECURITY_SUPPORT" aggregateAndDNSSupportEnv = "GRPC_XDS_EXPERIMENTAL_ENABLE_AGGREGATE_AND_LOGICAL_DNS_CLUSTER" rbacSupportEnv = "GRPC_XDS_EXPERIMENTAL_RBAC" + outlierDetectionSupportEnv = "GRPC_EXPERIMENTAL_ENABLE_OUTLIER_DETECTION" federationEnv = "GRPC_EXPERIMENTAL_XDS_FEDERATION" rlsInXDSEnv = "GRPC_EXPERIMENTAL_XDS_RLS_LB" @@ -83,9 +84,9 @@ var ( // "GRPC_XDS_EXPERIMENTAL_RBAC" to "false". XDSRBAC = !strings.EqualFold(os.Getenv(rbacSupportEnv), "false") // XDSOutlierDetection indicates whether outlier detection support is - // enabled, which can be enabled by setting the environment variable - // "GRPC_EXPERIMENTAL_ENABLE_OUTLIER_DETECTION" to "true". - XDSOutlierDetection = false + // enabled, which can be disabled by setting the environment variable + // "GRPC_EXPERIMENTAL_ENABLE_OUTLIER_DETECTION" to "false". + XDSOutlierDetection = !strings.EqualFold(os.Getenv(outlierDetectionSupportEnv), "false") // XDSFederation indicates whether federation support is enabled. XDSFederation = strings.EqualFold(os.Getenv(federationEnv), "true") diff --git a/vendor/google.golang.org/grpc/internal/grpclog/grpclog.go b/vendor/google.golang.org/grpc/internal/grpclog/grpclog.go index 30a3b4258f..b68e26a364 100644 --- a/vendor/google.golang.org/grpc/internal/grpclog/grpclog.go +++ b/vendor/google.golang.org/grpc/internal/grpclog/grpclog.go @@ -110,7 +110,7 @@ type LoggerV2 interface { // This is a copy of the DepthLoggerV2 defined in the external grpclog package. // It is defined here to avoid a circular dependency. // -// Experimental +// # Experimental // // Notice: This type is EXPERIMENTAL and may be changed or removed in a // later release. diff --git a/vendor/google.golang.org/grpc/internal/grpcrand/grpcrand.go b/vendor/google.golang.org/grpc/internal/grpcrand/grpcrand.go index 740f83c2b7..517ea70642 100644 --- a/vendor/google.golang.org/grpc/internal/grpcrand/grpcrand.go +++ b/vendor/google.golang.org/grpc/internal/grpcrand/grpcrand.go @@ -52,6 +52,13 @@ func Intn(n int) int { return r.Intn(n) } +// Int31n implements rand.Int31n on the grpcrand global source. +func Int31n(n int32) int32 { + mu.Lock() + defer mu.Unlock() + return r.Int31n(n) +} + // Float64 implements rand.Float64 on the grpcrand global source. func Float64() float64 { mu.Lock() diff --git a/vendor/google.golang.org/grpc/internal/grpcsync/oncefunc.go b/vendor/google.golang.org/grpc/internal/grpcsync/oncefunc.go new file mode 100644 index 0000000000..6635f7bca9 --- /dev/null +++ b/vendor/google.golang.org/grpc/internal/grpcsync/oncefunc.go @@ -0,0 +1,32 @@ +/* + * + * Copyright 2022 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package grpcsync + +import ( + "sync" +) + +// OnceFunc returns a function wrapping f which ensures f is only executed +// once even if the returned function is executed multiple times. +func OnceFunc(f func()) func() { + var once sync.Once + return func() { + once.Do(f) + } +} diff --git a/vendor/google.golang.org/grpc/internal/grpcutil/compressor.go b/vendor/google.golang.org/grpc/internal/grpcutil/compressor.go new file mode 100644 index 0000000000..9f40909679 --- /dev/null +++ b/vendor/google.golang.org/grpc/internal/grpcutil/compressor.go @@ -0,0 +1,47 @@ +/* + * + * Copyright 2022 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package grpcutil + +import ( + "strings" + + "google.golang.org/grpc/internal/envconfig" +) + +// RegisteredCompressorNames holds names of the registered compressors. +var RegisteredCompressorNames []string + +// IsCompressorNameRegistered returns true when name is available in registry. +func IsCompressorNameRegistered(name string) bool { + for _, compressor := range RegisteredCompressorNames { + if compressor == name { + return true + } + } + return false +} + +// RegisteredCompressors returns a string of registered compressor names +// separated by comma. +func RegisteredCompressors() string { + if !envconfig.AdvertiseCompressors { + return "" + } + return strings.Join(RegisteredCompressorNames, ",") +} diff --git a/vendor/google.golang.org/grpc/internal/grpcutil/method.go b/vendor/google.golang.org/grpc/internal/grpcutil/method.go index e9c4af6483..ec62b4775e 100644 --- a/vendor/google.golang.org/grpc/internal/grpcutil/method.go +++ b/vendor/google.golang.org/grpc/internal/grpcutil/method.go @@ -25,7 +25,6 @@ import ( // ParseMethod splits service and method from the input. It expects format // "/service/method". -// func ParseMethod(methodName string) (service, method string, _ error) { if !strings.HasPrefix(methodName, "/") { return "", "", errors.New("invalid method name: should start with /") diff --git a/vendor/google.golang.org/grpc/internal/internal.go b/vendor/google.golang.org/grpc/internal/internal.go index 83018be7c7..fd0ee3dcaf 100644 --- a/vendor/google.golang.org/grpc/internal/internal.go +++ b/vendor/google.golang.org/grpc/internal/internal.go @@ -63,20 +63,30 @@ var ( // xDS-enabled server invokes this method on a grpc.Server when a particular // listener moves to "not-serving" mode. DrainServerTransports interface{} // func(*grpc.Server, string) - // AddExtraServerOptions adds an array of ServerOption that will be + // AddGlobalServerOptions adds an array of ServerOption that will be // effective globally for newly created servers. The priority will be: 1. // user-provided; 2. this method; 3. default values. - AddExtraServerOptions interface{} // func(opt ...ServerOption) - // ClearExtraServerOptions clears the array of extra ServerOption. This + AddGlobalServerOptions interface{} // func(opt ...ServerOption) + // ClearGlobalServerOptions clears the array of extra ServerOption. This // method is useful in testing and benchmarking. - ClearExtraServerOptions func() - // AddExtraDialOptions adds an array of DialOption that will be effective + ClearGlobalServerOptions func() + // AddGlobalDialOptions adds an array of DialOption that will be effective // globally for newly created client channels. The priority will be: 1. // user-provided; 2. this method; 3. default values. - AddExtraDialOptions interface{} // func(opt ...DialOption) - // ClearExtraDialOptions clears the array of extra DialOption. This + AddGlobalDialOptions interface{} // func(opt ...DialOption) + // ClearGlobalDialOptions clears the array of extra DialOption. This // method is useful in testing and benchmarking. - ClearExtraDialOptions func() + ClearGlobalDialOptions func() + // JoinServerOptions combines the server options passed as arguments into a + // single server option. + JoinServerOptions interface{} // func(...grpc.ServerOption) grpc.ServerOption + + // WithBinaryLogger returns a DialOption that specifies the binary logger + // for a ClientConn. + WithBinaryLogger interface{} // func(binarylog.Logger) grpc.DialOption + // BinaryLogger returns a ServerOption that can set the binary logger for a + // server. + BinaryLogger interface{} // func(binarylog.Logger) grpc.ServerOption // NewXDSResolverWithConfigForTesting creates a new xds resolver builder using // the provided xds bootstrap config instead of the global configuration from @@ -117,22 +127,6 @@ var ( // // TODO: Remove this function once the RBAC env var is removed. UnregisterRBACHTTPFilterForTesting func() - - // RegisterOutlierDetectionBalancerForTesting registers the Outlier - // Detection Balancer for testing purposes, regardless of the Outlier - // Detection environment variable. - // - // TODO: Remove this function once the Outlier Detection env var is removed. - RegisterOutlierDetectionBalancerForTesting func() - - // UnregisterOutlierDetectionBalancerForTesting unregisters the Outlier - // Detection Balancer for testing purposes. This is needed because there is - // no way to unregister the Outlier Detection Balancer after registering it - // solely for testing purposes using - // RegisterOutlierDetectionBalancerForTesting(). - // - // TODO: Remove this function once the Outlier Detection env var is removed. - UnregisterOutlierDetectionBalancerForTesting func() ) // HealthChecker defines the signature of the client-side LB channel health checking function. diff --git a/vendor/google.golang.org/grpc/internal/resolver/unix/unix.go b/vendor/google.golang.org/grpc/internal/resolver/unix/unix.go index 20852e59df..7f1a702cac 100644 --- a/vendor/google.golang.org/grpc/internal/resolver/unix/unix.go +++ b/vendor/google.golang.org/grpc/internal/resolver/unix/unix.go @@ -49,8 +49,9 @@ func (b *builder) Build(target resolver.Target, cc resolver.ClientConn, _ resolv } addr := resolver.Address{Addr: endpoint} if b.scheme == unixAbstractScheme { - // prepend "\x00" to address for unix-abstract - addr.Addr = "\x00" + addr.Addr + // We can not prepend \0 as c++ gRPC does, as in Golang '@' is used to signify we do + // not want trailing \0 in address. + addr.Addr = "@" + addr.Addr } cc.UpdateState(resolver.State{Addresses: []resolver.Address{networktype.Set(addr, "unix")}}) return &nopResolver{}, nil diff --git a/vendor/google.golang.org/grpc/internal/serviceconfig/serviceconfig.go b/vendor/google.golang.org/grpc/internal/serviceconfig/serviceconfig.go index badbdbf597..51e733e495 100644 --- a/vendor/google.golang.org/grpc/internal/serviceconfig/serviceconfig.go +++ b/vendor/google.golang.org/grpc/internal/serviceconfig/serviceconfig.go @@ -67,10 +67,10 @@ func (bc *BalancerConfig) MarshalJSON() ([]byte, error) { // ServiceConfig contains a list of loadBalancingConfigs, each with a name and // config. This method iterates through that list in order, and stops at the // first policy that is supported. -// - If the config for the first supported policy is invalid, the whole service -// config is invalid. -// - If the list doesn't contain any supported policy, the whole service config -// is invalid. +// - If the config for the first supported policy is invalid, the whole service +// config is invalid. +// - If the list doesn't contain any supported policy, the whole service config +// is invalid. func (bc *BalancerConfig) UnmarshalJSON(b []byte) error { var ir intermediateBalancerConfig err := json.Unmarshal(b, &ir) diff --git a/vendor/google.golang.org/grpc/internal/status/status.go b/vendor/google.golang.org/grpc/internal/status/status.go index e5c6513edd..b0ead4f54f 100644 --- a/vendor/google.golang.org/grpc/internal/status/status.go +++ b/vendor/google.golang.org/grpc/internal/status/status.go @@ -164,3 +164,13 @@ func (e *Error) Is(target error) bool { } return proto.Equal(e.s.s, tse.s.s) } + +// IsRestrictedControlPlaneCode returns whether the status includes a code +// restricted for control plane usage as defined by gRFC A54. +func IsRestrictedControlPlaneCode(s *Status) bool { + switch s.Code() { + case codes.InvalidArgument, codes.NotFound, codes.AlreadyExists, codes.FailedPrecondition, codes.Aborted, codes.OutOfRange, codes.DataLoss: + return true + } + return false +} diff --git a/vendor/google.golang.org/grpc/internal/transport/controlbuf.go b/vendor/google.golang.org/grpc/internal/transport/controlbuf.go index 244f4b081d..409769f48f 100644 --- a/vendor/google.golang.org/grpc/internal/transport/controlbuf.go +++ b/vendor/google.golang.org/grpc/internal/transport/controlbuf.go @@ -886,9 +886,9 @@ func (l *loopyWriter) processData() (bool, error) { dataItem := str.itl.peek().(*dataFrame) // Peek at the first data item this stream. // A data item is represented by a dataFrame, since it later translates into // multiple HTTP2 data frames. - // Every dataFrame has two buffers; h that keeps grpc-message header and d that is acutal data. + // Every dataFrame has two buffers; h that keeps grpc-message header and d that is actual data. // As an optimization to keep wire traffic low, data from d is copied to h to make as big as the - // maximum possilbe HTTP2 frame size. + // maximum possible HTTP2 frame size. if len(dataItem.h) == 0 && len(dataItem.d) == 0 { // Empty data frame // Client sends out empty data frame with endStream = true diff --git a/vendor/google.golang.org/grpc/internal/transport/handler_server.go b/vendor/google.golang.org/grpc/internal/transport/handler_server.go index 090120925b..fb272235d8 100644 --- a/vendor/google.golang.org/grpc/internal/transport/handler_server.go +++ b/vendor/google.golang.org/grpc/internal/transport/handler_server.go @@ -442,10 +442,10 @@ func (ht *serverHandlerTransport) Drain() { // mapRecvMsgError returns the non-nil err into the appropriate // error value as expected by callers of *grpc.parser.recvMsg. // In particular, in can only be: -// * io.EOF -// * io.ErrUnexpectedEOF -// * of type transport.ConnectionError -// * an error from the status package +// - io.EOF +// - io.ErrUnexpectedEOF +// - of type transport.ConnectionError +// - an error from the status package func mapRecvMsgError(err error) error { if err == io.EOF || err == io.ErrUnexpectedEOF { return err diff --git a/vendor/google.golang.org/grpc/internal/transport/http2_client.go b/vendor/google.golang.org/grpc/internal/transport/http2_client.go index 28c77af70a..d518b07e16 100644 --- a/vendor/google.golang.org/grpc/internal/transport/http2_client.go +++ b/vendor/google.golang.org/grpc/internal/transport/http2_client.go @@ -38,8 +38,10 @@ import ( "google.golang.org/grpc/credentials" "google.golang.org/grpc/internal/channelz" icredentials "google.golang.org/grpc/internal/credentials" + "google.golang.org/grpc/internal/grpcsync" "google.golang.org/grpc/internal/grpcutil" imetadata "google.golang.org/grpc/internal/metadata" + istatus "google.golang.org/grpc/internal/status" "google.golang.org/grpc/internal/syscall" "google.golang.org/grpc/internal/transport/networktype" "google.golang.org/grpc/keepalive" @@ -99,16 +101,13 @@ type http2Client struct { maxSendHeaderListSize *uint32 bdpEst *bdpEstimator - // onPrefaceReceipt is a callback that client transport calls upon - // receiving server preface to signal that a succefull HTTP2 - // connection was established. - onPrefaceReceipt func() maxConcurrentStreams uint32 streamQuota int64 streamsQuotaAvailable chan struct{} waitingStreams uint32 nextID uint32 + registeredCompressors string // Do not access controlBuf with mu held. mu sync.Mutex // guard the following variables @@ -194,7 +193,7 @@ func isTemporary(err error) bool { // newHTTP2Client constructs a connected ClientTransport to addr based on HTTP2 // and starts to receive messages on it. Non-nil error returns if construction // fails. -func newHTTP2Client(connectCtx, ctx context.Context, addr resolver.Address, opts ConnectOptions, onPrefaceReceipt func(), onGoAway func(GoAwayReason), onClose func()) (_ *http2Client, err error) { +func newHTTP2Client(connectCtx, ctx context.Context, addr resolver.Address, opts ConnectOptions, onGoAway func(GoAwayReason), onClose func()) (_ *http2Client, err error) { scheme := "http" ctx, cancel := context.WithCancel(ctx) defer func() { @@ -216,12 +215,35 @@ func newHTTP2Client(connectCtx, ctx context.Context, addr resolver.Address, opts } return nil, connectionErrorf(true, err, "transport: Error while dialing %v", err) } + // Any further errors will close the underlying connection defer func(conn net.Conn) { if err != nil { conn.Close() } }(conn) + + // The following defer and goroutine monitor the connectCtx for cancelation + // and deadline. On context expiration, the connection is hard closed and + // this function will naturally fail as a result. Otherwise, the defer + // waits for the goroutine to exit to prevent the context from being + // monitored (and to prevent the connection from ever being closed) after + // returning from this function. + ctxMonitorDone := grpcsync.NewEvent() + newClientCtx, newClientDone := context.WithCancel(connectCtx) + defer func() { + newClientDone() // Awaken the goroutine below if connectCtx hasn't expired. + <-ctxMonitorDone.Done() // Wait for the goroutine below to exit. + }() + go func(conn net.Conn) { + defer ctxMonitorDone.Fire() // Signal this goroutine has exited. + <-newClientCtx.Done() // Block until connectCtx expires or the defer above executes. + if connectCtx.Err() != nil { + // connectCtx expired before exiting the function. Hard close the connection. + conn.Close() + } + }(conn) + kp := opts.KeepaliveParams // Validate keepalive parameters. if kp.Time == 0 { @@ -253,15 +275,7 @@ func newHTTP2Client(connectCtx, ctx context.Context, addr resolver.Address, opts } } if transportCreds != nil { - rawConn := conn - // Pull the deadline from the connectCtx, which will be used for - // timeouts in the authentication protocol handshake. Can ignore the - // boolean as the deadline will return the zero value, which will make - // the conn not timeout on I/O operations. - deadline, _ := connectCtx.Deadline() - rawConn.SetDeadline(deadline) - conn, authInfo, err = transportCreds.ClientHandshake(connectCtx, addr.ServerName, rawConn) - rawConn.SetDeadline(time.Time{}) + conn, authInfo, err = transportCreds.ClientHandshake(connectCtx, addr.ServerName, conn) if err != nil { return nil, connectionErrorf(isTemporary(err), err, "transport: authentication handshake failed: %v", err) } @@ -299,6 +313,7 @@ func newHTTP2Client(connectCtx, ctx context.Context, addr resolver.Address, opts ctxDone: ctx.Done(), // Cache Done chan. cancel: cancel, userAgent: opts.UserAgent, + registeredCompressors: grpcutil.RegisteredCompressors(), conn: conn, remoteAddr: conn.RemoteAddr(), localAddr: conn.LocalAddr(), @@ -315,17 +330,18 @@ func newHTTP2Client(connectCtx, ctx context.Context, addr resolver.Address, opts kp: kp, statsHandlers: opts.StatsHandlers, initialWindowSize: initialWindowSize, - onPrefaceReceipt: onPrefaceReceipt, nextID: 1, maxConcurrentStreams: defaultMaxStreamsClient, streamQuota: defaultMaxStreamsClient, streamsQuotaAvailable: make(chan struct{}, 1), czData: new(channelzData), onGoAway: onGoAway, - onClose: onClose, keepaliveEnabled: keepaliveEnabled, bufferPool: newBufferPool(), + onClose: onClose, } + // Add peer information to the http2client context. + t.ctx = peer.NewContext(t.ctx, t.getPeer()) if md, ok := addr.Metadata.(*metadata.MD); ok { t.md = *md @@ -361,21 +377,32 @@ func newHTTP2Client(connectCtx, ctx context.Context, addr resolver.Address, opts t.kpDormancyCond = sync.NewCond(&t.mu) go t.keepalive() } - // Start the reader goroutine for incoming message. Each transport has - // a dedicated goroutine which reads HTTP2 frame from network. Then it - // dispatches the frame to the corresponding stream entity. - go t.reader() + + // Start the reader goroutine for incoming messages. Each transport has a + // dedicated goroutine which reads HTTP2 frames from the network. Then it + // dispatches the frame to the corresponding stream entity. When the + // server preface is received, readerErrCh is closed. If an error occurs + // first, an error is pushed to the channel. This must be checked before + // returning from this function. + readerErrCh := make(chan error, 1) + go t.reader(readerErrCh) + defer func() { + if err == nil { + err = <-readerErrCh + } + if err != nil { + t.Close(err) + } + }() // Send connection preface to server. n, err := t.conn.Write(clientPreface) if err != nil { err = connectionErrorf(true, err, "transport: failed to write client preface: %v", err) - t.Close(err) return nil, err } if n != len(clientPreface) { err = connectionErrorf(true, nil, "transport: preface mismatch, wrote %d bytes; want %d", n, len(clientPreface)) - t.Close(err) return nil, err } var ss []http2.Setting @@ -395,14 +422,12 @@ func newHTTP2Client(connectCtx, ctx context.Context, addr resolver.Address, opts err = t.framer.fr.WriteSettings(ss...) if err != nil { err = connectionErrorf(true, err, "transport: failed to write initial settings frame: %v", err) - t.Close(err) return nil, err } // Adjust the connection flow control window if needed. if delta := uint32(icwz - defaultWindowSize); delta > 0 { if err := t.framer.fr.WriteWindowUpdate(0, delta); err != nil { err = connectionErrorf(true, err, "transport: failed to write window update: %v", err) - t.Close(err) return nil, err } } @@ -469,7 +494,7 @@ func (t *http2Client) newStream(ctx context.Context, callHdr *CallHdr) *Stream { func (t *http2Client) getPeer() *peer.Peer { return &peer.Peer{ Addr: t.remoteAddr, - AuthInfo: t.authInfo, + AuthInfo: t.authInfo, // Can be nil } } @@ -505,9 +530,22 @@ func (t *http2Client) createHeaderFields(ctx context.Context, callHdr *CallHdr) headerFields = append(headerFields, hpack.HeaderField{Name: "grpc-previous-rpc-attempts", Value: strconv.Itoa(callHdr.PreviousAttempts)}) } + registeredCompressors := t.registeredCompressors if callHdr.SendCompress != "" { headerFields = append(headerFields, hpack.HeaderField{Name: "grpc-encoding", Value: callHdr.SendCompress}) - headerFields = append(headerFields, hpack.HeaderField{Name: "grpc-accept-encoding", Value: callHdr.SendCompress}) + // Include the outgoing compressor name when compressor is not registered + // via encoding.RegisterCompressor. This is possible when client uses + // WithCompressor dial option. + if !grpcutil.IsCompressorNameRegistered(callHdr.SendCompress) { + if registeredCompressors != "" { + registeredCompressors += "," + } + registeredCompressors += callHdr.SendCompress + } + } + + if registeredCompressors != "" { + headerFields = append(headerFields, hpack.HeaderField{Name: "grpc-accept-encoding", Value: registeredCompressors}) } if dl, ok := ctx.Deadline(); ok { // Send out timeout regardless its value. The server can detect timeout context by itself. @@ -587,7 +625,11 @@ func (t *http2Client) getTrAuthData(ctx context.Context, audience string) (map[s for _, c := range t.perRPCCreds { data, err := c.GetRequestMetadata(ctx, audience) if err != nil { - if _, ok := status.FromError(err); ok { + if st, ok := status.FromError(err); ok { + // Restrict the code to the list allowed by gRFC A54. + if istatus.IsRestrictedControlPlaneCode(st) { + err = status.Errorf(codes.Internal, "transport: received per-RPC creds error with illegal status: %v", err) + } return nil, err } @@ -616,7 +658,14 @@ func (t *http2Client) getCallAuthData(ctx context.Context, audience string, call } data, err := callCreds.GetRequestMetadata(ctx, audience) if err != nil { - return nil, status.Errorf(codes.Internal, "transport: %v", err) + if st, ok := status.FromError(err); ok { + // Restrict the code to the list allowed by gRFC A54. + if istatus.IsRestrictedControlPlaneCode(st) { + err = status.Errorf(codes.Internal, "transport: received per-RPC creds error with illegal status: %v", err) + } + return nil, err + } + return nil, status.Errorf(codes.Internal, "transport: per-RPC creds failed due to error: %v", err) } callAuthData = make(map[string]string, len(data)) for k, v := range data { @@ -632,13 +681,13 @@ func (t *http2Client) getCallAuthData(ctx context.Context, audience string, call // NewStream errors result in transparent retry, as they mean nothing went onto // the wire. However, there are two notable exceptions: // -// 1. If the stream headers violate the max header list size allowed by the -// server. It's possible this could succeed on another transport, even if -// it's unlikely, but do not transparently retry. -// 2. If the credentials errored when requesting their headers. In this case, -// it's possible a retry can fix the problem, but indefinitely transparently -// retrying is not appropriate as it is likely the credentials, if they can -// eventually succeed, would need I/O to do so. +// 1. If the stream headers violate the max header list size allowed by the +// server. It's possible this could succeed on another transport, even if +// it's unlikely, but do not transparently retry. +// 2. If the credentials errored when requesting their headers. In this case, +// it's possible a retry can fix the problem, but indefinitely transparently +// retrying is not appropriate as it is likely the credentials, if they can +// eventually succeed, would need I/O to do so. type NewStreamError struct { Err error @@ -878,19 +927,15 @@ func (t *http2Client) closeStream(s *Stream, err error, rst bool, rstCode http2. // Close kicks off the shutdown process of the transport. This should be called // only once on a transport. Once it is called, the transport should not be // accessed any more. -// -// This method blocks until the addrConn that initiated this transport is -// re-connected. This happens because t.onClose() begins reconnect logic at the -// addrConn level and blocks until the addrConn is successfully connected. func (t *http2Client) Close(err error) { t.mu.Lock() - // Make sure we only Close once. + // Make sure we only close once. if t.state == closing { t.mu.Unlock() return } - // Call t.onClose before setting the state to closing to prevent the client - // from attempting to create new streams ASAP. + // Call t.onClose ASAP to prevent the client from attempting to create new + // streams. t.onClose() t.state = closing streams := t.activeStreams @@ -1230,18 +1275,29 @@ func (t *http2Client) handleGoAway(f *http2.GoAwayFrame) { if upperLimit == 0 { // This is the first GoAway Frame. upperLimit = math.MaxUint32 // Kill all streams after the GoAway ID. } + + t.prevGoAwayID = id + if len(t.activeStreams) == 0 { + t.mu.Unlock() + t.Close(connectionErrorf(true, nil, "received goaway and there are no active streams")) + return + } + + streamsToClose := make([]*Stream, 0) for streamID, stream := range t.activeStreams { if streamID > id && streamID <= upperLimit { // The stream was unprocessed by the server. - atomic.StoreUint32(&stream.unprocessed, 1) - t.closeStream(stream, errStreamDrain, false, http2.ErrCodeNo, statusGoAway, nil, false) + if streamID > id && streamID <= upperLimit { + atomic.StoreUint32(&stream.unprocessed, 1) + streamsToClose = append(streamsToClose, stream) + } } } - t.prevGoAwayID = id - active := len(t.activeStreams) t.mu.Unlock() - if active == 0 { - t.Close(connectionErrorf(true, nil, "received goaway and there are no active streams")) + // Called outside t.mu because closeStream can take controlBuf's mu, which + // could induce deadlock and is not allowed. + for _, stream := range streamsToClose { + t.closeStream(stream, errStreamDrain, false, http2.ErrCodeNo, statusGoAway, nil, false) } } @@ -1469,33 +1525,35 @@ func (t *http2Client) operateHeaders(frame *http2.MetaHeadersFrame) { t.closeStream(s, io.EOF, rst, http2.ErrCodeNo, statusGen, mdata, true) } -// reader runs as a separate goroutine in charge of reading data from network -// connection. -// -// TODO(zhaoq): currently one reader per transport. Investigate whether this is -// optimal. -// TODO(zhaoq): Check the validity of the incoming frame sequence. -func (t *http2Client) reader() { - defer close(t.readerDone) - // Check the validity of server preface. +// readServerPreface reads and handles the initial settings frame from the +// server. +func (t *http2Client) readServerPreface() error { frame, err := t.framer.fr.ReadFrame() if err != nil { - err = connectionErrorf(true, err, "error reading server preface: %v", err) - t.Close(err) // this kicks off resetTransport, so must be last before return - return - } - t.conn.SetReadDeadline(time.Time{}) // reset deadline once we get the settings frame (we didn't time out, yay!) - if t.keepaliveEnabled { - atomic.StoreInt64(&t.lastRead, time.Now().UnixNano()) + return connectionErrorf(true, err, "error reading server preface: %v", err) } sf, ok := frame.(*http2.SettingsFrame) if !ok { - // this kicks off resetTransport, so must be last before return - t.Close(connectionErrorf(true, nil, "initial http2 frame from server is not a settings frame: %T", frame)) - return + return connectionErrorf(true, nil, "initial http2 frame from server is not a settings frame: %T", frame) } - t.onPrefaceReceipt() t.handleSettings(sf, true) + return nil +} + +// reader verifies the server preface and reads all subsequent data from +// network connection. If the server preface is not read successfully, an +// error is pushed to errCh; otherwise errCh is closed with no error. +func (t *http2Client) reader(errCh chan<- error) { + defer close(t.readerDone) + + if err := t.readServerPreface(); err != nil { + errCh <- err + return + } + close(errCh) + if t.keepaliveEnabled { + atomic.StoreInt64(&t.lastRead, time.Now().UnixNano()) + } // loop to keep reading incoming messages on this transport. for { diff --git a/vendor/google.golang.org/grpc/internal/transport/http2_server.go b/vendor/google.golang.org/grpc/internal/transport/http2_server.go index 28bcba0a33..3dd15647bc 100644 --- a/vendor/google.golang.org/grpc/internal/transport/http2_server.go +++ b/vendor/google.golang.org/grpc/internal/transport/http2_server.go @@ -265,6 +265,9 @@ func NewServerTransport(conn net.Conn, config *ServerConfig) (_ ServerTransport, czData: new(channelzData), bufferPool: newBufferPool(), } + // Add peer information to the http2server context. + t.ctx = peer.NewContext(t.ctx, t.getPeer()) + t.controlBuf = newControlBuffer(t.done) if dynamicWindow { t.bdpEst = &bdpEstimator{ @@ -485,14 +488,7 @@ func (t *http2Server) operateHeaders(frame *http2.MetaHeadersFrame, handle func( } else { s.ctx, s.cancel = context.WithCancel(t.ctx) } - pr := &peer.Peer{ - Addr: t.remoteAddr, - } - // Attach Auth info if there is any. - if t.authInfo != nil { - pr.AuthInfo = t.authInfo - } - s.ctx = peer.NewContext(s.ctx, pr) + // Attach the received metadata to the context. if len(mdata) > 0 { s.ctx = metadata.NewIncomingContext(s.ctx, mdata) @@ -1416,6 +1412,13 @@ func (t *http2Server) getOutFlowWindow() int64 { } } +func (t *http2Server) getPeer() *peer.Peer { + return &peer.Peer{ + Addr: t.remoteAddr, + AuthInfo: t.authInfo, // Can be nil + } +} + func getJitter(v time.Duration) time.Duration { if v == infinity { return 0 diff --git a/vendor/google.golang.org/grpc/internal/transport/http_util.go b/vendor/google.golang.org/grpc/internal/transport/http_util.go index 56e95788d9..2c601a864d 100644 --- a/vendor/google.golang.org/grpc/internal/transport/http_util.go +++ b/vendor/google.golang.org/grpc/internal/transport/http_util.go @@ -20,7 +20,6 @@ package transport import ( "bufio" - "bytes" "encoding/base64" "fmt" "io" @@ -45,7 +44,7 @@ import ( const ( // http2MaxFrameLen specifies the max length of a HTTP2 frame. http2MaxFrameLen = 16384 // 16KB frame - // http://http2.github.io/http2-spec/#SettingValues + // https://httpwg.org/specs/rfc7540.html#SettingValues http2InitHeaderTableSize = 4096 ) @@ -251,13 +250,13 @@ func encodeGrpcMessage(msg string) string { } func encodeGrpcMessageUnchecked(msg string) string { - var buf bytes.Buffer + var sb strings.Builder for len(msg) > 0 { r, size := utf8.DecodeRuneInString(msg) for _, b := range []byte(string(r)) { if size > 1 { // If size > 1, r is not ascii. Always do percent encoding. - buf.WriteString(fmt.Sprintf("%%%02X", b)) + fmt.Fprintf(&sb, "%%%02X", b) continue } @@ -266,14 +265,14 @@ func encodeGrpcMessageUnchecked(msg string) string { // // fmt.Sprintf("%%%02X", utf8.RuneError) gives "%FFFD". if b >= spaceByte && b <= tildeByte && b != percentByte { - buf.WriteByte(b) + sb.WriteByte(b) } else { - buf.WriteString(fmt.Sprintf("%%%02X", b)) + fmt.Fprintf(&sb, "%%%02X", b) } } msg = msg[size:] } - return buf.String() + return sb.String() } // decodeGrpcMessage decodes the msg encoded by encodeGrpcMessage. @@ -291,23 +290,23 @@ func decodeGrpcMessage(msg string) string { } func decodeGrpcMessageUnchecked(msg string) string { - var buf bytes.Buffer + var sb strings.Builder lenMsg := len(msg) for i := 0; i < lenMsg; i++ { c := msg[i] if c == percentByte && i+2 < lenMsg { parsed, err := strconv.ParseUint(msg[i+1:i+3], 16, 8) if err != nil { - buf.WriteByte(c) + sb.WriteByte(c) } else { - buf.WriteByte(byte(parsed)) + sb.WriteByte(byte(parsed)) i += 2 } } else { - buf.WriteByte(c) + sb.WriteByte(c) } } - return buf.String() + return sb.String() } type bufWriter struct { diff --git a/vendor/google.golang.org/grpc/internal/transport/transport.go b/vendor/google.golang.org/grpc/internal/transport/transport.go index 6c3ba85159..2e615ee20c 100644 --- a/vendor/google.golang.org/grpc/internal/transport/transport.go +++ b/vendor/google.golang.org/grpc/internal/transport/transport.go @@ -43,6 +43,10 @@ import ( "google.golang.org/grpc/tap" ) +// ErrNoHeaders is used as a signal that a trailers only response was received, +// and is not a real error. +var ErrNoHeaders = errors.New("stream has no headers") + const logLevel = 2 type bufferPool struct { @@ -366,9 +370,15 @@ func (s *Stream) Header() (metadata.MD, error) { return s.header.Copy(), nil } s.waitOnHeader() + if !s.headerValid { return nil, s.status.Err() } + + if s.noHeaders { + return nil, ErrNoHeaders + } + return s.header.Copy(), nil } @@ -573,8 +583,8 @@ type ConnectOptions struct { // NewClientTransport establishes the transport with the required ConnectOptions // and returns it to the caller. -func NewClientTransport(connectCtx, ctx context.Context, addr resolver.Address, opts ConnectOptions, onPrefaceReceipt func(), onGoAway func(GoAwayReason), onClose func()) (ClientTransport, error) { - return newHTTP2Client(connectCtx, ctx, addr, opts, onPrefaceReceipt, onGoAway, onClose) +func NewClientTransport(connectCtx, ctx context.Context, addr resolver.Address, opts ConnectOptions, onGoAway func(GoAwayReason), onClose func()) (ClientTransport, error) { + return newHTTP2Client(connectCtx, ctx, addr, opts, onGoAway, onClose) } // Options provides additional hints and information for message diff --git a/vendor/google.golang.org/grpc/metadata/metadata.go b/vendor/google.golang.org/grpc/metadata/metadata.go index 8e0f6abe89..fb4a88f59b 100644 --- a/vendor/google.golang.org/grpc/metadata/metadata.go +++ b/vendor/google.golang.org/grpc/metadata/metadata.go @@ -41,16 +41,17 @@ type MD map[string][]string // New creates an MD from a given key-value map. // // Only the following ASCII characters are allowed in keys: -// - digits: 0-9 -// - uppercase letters: A-Z (normalized to lower) -// - lowercase letters: a-z -// - special characters: -_. +// - digits: 0-9 +// - uppercase letters: A-Z (normalized to lower) +// - lowercase letters: a-z +// - special characters: -_. +// // Uppercase letters are automatically converted to lowercase. // // Keys beginning with "grpc-" are reserved for grpc-internal use only and may // result in errors if set in metadata. func New(m map[string]string) MD { - md := MD{} + md := make(MD, len(m)) for k, val := range m { key := strings.ToLower(k) md[key] = append(md[key], val) @@ -62,10 +63,11 @@ func New(m map[string]string) MD { // Pairs panics if len(kv) is odd. // // Only the following ASCII characters are allowed in keys: -// - digits: 0-9 -// - uppercase letters: A-Z (normalized to lower) -// - lowercase letters: a-z -// - special characters: -_. +// - digits: 0-9 +// - uppercase letters: A-Z (normalized to lower) +// - lowercase letters: a-z +// - special characters: -_. +// // Uppercase letters are automatically converted to lowercase. // // Keys beginning with "grpc-" are reserved for grpc-internal use only and may @@ -74,7 +76,7 @@ func Pairs(kv ...string) MD { if len(kv)%2 == 1 { panic(fmt.Sprintf("metadata: Pairs got the odd number of input pairs for metadata: %d", len(kv))) } - md := MD{} + md := make(MD, len(kv)/2) for i := 0; i < len(kv); i += 2 { key := strings.ToLower(kv[i]) md[key] = append(md[key], kv[i+1]) @@ -182,19 +184,51 @@ func FromIncomingContext(ctx context.Context) (MD, bool) { if !ok { return nil, false } - out := MD{} + out := make(MD, len(md)) for k, v := range md { // We need to manually convert all keys to lower case, because MD is a // map, and there's no guarantee that the MD attached to the context is // created using our helper functions. key := strings.ToLower(k) - s := make([]string, len(v)) - copy(s, v) - out[key] = s + out[key] = copyOf(v) } return out, true } +// ValueFromIncomingContext returns the metadata value corresponding to the metadata +// key from the incoming metadata if it exists. Key must be lower-case. +// +// # Experimental +// +// Notice: This API is EXPERIMENTAL and may be changed or removed in a +// later release. +func ValueFromIncomingContext(ctx context.Context, key string) []string { + md, ok := ctx.Value(mdIncomingKey{}).(MD) + if !ok { + return nil + } + + if v, ok := md[key]; ok { + return copyOf(v) + } + for k, v := range md { + // We need to manually convert all keys to lower case, because MD is a + // map, and there's no guarantee that the MD attached to the context is + // created using our helper functions. + if strings.ToLower(k) == key { + return copyOf(v) + } + } + return nil +} + +// the returned slice must not be modified in place +func copyOf(v []string) []string { + vals := make([]string, len(v)) + copy(vals, v) + return vals +} + // FromOutgoingContextRaw returns the un-merged, intermediary contents of rawMD. // // Remember to perform strings.ToLower on the keys, for both the returned MD (MD @@ -222,15 +256,18 @@ func FromOutgoingContext(ctx context.Context) (MD, bool) { return nil, false } - out := MD{} + mdSize := len(raw.md) + for i := range raw.added { + mdSize += len(raw.added[i]) / 2 + } + + out := make(MD, mdSize) for k, v := range raw.md { // We need to manually convert all keys to lower case, because MD is a // map, and there's no guarantee that the MD attached to the context is // created using our helper functions. key := strings.ToLower(k) - s := make([]string, len(v)) - copy(s, v) - out[key] = s + out[key] = copyOf(v) } for _, added := range raw.added { if len(added)%2 == 1 { diff --git a/vendor/google.golang.org/grpc/picker_wrapper.go b/vendor/google.golang.org/grpc/picker_wrapper.go index 843633c910..a5d5516ee0 100644 --- a/vendor/google.golang.org/grpc/picker_wrapper.go +++ b/vendor/google.golang.org/grpc/picker_wrapper.go @@ -26,6 +26,7 @@ import ( "google.golang.org/grpc/balancer" "google.golang.org/grpc/codes" "google.golang.org/grpc/internal/channelz" + istatus "google.golang.org/grpc/internal/status" "google.golang.org/grpc/internal/transport" "google.golang.org/grpc/status" ) @@ -129,8 +130,12 @@ func (pw *pickerWrapper) pick(ctx context.Context, failfast bool, info balancer. if err == balancer.ErrNoSubConnAvailable { continue } - if _, ok := status.FromError(err); ok { + if st, ok := status.FromError(err); ok { // Status error: end the RPC unconditionally with this status. + // First restrict the code to the list allowed by gRFC A54. + if istatus.IsRestrictedControlPlaneCode(st) { + err = status.Errorf(codes.Internal, "received picker error with illegal status: %v", err) + } return nil, nil, dropError{error: err} } // For all other errors, wait for ready RPCs should block and other diff --git a/vendor/google.golang.org/grpc/preloader.go b/vendor/google.golang.org/grpc/preloader.go index 0a1e975ad9..cd45547854 100644 --- a/vendor/google.golang.org/grpc/preloader.go +++ b/vendor/google.golang.org/grpc/preloader.go @@ -25,7 +25,7 @@ import ( // PreparedMsg is responsible for creating a Marshalled and Compressed object. // -// Experimental +// # Experimental // // Notice: This type is EXPERIMENTAL and may be changed or removed in a // later release. diff --git a/vendor/google.golang.org/grpc/resolver/resolver.go b/vendor/google.golang.org/grpc/resolver/resolver.go index ca2e35a359..967cbc7373 100644 --- a/vendor/google.golang.org/grpc/resolver/resolver.go +++ b/vendor/google.golang.org/grpc/resolver/resolver.go @@ -96,7 +96,7 @@ const ( // Address represents a server the client connects to. // -// Experimental +// # Experimental // // Notice: This type is EXPERIMENTAL and may be changed or removed in a // later release. @@ -236,12 +236,12 @@ type ClientConn interface { // // Examples: // -// - "dns://some_authority/foo.bar" -// Target{Scheme: "dns", Authority: "some_authority", Endpoint: "foo.bar"} -// - "foo.bar" -// Target{Scheme: resolver.GetDefaultScheme(), Endpoint: "foo.bar"} -// - "unknown_scheme://authority/endpoint" -// Target{Scheme: resolver.GetDefaultScheme(), Endpoint: "unknown_scheme://authority/endpoint"} +// - "dns://some_authority/foo.bar" +// Target{Scheme: "dns", Authority: "some_authority", Endpoint: "foo.bar"} +// - "foo.bar" +// Target{Scheme: resolver.GetDefaultScheme(), Endpoint: "foo.bar"} +// - "unknown_scheme://authority/endpoint" +// Target{Scheme: resolver.GetDefaultScheme(), Endpoint: "unknown_scheme://authority/endpoint"} type Target struct { // Deprecated: use URL.Scheme instead. Scheme string diff --git a/vendor/google.golang.org/grpc/rpc_util.go b/vendor/google.golang.org/grpc/rpc_util.go index 5d407b004b..934fc1aa01 100644 --- a/vendor/google.golang.org/grpc/rpc_util.go +++ b/vendor/google.golang.org/grpc/rpc_util.go @@ -198,7 +198,7 @@ func Header(md *metadata.MD) CallOption { // HeaderCallOption is a CallOption for collecting response header metadata. // The metadata field will be populated *after* the RPC completes. // -// Experimental +// # Experimental // // Notice: This type is EXPERIMENTAL and may be changed or removed in a // later release. @@ -220,7 +220,7 @@ func Trailer(md *metadata.MD) CallOption { // TrailerCallOption is a CallOption for collecting response trailer metadata. // The metadata field will be populated *after* the RPC completes. // -// Experimental +// # Experimental // // Notice: This type is EXPERIMENTAL and may be changed or removed in a // later release. @@ -242,7 +242,7 @@ func Peer(p *peer.Peer) CallOption { // PeerCallOption is a CallOption for collecting the identity of the remote // peer. The peer field will be populated *after* the RPC completes. // -// Experimental +// # Experimental // // Notice: This type is EXPERIMENTAL and may be changed or removed in a // later release. @@ -282,7 +282,7 @@ func FailFast(failFast bool) CallOption { // FailFastCallOption is a CallOption for indicating whether an RPC should fail // fast or not. // -// Experimental +// # Experimental // // Notice: This type is EXPERIMENTAL and may be changed or removed in a // later release. @@ -305,7 +305,7 @@ func MaxCallRecvMsgSize(bytes int) CallOption { // MaxRecvMsgSizeCallOption is a CallOption that indicates the maximum message // size in bytes the client can receive. // -// Experimental +// # Experimental // // Notice: This type is EXPERIMENTAL and may be changed or removed in a // later release. @@ -328,7 +328,7 @@ func MaxCallSendMsgSize(bytes int) CallOption { // MaxSendMsgSizeCallOption is a CallOption that indicates the maximum message // size in bytes the client can send. // -// Experimental +// # Experimental // // Notice: This type is EXPERIMENTAL and may be changed or removed in a // later release. @@ -351,7 +351,7 @@ func PerRPCCredentials(creds credentials.PerRPCCredentials) CallOption { // PerRPCCredsCallOption is a CallOption that indicates the per-RPC // credentials to use for the call. // -// Experimental +// # Experimental // // Notice: This type is EXPERIMENTAL and may be changed or removed in a // later release. @@ -369,7 +369,7 @@ func (o PerRPCCredsCallOption) after(c *callInfo, attempt *csAttempt) {} // sending the request. If WithCompressor is also set, UseCompressor has // higher priority. // -// Experimental +// # Experimental // // Notice: This API is EXPERIMENTAL and may be changed or removed in a // later release. @@ -379,7 +379,7 @@ func UseCompressor(name string) CallOption { // CompressorCallOption is a CallOption that indicates the compressor to use. // -// Experimental +// # Experimental // // Notice: This type is EXPERIMENTAL and may be changed or removed in a // later release. @@ -416,7 +416,7 @@ func CallContentSubtype(contentSubtype string) CallOption { // ContentSubtypeCallOption is a CallOption that indicates the content-subtype // used for marshaling messages. // -// Experimental +// # Experimental // // Notice: This type is EXPERIMENTAL and may be changed or removed in a // later release. @@ -444,7 +444,7 @@ func (o ContentSubtypeCallOption) after(c *callInfo, attempt *csAttempt) {} // This function is provided for advanced users; prefer to use only // CallContentSubtype to select a registered codec instead. // -// Experimental +// # Experimental // // Notice: This API is EXPERIMENTAL and may be changed or removed in a // later release. @@ -455,7 +455,7 @@ func ForceCodec(codec encoding.Codec) CallOption { // ForceCodecCallOption is a CallOption that indicates the codec used for // marshaling messages. // -// Experimental +// # Experimental // // Notice: This type is EXPERIMENTAL and may be changed or removed in a // later release. @@ -480,7 +480,7 @@ func CallCustomCodec(codec Codec) CallOption { // CustomCodecCallOption is a CallOption that indicates the codec used for // marshaling messages. // -// Experimental +// # Experimental // // Notice: This type is EXPERIMENTAL and may be changed or removed in a // later release. @@ -497,7 +497,7 @@ func (o CustomCodecCallOption) after(c *callInfo, attempt *csAttempt) {} // MaxRetryRPCBufferSize returns a CallOption that limits the amount of memory // used for buffering this RPC's requests for retry purposes. // -// Experimental +// # Experimental // // Notice: This API is EXPERIMENTAL and may be changed or removed in a // later release. @@ -508,7 +508,7 @@ func MaxRetryRPCBufferSize(bytes int) CallOption { // MaxRetryRPCBufferSizeCallOption is a CallOption indicating the amount of // memory to be used for caching this RPC for retry purposes. // -// Experimental +// # Experimental // // Notice: This type is EXPERIMENTAL and may be changed or removed in a // later release. @@ -548,10 +548,11 @@ type parser struct { // format. The caller owns the returned msg memory. // // If there is an error, possible values are: -// * io.EOF, when no messages remain -// * io.ErrUnexpectedEOF -// * of type transport.ConnectionError -// * an error from the status package +// - io.EOF, when no messages remain +// - io.ErrUnexpectedEOF +// - of type transport.ConnectionError +// - an error from the status package +// // No other error values or types must be returned, which also means // that the underlying io.Reader must not return an incompatible // error. diff --git a/vendor/google.golang.org/grpc/server.go b/vendor/google.golang.org/grpc/server.go index 2ad9da7bfc..f4dde72b41 100644 --- a/vendor/google.golang.org/grpc/server.go +++ b/vendor/google.golang.org/grpc/server.go @@ -73,12 +73,14 @@ func init() { internal.DrainServerTransports = func(srv *Server, addr string) { srv.drainServerTransports(addr) } - internal.AddExtraServerOptions = func(opt ...ServerOption) { - extraServerOptions = opt + internal.AddGlobalServerOptions = func(opt ...ServerOption) { + extraServerOptions = append(extraServerOptions, opt...) } - internal.ClearExtraServerOptions = func() { + internal.ClearGlobalServerOptions = func() { extraServerOptions = nil } + internal.BinaryLogger = binaryLogger + internal.JoinServerOptions = newJoinServerOption } var statusOK = status.New(codes.OK, "") @@ -155,6 +157,7 @@ type serverOptions struct { streamInt StreamServerInterceptor chainUnaryInts []UnaryServerInterceptor chainStreamInts []StreamServerInterceptor + binaryLogger binarylog.Logger inTapHandle tap.ServerInHandle statsHandlers []stats.Handler maxConcurrentStreams uint32 @@ -214,6 +217,22 @@ func newFuncServerOption(f func(*serverOptions)) *funcServerOption { } } +// joinServerOption provides a way to combine arbitrary number of server +// options into one. +type joinServerOption struct { + opts []ServerOption +} + +func (mdo *joinServerOption) apply(do *serverOptions) { + for _, opt := range mdo.opts { + opt.apply(do) + } +} + +func newJoinServerOption(opts ...ServerOption) ServerOption { + return &joinServerOption{opts: opts} +} + // WriteBufferSize determines how much data can be batched before doing a write on the wire. // The corresponding memory allocation for this buffer will be twice the size to keep syscalls low. // The default value for this buffer is 32KB. @@ -452,6 +471,14 @@ func StatsHandler(h stats.Handler) ServerOption { }) } +// binaryLogger returns a ServerOption that can set the binary logger for the +// server. +func binaryLogger(bl binarylog.Logger) ServerOption { + return newFuncServerOption(func(o *serverOptions) { + o.binaryLogger = bl + }) +} + // UnknownServiceHandler returns a ServerOption that allows for adding a custom // unknown service handler. The provided method is a bidi-streaming RPC service // handler that will be invoked instead of returning the "unimplemented" gRPC @@ -1199,9 +1226,16 @@ func (s *Server) processUnaryRPC(t transport.ServerTransport, stream *transport. } }() } - - binlog := binarylog.GetMethodLogger(stream.Method()) - if binlog != nil { + var binlogs []binarylog.MethodLogger + if ml := binarylog.GetMethodLogger(stream.Method()); ml != nil { + binlogs = append(binlogs, ml) + } + if s.opts.binaryLogger != nil { + if ml := s.opts.binaryLogger.GetMethodLogger(stream.Method()); ml != nil { + binlogs = append(binlogs, ml) + } + } + if len(binlogs) != 0 { ctx := stream.Context() md, _ := metadata.FromIncomingContext(ctx) logEntry := &binarylog.ClientHeader{ @@ -1221,7 +1255,9 @@ func (s *Server) processUnaryRPC(t transport.ServerTransport, stream *transport. if peer, ok := peer.FromContext(ctx); ok { logEntry.PeerAddr = peer.Addr } - binlog.Log(logEntry) + for _, binlog := range binlogs { + binlog.Log(logEntry) + } } // comp and cp are used for compression. decomp and dc are used for @@ -1261,7 +1297,7 @@ func (s *Server) processUnaryRPC(t transport.ServerTransport, stream *transport. } var payInfo *payloadInfo - if len(shs) != 0 || binlog != nil { + if len(shs) != 0 || len(binlogs) != 0 { payInfo = &payloadInfo{} } d, err := recvAndDecompress(&parser{r: stream}, stream, dc, s.opts.maxReceiveMessageSize, payInfo, decomp) @@ -1287,10 +1323,13 @@ func (s *Server) processUnaryRPC(t transport.ServerTransport, stream *transport. Length: len(d), }) } - if binlog != nil { - binlog.Log(&binarylog.ClientMessage{ + if len(binlogs) != 0 { + cm := &binarylog.ClientMessage{ Message: d, - }) + } + for _, binlog := range binlogs { + binlog.Log(cm) + } } if trInfo != nil { trInfo.tr.LazyLog(&payload{sent: false, msg: v}, true) @@ -1314,18 +1353,24 @@ func (s *Server) processUnaryRPC(t transport.ServerTransport, stream *transport. if e := t.WriteStatus(stream, appStatus); e != nil { channelz.Warningf(logger, s.channelzID, "grpc: Server.processUnaryRPC failed to write status: %v", e) } - if binlog != nil { + if len(binlogs) != 0 { if h, _ := stream.Header(); h.Len() > 0 { // Only log serverHeader if there was header. Otherwise it can // be trailer only. - binlog.Log(&binarylog.ServerHeader{ + sh := &binarylog.ServerHeader{ Header: h, - }) + } + for _, binlog := range binlogs { + binlog.Log(sh) + } } - binlog.Log(&binarylog.ServerTrailer{ + st := &binarylog.ServerTrailer{ Trailer: stream.Trailer(), Err: appErr, - }) + } + for _, binlog := range binlogs { + binlog.Log(st) + } } return appErr } @@ -1351,26 +1396,34 @@ func (s *Server) processUnaryRPC(t transport.ServerTransport, stream *transport. panic(fmt.Sprintf("grpc: Unexpected error (%T) from sendResponse: %v", st, st)) } } - if binlog != nil { + if len(binlogs) != 0 { h, _ := stream.Header() - binlog.Log(&binarylog.ServerHeader{ + sh := &binarylog.ServerHeader{ Header: h, - }) - binlog.Log(&binarylog.ServerTrailer{ + } + st := &binarylog.ServerTrailer{ Trailer: stream.Trailer(), Err: appErr, - }) + } + for _, binlog := range binlogs { + binlog.Log(sh) + binlog.Log(st) + } } return err } - if binlog != nil { + if len(binlogs) != 0 { h, _ := stream.Header() - binlog.Log(&binarylog.ServerHeader{ + sh := &binarylog.ServerHeader{ Header: h, - }) - binlog.Log(&binarylog.ServerMessage{ + } + sm := &binarylog.ServerMessage{ Message: reply, - }) + } + for _, binlog := range binlogs { + binlog.Log(sh) + binlog.Log(sm) + } } if channelz.IsOn() { t.IncrMsgSent() @@ -1382,11 +1435,14 @@ func (s *Server) processUnaryRPC(t transport.ServerTransport, stream *transport. // Should the logging be in WriteStatus? Should we ignore the WriteStatus // error or allow the stats handler to see it? err = t.WriteStatus(stream, statusOK) - if binlog != nil { - binlog.Log(&binarylog.ServerTrailer{ + if len(binlogs) != 0 { + st := &binarylog.ServerTrailer{ Trailer: stream.Trailer(), Err: appErr, - }) + } + for _, binlog := range binlogs { + binlog.Log(st) + } } return err } @@ -1499,8 +1555,15 @@ func (s *Server) processStreamingRPC(t transport.ServerTransport, stream *transp }() } - ss.binlog = binarylog.GetMethodLogger(stream.Method()) - if ss.binlog != nil { + if ml := binarylog.GetMethodLogger(stream.Method()); ml != nil { + ss.binlogs = append(ss.binlogs, ml) + } + if s.opts.binaryLogger != nil { + if ml := s.opts.binaryLogger.GetMethodLogger(stream.Method()); ml != nil { + ss.binlogs = append(ss.binlogs, ml) + } + } + if len(ss.binlogs) != 0 { md, _ := metadata.FromIncomingContext(ctx) logEntry := &binarylog.ClientHeader{ Header: md, @@ -1519,7 +1582,9 @@ func (s *Server) processStreamingRPC(t transport.ServerTransport, stream *transp if peer, ok := peer.FromContext(ss.Context()); ok { logEntry.PeerAddr = peer.Addr } - ss.binlog.Log(logEntry) + for _, binlog := range ss.binlogs { + binlog.Log(logEntry) + } } // If dc is set and matches the stream's compression, use it. Otherwise, try @@ -1585,11 +1650,14 @@ func (s *Server) processStreamingRPC(t transport.ServerTransport, stream *transp ss.mu.Unlock() } t.WriteStatus(ss.s, appStatus) - if ss.binlog != nil { - ss.binlog.Log(&binarylog.ServerTrailer{ + if len(ss.binlogs) != 0 { + st := &binarylog.ServerTrailer{ Trailer: ss.s.Trailer(), Err: appErr, - }) + } + for _, binlog := range ss.binlogs { + binlog.Log(st) + } } // TODO: Should we log an error from WriteStatus here and below? return appErr @@ -1600,11 +1668,14 @@ func (s *Server) processStreamingRPC(t transport.ServerTransport, stream *transp ss.mu.Unlock() } err = t.WriteStatus(ss.s, statusOK) - if ss.binlog != nil { - ss.binlog.Log(&binarylog.ServerTrailer{ + if len(ss.binlogs) != 0 { + st := &binarylog.ServerTrailer{ Trailer: ss.s.Trailer(), Err: appErr, - }) + } + for _, binlog := range ss.binlogs { + binlog.Log(st) + } } return err } diff --git a/vendor/google.golang.org/grpc/serviceconfig/serviceconfig.go b/vendor/google.golang.org/grpc/serviceconfig/serviceconfig.go index 73a2f92661..35e7a20a04 100644 --- a/vendor/google.golang.org/grpc/serviceconfig/serviceconfig.go +++ b/vendor/google.golang.org/grpc/serviceconfig/serviceconfig.go @@ -19,7 +19,7 @@ // Package serviceconfig defines types and methods for operating on gRPC // service configs. // -// Experimental +// # Experimental // // Notice: This package is EXPERIMENTAL and may be changed or removed in a // later release. diff --git a/vendor/google.golang.org/grpc/status/status.go b/vendor/google.golang.org/grpc/status/status.go index 6d163b6e38..623be39f26 100644 --- a/vendor/google.golang.org/grpc/status/status.go +++ b/vendor/google.golang.org/grpc/status/status.go @@ -76,14 +76,14 @@ func FromProto(s *spb.Status) *Status { // FromError returns a Status representation of err. // -// - If err was produced by this package or implements the method `GRPCStatus() -// *Status`, the appropriate Status is returned. +// - If err was produced by this package or implements the method `GRPCStatus() +// *Status`, the appropriate Status is returned. // -// - If err is nil, a Status is returned with codes.OK and no message. +// - If err is nil, a Status is returned with codes.OK and no message. // -// - Otherwise, err is an error not compatible with this package. In this -// case, a Status is returned with codes.Unknown and err's Error() message, -// and ok is false. +// - Otherwise, err is an error not compatible with this package. In this +// case, a Status is returned with codes.Unknown and err's Error() message, +// and ok is false. func FromError(err error) (s *Status, ok bool) { if err == nil { return nil, true diff --git a/vendor/google.golang.org/grpc/stream.go b/vendor/google.golang.org/grpc/stream.go index 446a91e323..960c3e33df 100644 --- a/vendor/google.golang.org/grpc/stream.go +++ b/vendor/google.golang.org/grpc/stream.go @@ -39,6 +39,7 @@ import ( imetadata "google.golang.org/grpc/internal/metadata" iresolver "google.golang.org/grpc/internal/resolver" "google.golang.org/grpc/internal/serviceconfig" + istatus "google.golang.org/grpc/internal/status" "google.golang.org/grpc/internal/transport" "google.golang.org/grpc/metadata" "google.golang.org/grpc/peer" @@ -195,6 +196,13 @@ func newClientStream(ctx context.Context, desc *StreamDesc, cc *ClientConn, meth rpcInfo := iresolver.RPCInfo{Context: ctx, Method: method} rpcConfig, err := cc.safeConfigSelector.SelectConfig(rpcInfo) if err != nil { + if st, ok := status.FromError(err); ok { + // Restrict the code to the list allowed by gRFC A54. + if istatus.IsRestrictedControlPlaneCode(st) { + err = status.Errorf(codes.Internal, "config selector returned illegal status: %v", err) + } + return nil, err + } return nil, toRPCErr(err) } @@ -301,7 +309,14 @@ func newClientStreamWithParams(ctx context.Context, desc *StreamDesc, cc *Client if !cc.dopts.disableRetry { cs.retryThrottler = cc.retryThrottler.Load().(*retryThrottler) } - cs.binlog = binarylog.GetMethodLogger(method) + if ml := binarylog.GetMethodLogger(method); ml != nil { + cs.binlogs = append(cs.binlogs, ml) + } + if cc.dopts.binaryLogger != nil { + if ml := cc.dopts.binaryLogger.GetMethodLogger(method); ml != nil { + cs.binlogs = append(cs.binlogs, ml) + } + } // Pick the transport to use and create a new stream on the transport. // Assign cs.attempt upon success. @@ -322,7 +337,7 @@ func newClientStreamWithParams(ctx context.Context, desc *StreamDesc, cc *Client return nil, err } - if cs.binlog != nil { + if len(cs.binlogs) != 0 { md, _ := metadata.FromOutgoingContext(ctx) logEntry := &binarylog.ClientHeader{ OnClientSide: true, @@ -336,7 +351,9 @@ func newClientStreamWithParams(ctx context.Context, desc *StreamDesc, cc *Client logEntry.Timeout = 0 } } - cs.binlog.Log(logEntry) + for _, binlog := range cs.binlogs { + binlog.Log(logEntry) + } } if desc != unaryStreamDesc { @@ -480,7 +497,7 @@ type clientStream struct { retryThrottler *retryThrottler // The throttler active when the RPC began. - binlog binarylog.MethodLogger // Binary logger, can be nil. + binlogs []binarylog.MethodLogger // serverHeaderBinlogged is a boolean for whether server header has been // logged. Server header will be logged when the first time one of those // happens: stream.Header(), stream.Recv(). @@ -735,17 +752,25 @@ func (cs *clientStream) withRetry(op func(a *csAttempt) error, onSuccess func()) func (cs *clientStream) Header() (metadata.MD, error) { var m metadata.MD + noHeader := false err := cs.withRetry(func(a *csAttempt) error { var err error m, err = a.s.Header() + if err == transport.ErrNoHeaders { + noHeader = true + return nil + } return toRPCErr(err) }, cs.commitAttemptLocked) + if err != nil { cs.finish(err) return nil, err } - if cs.binlog != nil && !cs.serverHeaderBinlogged { - // Only log if binary log is on and header has not been logged. + + if len(cs.binlogs) != 0 && !cs.serverHeaderBinlogged && !noHeader { + // Only log if binary log is on and header has not been logged, and + // there is actually headers to log. logEntry := &binarylog.ServerHeader{ OnClientSide: true, Header: m, @@ -754,8 +779,10 @@ func (cs *clientStream) Header() (metadata.MD, error) { if peer, ok := peer.FromContext(cs.Context()); ok { logEntry.PeerAddr = peer.Addr } - cs.binlog.Log(logEntry) cs.serverHeaderBinlogged = true + for _, binlog := range cs.binlogs { + binlog.Log(logEntry) + } } return m, nil } @@ -829,38 +856,44 @@ func (cs *clientStream) SendMsg(m interface{}) (err error) { return a.sendMsg(m, hdr, payload, data) } err = cs.withRetry(op, func() { cs.bufferForRetryLocked(len(hdr)+len(payload), op) }) - if cs.binlog != nil && err == nil { - cs.binlog.Log(&binarylog.ClientMessage{ + if len(cs.binlogs) != 0 && err == nil { + cm := &binarylog.ClientMessage{ OnClientSide: true, Message: data, - }) + } + for _, binlog := range cs.binlogs { + binlog.Log(cm) + } } return err } func (cs *clientStream) RecvMsg(m interface{}) error { - if cs.binlog != nil && !cs.serverHeaderBinlogged { + if len(cs.binlogs) != 0 && !cs.serverHeaderBinlogged { // Call Header() to binary log header if it's not already logged. cs.Header() } var recvInfo *payloadInfo - if cs.binlog != nil { + if len(cs.binlogs) != 0 { recvInfo = &payloadInfo{} } err := cs.withRetry(func(a *csAttempt) error { return a.recvMsg(m, recvInfo) }, cs.commitAttemptLocked) - if cs.binlog != nil && err == nil { - cs.binlog.Log(&binarylog.ServerMessage{ + if len(cs.binlogs) != 0 && err == nil { + sm := &binarylog.ServerMessage{ OnClientSide: true, Message: recvInfo.uncompressedBytes, - }) + } + for _, binlog := range cs.binlogs { + binlog.Log(sm) + } } if err != nil || !cs.desc.ServerStreams { // err != nil or non-server-streaming indicates end of stream. cs.finish(err) - if cs.binlog != nil { + if len(cs.binlogs) != 0 { // finish will not log Trailer. Log Trailer here. logEntry := &binarylog.ServerTrailer{ OnClientSide: true, @@ -873,7 +906,9 @@ func (cs *clientStream) RecvMsg(m interface{}) error { if peer, ok := peer.FromContext(cs.Context()); ok { logEntry.PeerAddr = peer.Addr } - cs.binlog.Log(logEntry) + for _, binlog := range cs.binlogs { + binlog.Log(logEntry) + } } } return err @@ -894,10 +929,13 @@ func (cs *clientStream) CloseSend() error { return nil } cs.withRetry(op, func() { cs.bufferForRetryLocked(0, op) }) - if cs.binlog != nil { - cs.binlog.Log(&binarylog.ClientHalfClose{ + if len(cs.binlogs) != 0 { + chc := &binarylog.ClientHalfClose{ OnClientSide: true, - }) + } + for _, binlog := range cs.binlogs { + binlog.Log(chc) + } } // We never returned an error here for reasons. return nil @@ -930,10 +968,13 @@ func (cs *clientStream) finish(err error) { // // Only one of cancel or trailer needs to be logged. In the cases where // users don't call RecvMsg, users must have already canceled the RPC. - if cs.binlog != nil && status.Code(err) == codes.Canceled { - cs.binlog.Log(&binarylog.Cancel{ + if len(cs.binlogs) != 0 && status.Code(err) == codes.Canceled { + c := &binarylog.Cancel{ OnClientSide: true, - }) + } + for _, binlog := range cs.binlogs { + binlog.Log(c) + } } if err == nil { cs.retryThrottler.successfulRPC() @@ -1005,6 +1046,7 @@ func (a *csAttempt) recvMsg(m interface{}, payInfo *payloadInfo) (err error) { } return io.EOF // indicates successful end of stream. } + return toRPCErr(err) } if a.trInfo != nil { @@ -1453,7 +1495,7 @@ type serverStream struct { statsHandler []stats.Handler - binlog binarylog.MethodLogger + binlogs []binarylog.MethodLogger // serverHeaderBinlogged indicates whether server header has been logged. It // will happen when one of the following two happens: stream.SendHeader(), // stream.Send(). @@ -1487,12 +1529,15 @@ func (ss *serverStream) SendHeader(md metadata.MD) error { } err = ss.t.WriteHeader(ss.s, md) - if ss.binlog != nil && !ss.serverHeaderBinlogged { + if len(ss.binlogs) != 0 && !ss.serverHeaderBinlogged { h, _ := ss.s.Header() - ss.binlog.Log(&binarylog.ServerHeader{ + sh := &binarylog.ServerHeader{ Header: h, - }) + } ss.serverHeaderBinlogged = true + for _, binlog := range ss.binlogs { + binlog.Log(sh) + } } return err } @@ -1549,17 +1594,23 @@ func (ss *serverStream) SendMsg(m interface{}) (err error) { if err := ss.t.Write(ss.s, hdr, payload, &transport.Options{Last: false}); err != nil { return toRPCErr(err) } - if ss.binlog != nil { + if len(ss.binlogs) != 0 { if !ss.serverHeaderBinlogged { h, _ := ss.s.Header() - ss.binlog.Log(&binarylog.ServerHeader{ + sh := &binarylog.ServerHeader{ Header: h, - }) + } ss.serverHeaderBinlogged = true + for _, binlog := range ss.binlogs { + binlog.Log(sh) + } } - ss.binlog.Log(&binarylog.ServerMessage{ + sm := &binarylog.ServerMessage{ Message: data, - }) + } + for _, binlog := range ss.binlogs { + binlog.Log(sm) + } } if len(ss.statsHandler) != 0 { for _, sh := range ss.statsHandler { @@ -1598,13 +1649,16 @@ func (ss *serverStream) RecvMsg(m interface{}) (err error) { } }() var payInfo *payloadInfo - if len(ss.statsHandler) != 0 || ss.binlog != nil { + if len(ss.statsHandler) != 0 || len(ss.binlogs) != 0 { payInfo = &payloadInfo{} } if err := recv(ss.p, ss.codec, ss.s, ss.dc, m, ss.maxReceiveMessageSize, payInfo, ss.decomp); err != nil { if err == io.EOF { - if ss.binlog != nil { - ss.binlog.Log(&binarylog.ClientHalfClose{}) + if len(ss.binlogs) != 0 { + chc := &binarylog.ClientHalfClose{} + for _, binlog := range ss.binlogs { + binlog.Log(chc) + } } return err } @@ -1625,10 +1679,13 @@ func (ss *serverStream) RecvMsg(m interface{}) (err error) { }) } } - if ss.binlog != nil { - ss.binlog.Log(&binarylog.ClientMessage{ + if len(ss.binlogs) != 0 { + cm := &binarylog.ClientMessage{ Message: payInfo.uncompressedBytes, - }) + } + for _, binlog := range ss.binlogs { + binlog.Log(cm) + } } return nil } diff --git a/vendor/google.golang.org/grpc/tap/tap.go b/vendor/google.golang.org/grpc/tap/tap.go index dbf34e6bb5..bfa5dfa40e 100644 --- a/vendor/google.golang.org/grpc/tap/tap.go +++ b/vendor/google.golang.org/grpc/tap/tap.go @@ -19,7 +19,7 @@ // Package tap defines the function handles which are executed on the transport // layer of gRPC-Go and related information. // -// Experimental +// # Experimental // // Notice: This API is EXPERIMENTAL and may be changed or removed in a // later release. diff --git a/vendor/google.golang.org/grpc/version.go b/vendor/google.golang.org/grpc/version.go index 8934f06bc0..2198e7098d 100644 --- a/vendor/google.golang.org/grpc/version.go +++ b/vendor/google.golang.org/grpc/version.go @@ -19,4 +19,4 @@ package grpc // Version is the current grpc version. -const Version = "1.49.0" +const Version = "1.51.0" diff --git a/vendor/google.golang.org/grpc/vet.sh b/vendor/google.golang.org/grpc/vet.sh index c3fc8253b1..bd8e0cdb33 100644 --- a/vendor/google.golang.org/grpc/vet.sh +++ b/vendor/google.golang.org/grpc/vet.sh @@ -67,7 +67,9 @@ elif [[ "$#" -ne 0 ]]; then fi # - Ensure all source files contain a copyright message. -not git grep -L "\(Copyright [0-9]\{4,\} gRPC authors\)\|DO NOT EDIT" -- '*.go' +# (Done in two parts because Darwin "git grep" has broken support for compound +# exclusion matches.) +(grep -L "DO NOT EDIT" $(git grep -L "\(Copyright [0-9]\{4,\} gRPC authors\)" -- '*.go') || true) | fail_on_output # - Make sure all tests in grpc and grpc/test use leakcheck via Teardown. not grep 'func Test[^(]' *_test.go @@ -81,7 +83,7 @@ not git grep -l 'x/net/context' -- "*.go" git grep -l '"math/rand"' -- "*.go" 2>&1 | not grep -v '^examples\|^stress\|grpcrand\|^benchmark\|wrr_test' # - Do not call grpclog directly. Use grpclog.Component instead. -git grep -l 'grpclog.I\|grpclog.W\|grpclog.E\|grpclog.F\|grpclog.V' -- "*.go" | not grep -v '^grpclog/component.go\|^internal/grpctest/tlogger_test.go' +git grep -l -e 'grpclog.I' --or -e 'grpclog.W' --or -e 'grpclog.E' --or -e 'grpclog.F' --or -e 'grpclog.V' -- "*.go" | not grep -v '^grpclog/component.go\|^internal/grpctest/tlogger_test.go' # - Ensure all ptypes proto packages are renamed when importing. not git grep "\(import \|^\s*\)\"github.com/golang/protobuf/ptypes/" -- "*.go" diff --git a/vendor/k8s.io/api/admission/v1/doc.go b/vendor/k8s.io/api/admission/v1/doc.go new file mode 100644 index 0000000000..cbc6bb59dd --- /dev/null +++ b/vendor/k8s.io/api/admission/v1/doc.go @@ -0,0 +1,23 @@ +/* +Copyright 2019 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// +k8s:deepcopy-gen=package +// +k8s:protobuf-gen=package +// +k8s:openapi-gen=false + +// +groupName=admission.k8s.io + +package v1 // import "k8s.io/api/admission/v1" diff --git a/vendor/k8s.io/api/admission/v1/generated.pb.go b/vendor/k8s.io/api/admission/v1/generated.pb.go new file mode 100644 index 0000000000..a2d8ff5dde --- /dev/null +++ b/vendor/k8s.io/api/admission/v1/generated.pb.go @@ -0,0 +1,1783 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: k8s.io/kubernetes/vendor/k8s.io/api/admission/v1/generated.proto + +package v1 + +import ( + fmt "fmt" + + io "io" + + proto "github.com/gogo/protobuf/proto" + github_com_gogo_protobuf_sortkeys "github.com/gogo/protobuf/sortkeys" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + math "math" + math_bits "math/bits" + reflect "reflect" + strings "strings" + + k8s_io_apimachinery_pkg_types "k8s.io/apimachinery/pkg/types" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +func (m *AdmissionRequest) Reset() { *m = AdmissionRequest{} } +func (*AdmissionRequest) ProtoMessage() {} +func (*AdmissionRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_4b73421fd5edef9f, []int{0} +} +func (m *AdmissionRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *AdmissionRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil +} +func (m *AdmissionRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_AdmissionRequest.Merge(m, src) +} +func (m *AdmissionRequest) XXX_Size() int { + return m.Size() +} +func (m *AdmissionRequest) XXX_DiscardUnknown() { + xxx_messageInfo_AdmissionRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_AdmissionRequest proto.InternalMessageInfo + +func (m *AdmissionResponse) Reset() { *m = AdmissionResponse{} } +func (*AdmissionResponse) ProtoMessage() {} +func (*AdmissionResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_4b73421fd5edef9f, []int{1} +} +func (m *AdmissionResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *AdmissionResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil +} +func (m *AdmissionResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_AdmissionResponse.Merge(m, src) +} +func (m *AdmissionResponse) XXX_Size() int { + return m.Size() +} +func (m *AdmissionResponse) XXX_DiscardUnknown() { + xxx_messageInfo_AdmissionResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_AdmissionResponse proto.InternalMessageInfo + +func (m *AdmissionReview) Reset() { *m = AdmissionReview{} } +func (*AdmissionReview) ProtoMessage() {} +func (*AdmissionReview) Descriptor() ([]byte, []int) { + return fileDescriptor_4b73421fd5edef9f, []int{2} +} +func (m *AdmissionReview) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *AdmissionReview) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil +} +func (m *AdmissionReview) XXX_Merge(src proto.Message) { + xxx_messageInfo_AdmissionReview.Merge(m, src) +} +func (m *AdmissionReview) XXX_Size() int { + return m.Size() +} +func (m *AdmissionReview) XXX_DiscardUnknown() { + xxx_messageInfo_AdmissionReview.DiscardUnknown(m) +} + +var xxx_messageInfo_AdmissionReview proto.InternalMessageInfo + +func init() { + proto.RegisterType((*AdmissionRequest)(nil), "k8s.io.api.admission.v1.AdmissionRequest") + proto.RegisterType((*AdmissionResponse)(nil), "k8s.io.api.admission.v1.AdmissionResponse") + proto.RegisterMapType((map[string]string)(nil), "k8s.io.api.admission.v1.AdmissionResponse.AuditAnnotationsEntry") + proto.RegisterType((*AdmissionReview)(nil), "k8s.io.api.admission.v1.AdmissionReview") +} + +func init() { + proto.RegisterFile("k8s.io/kubernetes/vendor/k8s.io/api/admission/v1/generated.proto", fileDescriptor_4b73421fd5edef9f) +} + +var fileDescriptor_4b73421fd5edef9f = []byte{ + // 921 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x56, 0x4f, 0x6f, 0x1b, 0x45, + 0x14, 0xf7, 0xd6, 0x8e, 0xed, 0x1d, 0x87, 0xda, 0x9d, 0x82, 0xba, 0xf2, 0x61, 0x6d, 0x72, 0x40, + 0x2e, 0x6a, 0x77, 0x49, 0x04, 0x55, 0x54, 0x81, 0xd4, 0x2c, 0xa9, 0x50, 0x40, 0x6a, 0xa2, 0x69, + 0x03, 0x15, 0x07, 0xa4, 0xb1, 0x3d, 0xb5, 0x07, 0xdb, 0x33, 0xcb, 0xce, 0xac, 0x83, 0x6f, 0x9c, + 0x38, 0xf3, 0x0d, 0x38, 0xf2, 0x19, 0xf8, 0x06, 0x39, 0xf6, 0xd8, 0x93, 0x45, 0xcc, 0xb7, 0xc8, + 0x09, 0xcd, 0xec, 0xec, 0x9f, 0x26, 0xb1, 0x08, 0x0d, 0xa7, 0xec, 0xfb, 0xf3, 0xfb, 0xbd, 0x97, + 0xdf, 0xdb, 0xf7, 0xd6, 0xe0, 0xc9, 0x64, 0x57, 0x78, 0x94, 0xfb, 0x93, 0xb8, 0x4f, 0x22, 0x46, + 0x24, 0x11, 0xfe, 0x9c, 0xb0, 0x21, 0x8f, 0x7c, 0x13, 0xc0, 0x21, 0xf5, 0xf1, 0x70, 0x46, 0x85, + 0xa0, 0x9c, 0xf9, 0xf3, 0x6d, 0x7f, 0x44, 0x18, 0x89, 0xb0, 0x24, 0x43, 0x2f, 0x8c, 0xb8, 0xe4, + 0xf0, 0x5e, 0x92, 0xe8, 0xe1, 0x90, 0x7a, 0x59, 0xa2, 0x37, 0xdf, 0x6e, 0x3f, 0x1c, 0x51, 0x39, + 0x8e, 0xfb, 0xde, 0x80, 0xcf, 0xfc, 0x11, 0x1f, 0x71, 0x5f, 0xe7, 0xf7, 0xe3, 0x57, 0xda, 0xd2, + 0x86, 0x7e, 0x4a, 0x78, 0xda, 0x0f, 0x8a, 0x05, 0x63, 0x39, 0x26, 0x4c, 0xd2, 0x01, 0x96, 0x57, + 0x57, 0x6d, 0x7f, 0x9a, 0x67, 0xcf, 0xf0, 0x60, 0x4c, 0x19, 0x89, 0x16, 0x7e, 0x38, 0x19, 0x29, + 0x87, 0xf0, 0x67, 0x44, 0xe2, 0xab, 0x50, 0xfe, 0x3a, 0x54, 0x14, 0x33, 0x49, 0x67, 0xe4, 0x12, + 0xe0, 0xd1, 0xbf, 0x01, 0xc4, 0x60, 0x4c, 0x66, 0xf8, 0x22, 0x6e, 0xeb, 0x77, 0x1b, 0xb4, 0xf6, + 0x52, 0x31, 0x10, 0xf9, 0x29, 0x26, 0x42, 0xc2, 0x00, 0x94, 0x63, 0x3a, 0x74, 0xac, 0xae, 0xd5, + 0xb3, 0x83, 0x4f, 0x4e, 0x97, 0x9d, 0xd2, 0x6a, 0xd9, 0x29, 0x1f, 0x1f, 0xec, 0x9f, 0x2f, 0x3b, + 0x1f, 0xae, 0x2b, 0x24, 0x17, 0x21, 0x11, 0xde, 0xf1, 0xc1, 0x3e, 0x52, 0x60, 0xf8, 0x12, 0x54, + 0x26, 0x94, 0x0d, 0x9d, 0x5b, 0x5d, 0xab, 0xd7, 0xd8, 0x79, 0xe4, 0xe5, 0xe2, 0x67, 0x30, 0x2f, + 0x9c, 0x8c, 0x94, 0x43, 0x78, 0x4a, 0x06, 0x6f, 0xbe, 0xed, 0x7d, 0x15, 0xf1, 0x38, 0xfc, 0x96, + 0x44, 0xaa, 0x99, 0x6f, 0x28, 0x1b, 0x06, 0x9b, 0xa6, 0x78, 0x45, 0x59, 0x48, 0x33, 0xc2, 0x31, + 0xa8, 0x47, 0x44, 0xf0, 0x38, 0x1a, 0x10, 0xa7, 0xac, 0xd9, 0x1f, 0xff, 0x77, 0x76, 0x64, 0x18, + 0x82, 0x96, 0xa9, 0x50, 0x4f, 0x3d, 0x28, 0x63, 0x87, 0x9f, 0x81, 0x86, 0x88, 0xfb, 0x69, 0xc0, + 0xa9, 0x68, 0x3d, 0xee, 0x1a, 0x40, 0xe3, 0x79, 0x1e, 0x42, 0xc5, 0x3c, 0x48, 0x41, 0x23, 0x4a, + 0x94, 0x54, 0x5d, 0x3b, 0xef, 0xdd, 0x48, 0x81, 0xa6, 0x2a, 0x85, 0x72, 0x3a, 0x54, 0xe4, 0x86, + 0x0b, 0xd0, 0x34, 0x66, 0xd6, 0xe5, 0xed, 0x1b, 0x4b, 0x72, 0x77, 0xb5, 0xec, 0x34, 0xd1, 0xdb, + 0xb4, 0xe8, 0x62, 0x1d, 0xf8, 0x35, 0x80, 0xc6, 0x55, 0x10, 0xc2, 0x69, 0x6a, 0x8d, 0xda, 0x46, + 0x23, 0x88, 0x2e, 0x65, 0xa0, 0x2b, 0x50, 0xb0, 0x0b, 0x2a, 0x0c, 0xcf, 0x88, 0xb3, 0xa1, 0xd1, + 0xd9, 0xd0, 0x9f, 0xe1, 0x19, 0x41, 0x3a, 0x02, 0x7d, 0x60, 0xab, 0xbf, 0x22, 0xc4, 0x03, 0xe2, + 0x54, 0x75, 0xda, 0x1d, 0x93, 0x66, 0x3f, 0x4b, 0x03, 0x28, 0xcf, 0x81, 0x9f, 0x03, 0x9b, 0x87, + 0xea, 0x55, 0xa7, 0x9c, 0x39, 0x35, 0x0d, 0x70, 0x53, 0xc0, 0x61, 0x1a, 0x38, 0x2f, 0x1a, 0x28, + 0x07, 0xc0, 0x17, 0xa0, 0x1e, 0x0b, 0x12, 0x1d, 0xb0, 0x57, 0xdc, 0xa9, 0x6b, 0x41, 0x3f, 0xf2, + 0x8a, 0xe7, 0xe3, 0xad, 0xb5, 0x57, 0x42, 0x1e, 0x9b, 0xec, 0xfc, 0x7d, 0x4a, 0x3d, 0x28, 0x63, + 0x82, 0xc7, 0xa0, 0xca, 0xfb, 0x3f, 0x92, 0x81, 0x74, 0x6c, 0xcd, 0xf9, 0x70, 0xed, 0x90, 0xcc, + 0xd6, 0x7a, 0x08, 0x9f, 0x3c, 0xfd, 0x59, 0x12, 0xa6, 0xe6, 0x13, 0xdc, 0x36, 0xd4, 0xd5, 0x43, + 0x4d, 0x82, 0x0c, 0x19, 0xfc, 0x01, 0xd8, 0x7c, 0x3a, 0x4c, 0x9c, 0x0e, 0x78, 0x17, 0xe6, 0x4c, + 0xca, 0xc3, 0x94, 0x07, 0xe5, 0x94, 0x70, 0x0b, 0x54, 0x87, 0xd1, 0x02, 0xc5, 0xcc, 0x69, 0x74, + 0xad, 0x5e, 0x3d, 0x00, 0xaa, 0x87, 0x7d, 0xed, 0x41, 0x26, 0x02, 0x5f, 0x82, 0x1a, 0x0f, 0x95, + 0x18, 0xc2, 0xd9, 0x7c, 0x97, 0x0e, 0x9a, 0xa6, 0x83, 0xda, 0x61, 0xc2, 0x82, 0x52, 0xba, 0xad, + 0x3f, 0x2a, 0xe0, 0x4e, 0xe1, 0x42, 0x89, 0x90, 0x33, 0x41, 0xfe, 0x97, 0x13, 0x75, 0x1f, 0xd4, + 0xf0, 0x74, 0xca, 0x4f, 0x48, 0x72, 0xa5, 0xea, 0x79, 0x13, 0x7b, 0x89, 0x1b, 0xa5, 0x71, 0x78, + 0x04, 0xaa, 0x42, 0x62, 0x19, 0x0b, 0x73, 0x71, 0x1e, 0x5c, 0x6f, 0xbd, 0x9e, 0x6b, 0x4c, 0x22, + 0x18, 0x22, 0x22, 0x9e, 0x4a, 0x64, 0x78, 0x60, 0x07, 0x6c, 0x84, 0x58, 0x0e, 0xc6, 0xfa, 0xaa, + 0x6c, 0x06, 0xf6, 0x6a, 0xd9, 0xd9, 0x38, 0x52, 0x0e, 0x94, 0xf8, 0xe1, 0x2e, 0xb0, 0xf5, 0xc3, + 0x8b, 0x45, 0x98, 0x2e, 0x46, 0x5b, 0x8d, 0xe8, 0x28, 0x75, 0x9e, 0x17, 0x0d, 0x94, 0x27, 0xc3, + 0x5f, 0x2d, 0xd0, 0xc2, 0xf1, 0x90, 0xca, 0x3d, 0xc6, 0xb8, 0xc4, 0xc9, 0x54, 0xaa, 0xdd, 0x72, + 0xaf, 0xb1, 0xf3, 0xc4, 0x5b, 0xf3, 0x11, 0xf4, 0x2e, 0x49, 0xec, 0xed, 0x5d, 0xa0, 0x78, 0xca, + 0x64, 0xb4, 0x08, 0x1c, 0xa3, 0x51, 0xeb, 0x62, 0x18, 0x5d, 0xaa, 0x09, 0x7b, 0xa0, 0x7e, 0x82, + 0x23, 0x46, 0xd9, 0x48, 0x38, 0xb5, 0x6e, 0x59, 0xad, 0xb6, 0xda, 0x8c, 0xef, 0x8c, 0x0f, 0x65, + 0xd1, 0xf6, 0x97, 0xe0, 0x83, 0x2b, 0xcb, 0xc1, 0x16, 0x28, 0x4f, 0xc8, 0x22, 0x99, 0x33, 0x52, + 0x8f, 0xf0, 0x7d, 0xb0, 0x31, 0xc7, 0xd3, 0x98, 0xe8, 0x99, 0xd9, 0x28, 0x31, 0x1e, 0xdf, 0xda, + 0xb5, 0xb6, 0xfe, 0xb4, 0x40, 0xb3, 0xf0, 0x6f, 0xcc, 0x29, 0x39, 0x81, 0x47, 0xa0, 0x66, 0xee, + 0x8d, 0xe6, 0x68, 0xec, 0xdc, 0xbf, 0x8e, 0x02, 0x1a, 0x10, 0x34, 0xd4, 0xab, 0x90, 0xde, 0xc1, + 0x94, 0x46, 0x9d, 0x86, 0xc8, 0x48, 0x64, 0x3e, 0x6e, 0x1f, 0x5f, 0x5f, 0xd4, 0x44, 0x80, 0xd4, + 0x42, 0x19, 0x53, 0xf0, 0xc5, 0xe9, 0x99, 0x5b, 0x7a, 0x7d, 0xe6, 0x96, 0xde, 0x9c, 0xb9, 0xa5, + 0x5f, 0x56, 0xae, 0x75, 0xba, 0x72, 0xad, 0xd7, 0x2b, 0xd7, 0x7a, 0xb3, 0x72, 0xad, 0xbf, 0x56, + 0xae, 0xf5, 0xdb, 0xdf, 0x6e, 0xe9, 0xfb, 0x7b, 0x6b, 0x7e, 0xeb, 0xfc, 0x13, 0x00, 0x00, 0xff, + 0xff, 0x5e, 0xe0, 0xad, 0x0d, 0x1e, 0x09, 0x00, 0x00, +} + +func (m *AdmissionRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *AdmissionRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *AdmissionRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + i -= len(m.RequestSubResource) + copy(dAtA[i:], m.RequestSubResource) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.RequestSubResource))) + i-- + dAtA[i] = 0x7a + if m.RequestResource != nil { + { + size, err := m.RequestResource.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x72 + } + if m.RequestKind != nil { + { + size, err := m.RequestKind.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x6a + } + { + size, err := m.Options.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x62 + if m.DryRun != nil { + i-- + if *m.DryRun { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x58 + } + { + size, err := m.OldObject.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x52 + { + size, err := m.Object.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x4a + { + size, err := m.UserInfo.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x42 + i -= len(m.Operation) + copy(dAtA[i:], m.Operation) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Operation))) + i-- + dAtA[i] = 0x3a + i -= len(m.Namespace) + copy(dAtA[i:], m.Namespace) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Namespace))) + i-- + dAtA[i] = 0x32 + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0x2a + i -= len(m.SubResource) + copy(dAtA[i:], m.SubResource) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.SubResource))) + i-- + dAtA[i] = 0x22 + { + size, err := m.Resource.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + { + size, err := m.Kind.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + i -= len(m.UID) + copy(dAtA[i:], m.UID) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.UID))) + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *AdmissionResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *AdmissionResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *AdmissionResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Warnings) > 0 { + for iNdEx := len(m.Warnings) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Warnings[iNdEx]) + copy(dAtA[i:], m.Warnings[iNdEx]) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Warnings[iNdEx]))) + i-- + dAtA[i] = 0x3a + } + } + if len(m.AuditAnnotations) > 0 { + keysForAuditAnnotations := make([]string, 0, len(m.AuditAnnotations)) + for k := range m.AuditAnnotations { + keysForAuditAnnotations = append(keysForAuditAnnotations, string(k)) + } + github_com_gogo_protobuf_sortkeys.Strings(keysForAuditAnnotations) + for iNdEx := len(keysForAuditAnnotations) - 1; iNdEx >= 0; iNdEx-- { + v := m.AuditAnnotations[string(keysForAuditAnnotations[iNdEx])] + baseI := i + i -= len(v) + copy(dAtA[i:], v) + i = encodeVarintGenerated(dAtA, i, uint64(len(v))) + i-- + dAtA[i] = 0x12 + i -= len(keysForAuditAnnotations[iNdEx]) + copy(dAtA[i:], keysForAuditAnnotations[iNdEx]) + i = encodeVarintGenerated(dAtA, i, uint64(len(keysForAuditAnnotations[iNdEx]))) + i-- + dAtA[i] = 0xa + i = encodeVarintGenerated(dAtA, i, uint64(baseI-i)) + i-- + dAtA[i] = 0x32 + } + } + if m.PatchType != nil { + i -= len(*m.PatchType) + copy(dAtA[i:], *m.PatchType) + i = encodeVarintGenerated(dAtA, i, uint64(len(*m.PatchType))) + i-- + dAtA[i] = 0x2a + } + if m.Patch != nil { + i -= len(m.Patch) + copy(dAtA[i:], m.Patch) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Patch))) + i-- + dAtA[i] = 0x22 + } + if m.Result != nil { + { + size, err := m.Result.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + i-- + if m.Allowed { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x10 + i -= len(m.UID) + copy(dAtA[i:], m.UID) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.UID))) + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *AdmissionReview) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *AdmissionReview) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *AdmissionReview) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Response != nil { + { + size, err := m.Response.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + if m.Request != nil { + { + size, err := m.Request.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintGenerated(dAtA []byte, offset int, v uint64) int { + offset -= sovGenerated(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *AdmissionRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.UID) + n += 1 + l + sovGenerated(uint64(l)) + l = m.Kind.Size() + n += 1 + l + sovGenerated(uint64(l)) + l = m.Resource.Size() + n += 1 + l + sovGenerated(uint64(l)) + l = len(m.SubResource) + n += 1 + l + sovGenerated(uint64(l)) + l = len(m.Name) + n += 1 + l + sovGenerated(uint64(l)) + l = len(m.Namespace) + n += 1 + l + sovGenerated(uint64(l)) + l = len(m.Operation) + n += 1 + l + sovGenerated(uint64(l)) + l = m.UserInfo.Size() + n += 1 + l + sovGenerated(uint64(l)) + l = m.Object.Size() + n += 1 + l + sovGenerated(uint64(l)) + l = m.OldObject.Size() + n += 1 + l + sovGenerated(uint64(l)) + if m.DryRun != nil { + n += 2 + } + l = m.Options.Size() + n += 1 + l + sovGenerated(uint64(l)) + if m.RequestKind != nil { + l = m.RequestKind.Size() + n += 1 + l + sovGenerated(uint64(l)) + } + if m.RequestResource != nil { + l = m.RequestResource.Size() + n += 1 + l + sovGenerated(uint64(l)) + } + l = len(m.RequestSubResource) + n += 1 + l + sovGenerated(uint64(l)) + return n +} + +func (m *AdmissionResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.UID) + n += 1 + l + sovGenerated(uint64(l)) + n += 2 + if m.Result != nil { + l = m.Result.Size() + n += 1 + l + sovGenerated(uint64(l)) + } + if m.Patch != nil { + l = len(m.Patch) + n += 1 + l + sovGenerated(uint64(l)) + } + if m.PatchType != nil { + l = len(*m.PatchType) + n += 1 + l + sovGenerated(uint64(l)) + } + if len(m.AuditAnnotations) > 0 { + for k, v := range m.AuditAnnotations { + _ = k + _ = v + mapEntrySize := 1 + len(k) + sovGenerated(uint64(len(k))) + 1 + len(v) + sovGenerated(uint64(len(v))) + n += mapEntrySize + 1 + sovGenerated(uint64(mapEntrySize)) + } + } + if len(m.Warnings) > 0 { + for _, s := range m.Warnings { + l = len(s) + n += 1 + l + sovGenerated(uint64(l)) + } + } + return n +} + +func (m *AdmissionReview) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Request != nil { + l = m.Request.Size() + n += 1 + l + sovGenerated(uint64(l)) + } + if m.Response != nil { + l = m.Response.Size() + n += 1 + l + sovGenerated(uint64(l)) + } + return n +} + +func sovGenerated(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozGenerated(x uint64) (n int) { + return sovGenerated(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (this *AdmissionRequest) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&AdmissionRequest{`, + `UID:` + fmt.Sprintf("%v", this.UID) + `,`, + `Kind:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.Kind), "GroupVersionKind", "v1.GroupVersionKind", 1), `&`, ``, 1) + `,`, + `Resource:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.Resource), "GroupVersionResource", "v1.GroupVersionResource", 1), `&`, ``, 1) + `,`, + `SubResource:` + fmt.Sprintf("%v", this.SubResource) + `,`, + `Name:` + fmt.Sprintf("%v", this.Name) + `,`, + `Namespace:` + fmt.Sprintf("%v", this.Namespace) + `,`, + `Operation:` + fmt.Sprintf("%v", this.Operation) + `,`, + `UserInfo:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.UserInfo), "UserInfo", "v11.UserInfo", 1), `&`, ``, 1) + `,`, + `Object:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.Object), "RawExtension", "runtime.RawExtension", 1), `&`, ``, 1) + `,`, + `OldObject:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.OldObject), "RawExtension", "runtime.RawExtension", 1), `&`, ``, 1) + `,`, + `DryRun:` + valueToStringGenerated(this.DryRun) + `,`, + `Options:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.Options), "RawExtension", "runtime.RawExtension", 1), `&`, ``, 1) + `,`, + `RequestKind:` + strings.Replace(fmt.Sprintf("%v", this.RequestKind), "GroupVersionKind", "v1.GroupVersionKind", 1) + `,`, + `RequestResource:` + strings.Replace(fmt.Sprintf("%v", this.RequestResource), "GroupVersionResource", "v1.GroupVersionResource", 1) + `,`, + `RequestSubResource:` + fmt.Sprintf("%v", this.RequestSubResource) + `,`, + `}`, + }, "") + return s +} +func (this *AdmissionResponse) String() string { + if this == nil { + return "nil" + } + keysForAuditAnnotations := make([]string, 0, len(this.AuditAnnotations)) + for k := range this.AuditAnnotations { + keysForAuditAnnotations = append(keysForAuditAnnotations, k) + } + github_com_gogo_protobuf_sortkeys.Strings(keysForAuditAnnotations) + mapStringForAuditAnnotations := "map[string]string{" + for _, k := range keysForAuditAnnotations { + mapStringForAuditAnnotations += fmt.Sprintf("%v: %v,", k, this.AuditAnnotations[k]) + } + mapStringForAuditAnnotations += "}" + s := strings.Join([]string{`&AdmissionResponse{`, + `UID:` + fmt.Sprintf("%v", this.UID) + `,`, + `Allowed:` + fmt.Sprintf("%v", this.Allowed) + `,`, + `Result:` + strings.Replace(fmt.Sprintf("%v", this.Result), "Status", "v1.Status", 1) + `,`, + `Patch:` + valueToStringGenerated(this.Patch) + `,`, + `PatchType:` + valueToStringGenerated(this.PatchType) + `,`, + `AuditAnnotations:` + mapStringForAuditAnnotations + `,`, + `Warnings:` + fmt.Sprintf("%v", this.Warnings) + `,`, + `}`, + }, "") + return s +} +func (this *AdmissionReview) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&AdmissionReview{`, + `Request:` + strings.Replace(this.Request.String(), "AdmissionRequest", "AdmissionRequest", 1) + `,`, + `Response:` + strings.Replace(this.Response.String(), "AdmissionResponse", "AdmissionResponse", 1) + `,`, + `}`, + }, "") + return s +} +func valueToStringGenerated(v interface{}) string { + rv := reflect.ValueOf(v) + if rv.IsNil() { + return "nil" + } + pv := reflect.Indirect(rv).Interface() + return fmt.Sprintf("*%v", pv) +} +func (m *AdmissionRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: AdmissionRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: AdmissionRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field UID", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.UID = k8s_io_apimachinery_pkg_types.UID(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Kind", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Kind.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Resource", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Resource.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SubResource", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.SubResource = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Name = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Namespace", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Namespace = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Operation", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Operation = Operation(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field UserInfo", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.UserInfo.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 9: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Object", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Object.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 10: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field OldObject", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.OldObject.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 11: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field DryRun", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + b := bool(v != 0) + m.DryRun = &b + case 12: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Options", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Options.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 13: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RequestKind", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.RequestKind == nil { + m.RequestKind = &v1.GroupVersionKind{} + } + if err := m.RequestKind.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 14: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RequestResource", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.RequestResource == nil { + m.RequestResource = &v1.GroupVersionResource{} + } + if err := m.RequestResource.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 15: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RequestSubResource", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.RequestSubResource = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *AdmissionResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: AdmissionResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: AdmissionResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field UID", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.UID = k8s_io_apimachinery_pkg_types.UID(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Allowed", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Allowed = bool(v != 0) + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Result", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Result == nil { + m.Result = &v1.Status{} + } + if err := m.Result.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Patch", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Patch = append(m.Patch[:0], dAtA[iNdEx:postIndex]...) + if m.Patch == nil { + m.Patch = []byte{} + } + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PatchType", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + s := PatchType(dAtA[iNdEx:postIndex]) + m.PatchType = &s + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AuditAnnotations", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.AuditAnnotations == nil { + m.AuditAnnotations = make(map[string]string) + } + var mapkey string + var mapvalue string + for iNdEx < postIndex { + entryPreIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + if fieldNum == 1 { + var stringLenmapkey uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLenmapkey |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLenmapkey := int(stringLenmapkey) + if intStringLenmapkey < 0 { + return ErrInvalidLengthGenerated + } + postStringIndexmapkey := iNdEx + intStringLenmapkey + if postStringIndexmapkey < 0 { + return ErrInvalidLengthGenerated + } + if postStringIndexmapkey > l { + return io.ErrUnexpectedEOF + } + mapkey = string(dAtA[iNdEx:postStringIndexmapkey]) + iNdEx = postStringIndexmapkey + } else if fieldNum == 2 { + var stringLenmapvalue uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLenmapvalue |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLenmapvalue := int(stringLenmapvalue) + if intStringLenmapvalue < 0 { + return ErrInvalidLengthGenerated + } + postStringIndexmapvalue := iNdEx + intStringLenmapvalue + if postStringIndexmapvalue < 0 { + return ErrInvalidLengthGenerated + } + if postStringIndexmapvalue > l { + return io.ErrUnexpectedEOF + } + mapvalue = string(dAtA[iNdEx:postStringIndexmapvalue]) + iNdEx = postStringIndexmapvalue + } else { + iNdEx = entryPreIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > postIndex { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + m.AuditAnnotations[mapkey] = mapvalue + iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Warnings", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Warnings = append(m.Warnings, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *AdmissionReview) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: AdmissionReview: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: AdmissionReview: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Request", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Request == nil { + m.Request = &AdmissionRequest{} + } + if err := m.Request.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Response", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Response == nil { + m.Response = &AdmissionResponse{} + } + if err := m.Response.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipGenerated(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenerated + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenerated + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenerated + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthGenerated + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupGenerated + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthGenerated + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthGenerated = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowGenerated = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupGenerated = fmt.Errorf("proto: unexpected end of group") +) diff --git a/vendor/k8s.io/api/admission/v1/generated.proto b/vendor/k8s.io/api/admission/v1/generated.proto new file mode 100644 index 0000000000..941deb4fb4 --- /dev/null +++ b/vendor/k8s.io/api/admission/v1/generated.proto @@ -0,0 +1,167 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + + +// This file was autogenerated by go-to-protobuf. Do not edit it manually! + +syntax = "proto2"; + +package k8s.io.api.admission.v1; + +import "k8s.io/api/authentication/v1/generated.proto"; +import "k8s.io/apimachinery/pkg/apis/meta/v1/generated.proto"; +import "k8s.io/apimachinery/pkg/runtime/generated.proto"; +import "k8s.io/apimachinery/pkg/runtime/schema/generated.proto"; + +// Package-wide variables from generator "generated". +option go_package = "k8s.io/api/admission/v1"; + +// AdmissionRequest describes the admission.Attributes for the admission request. +message AdmissionRequest { + // UID is an identifier for the individual request/response. It allows us to distinguish instances of requests which are + // otherwise identical (parallel requests, requests when earlier requests did not modify etc) + // The UID is meant to track the round trip (request/response) between the KAS and the WebHook, not the user request. + // It is suitable for correlating log entries between the webhook and apiserver, for either auditing or debugging. + optional string uid = 1; + + // Kind is the fully-qualified type of object being submitted (for example, v1.Pod or autoscaling.v1.Scale) + optional k8s.io.apimachinery.pkg.apis.meta.v1.GroupVersionKind kind = 2; + + // Resource is the fully-qualified resource being requested (for example, v1.pods) + optional k8s.io.apimachinery.pkg.apis.meta.v1.GroupVersionResource resource = 3; + + // SubResource is the subresource being requested, if any (for example, "status" or "scale") + // +optional + optional string subResource = 4; + + // RequestKind is the fully-qualified type of the original API request (for example, v1.Pod or autoscaling.v1.Scale). + // If this is specified and differs from the value in "kind", an equivalent match and conversion was performed. + // + // For example, if deployments can be modified via apps/v1 and apps/v1beta1, and a webhook registered a rule of + // `apiGroups:["apps"], apiVersions:["v1"], resources: ["deployments"]` and `matchPolicy: Equivalent`, + // an API request to apps/v1beta1 deployments would be converted and sent to the webhook + // with `kind: {group:"apps", version:"v1", kind:"Deployment"}` (matching the rule the webhook registered for), + // and `requestKind: {group:"apps", version:"v1beta1", kind:"Deployment"}` (indicating the kind of the original API request). + // + // See documentation for the "matchPolicy" field in the webhook configuration type for more details. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.GroupVersionKind requestKind = 13; + + // RequestResource is the fully-qualified resource of the original API request (for example, v1.pods). + // If this is specified and differs from the value in "resource", an equivalent match and conversion was performed. + // + // For example, if deployments can be modified via apps/v1 and apps/v1beta1, and a webhook registered a rule of + // `apiGroups:["apps"], apiVersions:["v1"], resources: ["deployments"]` and `matchPolicy: Equivalent`, + // an API request to apps/v1beta1 deployments would be converted and sent to the webhook + // with `resource: {group:"apps", version:"v1", resource:"deployments"}` (matching the resource the webhook registered for), + // and `requestResource: {group:"apps", version:"v1beta1", resource:"deployments"}` (indicating the resource of the original API request). + // + // See documentation for the "matchPolicy" field in the webhook configuration type. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.GroupVersionResource requestResource = 14; + + // RequestSubResource is the name of the subresource of the original API request, if any (for example, "status" or "scale") + // If this is specified and differs from the value in "subResource", an equivalent match and conversion was performed. + // See documentation for the "matchPolicy" field in the webhook configuration type. + // +optional + optional string requestSubResource = 15; + + // Name is the name of the object as presented in the request. On a CREATE operation, the client may omit name and + // rely on the server to generate the name. If that is the case, this field will contain an empty string. + // +optional + optional string name = 5; + + // Namespace is the namespace associated with the request (if any). + // +optional + optional string namespace = 6; + + // Operation is the operation being performed. This may be different than the operation + // requested. e.g. a patch can result in either a CREATE or UPDATE Operation. + optional string operation = 7; + + // UserInfo is information about the requesting user + optional k8s.io.api.authentication.v1.UserInfo userInfo = 8; + + // Object is the object from the incoming request. + // +optional + optional k8s.io.apimachinery.pkg.runtime.RawExtension object = 9; + + // OldObject is the existing object. Only populated for DELETE and UPDATE requests. + // +optional + optional k8s.io.apimachinery.pkg.runtime.RawExtension oldObject = 10; + + // DryRun indicates that modifications will definitely not be persisted for this request. + // Defaults to false. + // +optional + optional bool dryRun = 11; + + // Options is the operation option structure of the operation being performed. + // e.g. `meta.k8s.io/v1.DeleteOptions` or `meta.k8s.io/v1.CreateOptions`. This may be + // different than the options the caller provided. e.g. for a patch request the performed + // Operation might be a CREATE, in which case the Options will a + // `meta.k8s.io/v1.CreateOptions` even though the caller provided `meta.k8s.io/v1.PatchOptions`. + // +optional + optional k8s.io.apimachinery.pkg.runtime.RawExtension options = 12; +} + +// AdmissionResponse describes an admission response. +message AdmissionResponse { + // UID is an identifier for the individual request/response. + // This must be copied over from the corresponding AdmissionRequest. + optional string uid = 1; + + // Allowed indicates whether or not the admission request was permitted. + optional bool allowed = 2; + + // Result contains extra details into why an admission request was denied. + // This field IS NOT consulted in any way if "Allowed" is "true". + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.Status status = 3; + + // The patch body. Currently we only support "JSONPatch" which implements RFC 6902. + // +optional + optional bytes patch = 4; + + // The type of Patch. Currently we only allow "JSONPatch". + // +optional + optional string patchType = 5; + + // AuditAnnotations is an unstructured key value map set by remote admission controller (e.g. error=image-blacklisted). + // MutatingAdmissionWebhook and ValidatingAdmissionWebhook admission controller will prefix the keys with + // admission webhook name (e.g. imagepolicy.example.com/error=image-blacklisted). AuditAnnotations will be provided by + // the admission webhook to add additional context to the audit log for this request. + // +optional + map auditAnnotations = 6; + + // warnings is a list of warning messages to return to the requesting API client. + // Warning messages describe a problem the client making the API request should correct or be aware of. + // Limit warnings to 120 characters if possible. + // Warnings over 256 characters and large numbers of warnings may be truncated. + // +optional + repeated string warnings = 7; +} + +// AdmissionReview describes an admission review request/response. +message AdmissionReview { + // Request describes the attributes for the admission request. + // +optional + optional AdmissionRequest request = 1; + + // Response describes the attributes for the admission response. + // +optional + optional AdmissionResponse response = 2; +} + diff --git a/vendor/k8s.io/api/admission/v1/register.go b/vendor/k8s.io/api/admission/v1/register.go new file mode 100644 index 0000000000..79000535c7 --- /dev/null +++ b/vendor/k8s.io/api/admission/v1/register.go @@ -0,0 +1,53 @@ +/* +Copyright 2019 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +// GroupName is the group name for this API. +const GroupName = "admission.k8s.io" + +// SchemeGroupVersion is group version used to register these objects +var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1"} + +// Resource takes an unqualified resource and returns a Group qualified GroupResource +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} + +// TODO: move SchemeBuilder with zz_generated.deepcopy.go to k8s.io/api. +// localSchemeBuilder and AddToScheme will stay in k8s.io/kubernetes. +var ( + // SchemeBuilder points to a list of functions added to Scheme. + SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) + localSchemeBuilder = &SchemeBuilder + // AddToScheme is a common registration function for mapping packaged scoped group & version keys to a scheme. + AddToScheme = localSchemeBuilder.AddToScheme +) + +// Adds the list of known types to the given scheme. +func addKnownTypes(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(SchemeGroupVersion, + &AdmissionReview{}, + ) + metav1.AddToGroupVersion(scheme, SchemeGroupVersion) + return nil +} diff --git a/vendor/k8s.io/api/admission/v1/types.go b/vendor/k8s.io/api/admission/v1/types.go new file mode 100644 index 0000000000..556fd1ad54 --- /dev/null +++ b/vendor/k8s.io/api/admission/v1/types.go @@ -0,0 +1,169 @@ +/* +Copyright 2019 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +import ( + authenticationv1 "k8s.io/api/authentication/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" +) + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// AdmissionReview describes an admission review request/response. +type AdmissionReview struct { + metav1.TypeMeta `json:",inline"` + // Request describes the attributes for the admission request. + // +optional + Request *AdmissionRequest `json:"request,omitempty" protobuf:"bytes,1,opt,name=request"` + // Response describes the attributes for the admission response. + // +optional + Response *AdmissionResponse `json:"response,omitempty" protobuf:"bytes,2,opt,name=response"` +} + +// AdmissionRequest describes the admission.Attributes for the admission request. +type AdmissionRequest struct { + // UID is an identifier for the individual request/response. It allows us to distinguish instances of requests which are + // otherwise identical (parallel requests, requests when earlier requests did not modify etc) + // The UID is meant to track the round trip (request/response) between the KAS and the WebHook, not the user request. + // It is suitable for correlating log entries between the webhook and apiserver, for either auditing or debugging. + UID types.UID `json:"uid" protobuf:"bytes,1,opt,name=uid"` + // Kind is the fully-qualified type of object being submitted (for example, v1.Pod or autoscaling.v1.Scale) + Kind metav1.GroupVersionKind `json:"kind" protobuf:"bytes,2,opt,name=kind"` + // Resource is the fully-qualified resource being requested (for example, v1.pods) + Resource metav1.GroupVersionResource `json:"resource" protobuf:"bytes,3,opt,name=resource"` + // SubResource is the subresource being requested, if any (for example, "status" or "scale") + // +optional + SubResource string `json:"subResource,omitempty" protobuf:"bytes,4,opt,name=subResource"` + + // RequestKind is the fully-qualified type of the original API request (for example, v1.Pod or autoscaling.v1.Scale). + // If this is specified and differs from the value in "kind", an equivalent match and conversion was performed. + // + // For example, if deployments can be modified via apps/v1 and apps/v1beta1, and a webhook registered a rule of + // `apiGroups:["apps"], apiVersions:["v1"], resources: ["deployments"]` and `matchPolicy: Equivalent`, + // an API request to apps/v1beta1 deployments would be converted and sent to the webhook + // with `kind: {group:"apps", version:"v1", kind:"Deployment"}` (matching the rule the webhook registered for), + // and `requestKind: {group:"apps", version:"v1beta1", kind:"Deployment"}` (indicating the kind of the original API request). + // + // See documentation for the "matchPolicy" field in the webhook configuration type for more details. + // +optional + RequestKind *metav1.GroupVersionKind `json:"requestKind,omitempty" protobuf:"bytes,13,opt,name=requestKind"` + // RequestResource is the fully-qualified resource of the original API request (for example, v1.pods). + // If this is specified and differs from the value in "resource", an equivalent match and conversion was performed. + // + // For example, if deployments can be modified via apps/v1 and apps/v1beta1, and a webhook registered a rule of + // `apiGroups:["apps"], apiVersions:["v1"], resources: ["deployments"]` and `matchPolicy: Equivalent`, + // an API request to apps/v1beta1 deployments would be converted and sent to the webhook + // with `resource: {group:"apps", version:"v1", resource:"deployments"}` (matching the resource the webhook registered for), + // and `requestResource: {group:"apps", version:"v1beta1", resource:"deployments"}` (indicating the resource of the original API request). + // + // See documentation for the "matchPolicy" field in the webhook configuration type. + // +optional + RequestResource *metav1.GroupVersionResource `json:"requestResource,omitempty" protobuf:"bytes,14,opt,name=requestResource"` + // RequestSubResource is the name of the subresource of the original API request, if any (for example, "status" or "scale") + // If this is specified and differs from the value in "subResource", an equivalent match and conversion was performed. + // See documentation for the "matchPolicy" field in the webhook configuration type. + // +optional + RequestSubResource string `json:"requestSubResource,omitempty" protobuf:"bytes,15,opt,name=requestSubResource"` + + // Name is the name of the object as presented in the request. On a CREATE operation, the client may omit name and + // rely on the server to generate the name. If that is the case, this field will contain an empty string. + // +optional + Name string `json:"name,omitempty" protobuf:"bytes,5,opt,name=name"` + // Namespace is the namespace associated with the request (if any). + // +optional + Namespace string `json:"namespace,omitempty" protobuf:"bytes,6,opt,name=namespace"` + // Operation is the operation being performed. This may be different than the operation + // requested. e.g. a patch can result in either a CREATE or UPDATE Operation. + Operation Operation `json:"operation" protobuf:"bytes,7,opt,name=operation"` + // UserInfo is information about the requesting user + UserInfo authenticationv1.UserInfo `json:"userInfo" protobuf:"bytes,8,opt,name=userInfo"` + // Object is the object from the incoming request. + // +optional + Object runtime.RawExtension `json:"object,omitempty" protobuf:"bytes,9,opt,name=object"` + // OldObject is the existing object. Only populated for DELETE and UPDATE requests. + // +optional + OldObject runtime.RawExtension `json:"oldObject,omitempty" protobuf:"bytes,10,opt,name=oldObject"` + // DryRun indicates that modifications will definitely not be persisted for this request. + // Defaults to false. + // +optional + DryRun *bool `json:"dryRun,omitempty" protobuf:"varint,11,opt,name=dryRun"` + // Options is the operation option structure of the operation being performed. + // e.g. `meta.k8s.io/v1.DeleteOptions` or `meta.k8s.io/v1.CreateOptions`. This may be + // different than the options the caller provided. e.g. for a patch request the performed + // Operation might be a CREATE, in which case the Options will a + // `meta.k8s.io/v1.CreateOptions` even though the caller provided `meta.k8s.io/v1.PatchOptions`. + // +optional + Options runtime.RawExtension `json:"options,omitempty" protobuf:"bytes,12,opt,name=options"` +} + +// AdmissionResponse describes an admission response. +type AdmissionResponse struct { + // UID is an identifier for the individual request/response. + // This must be copied over from the corresponding AdmissionRequest. + UID types.UID `json:"uid" protobuf:"bytes,1,opt,name=uid"` + + // Allowed indicates whether or not the admission request was permitted. + Allowed bool `json:"allowed" protobuf:"varint,2,opt,name=allowed"` + + // Result contains extra details into why an admission request was denied. + // This field IS NOT consulted in any way if "Allowed" is "true". + // +optional + Result *metav1.Status `json:"status,omitempty" protobuf:"bytes,3,opt,name=status"` + + // The patch body. Currently we only support "JSONPatch" which implements RFC 6902. + // +optional + Patch []byte `json:"patch,omitempty" protobuf:"bytes,4,opt,name=patch"` + + // The type of Patch. Currently we only allow "JSONPatch". + // +optional + PatchType *PatchType `json:"patchType,omitempty" protobuf:"bytes,5,opt,name=patchType"` + + // AuditAnnotations is an unstructured key value map set by remote admission controller (e.g. error=image-blacklisted). + // MutatingAdmissionWebhook and ValidatingAdmissionWebhook admission controller will prefix the keys with + // admission webhook name (e.g. imagepolicy.example.com/error=image-blacklisted). AuditAnnotations will be provided by + // the admission webhook to add additional context to the audit log for this request. + // +optional + AuditAnnotations map[string]string `json:"auditAnnotations,omitempty" protobuf:"bytes,6,opt,name=auditAnnotations"` + + // warnings is a list of warning messages to return to the requesting API client. + // Warning messages describe a problem the client making the API request should correct or be aware of. + // Limit warnings to 120 characters if possible. + // Warnings over 256 characters and large numbers of warnings may be truncated. + // +optional + Warnings []string `json:"warnings,omitempty" protobuf:"bytes,7,rep,name=warnings"` +} + +// PatchType is the type of patch being used to represent the mutated object +type PatchType string + +// PatchType constants. +const ( + PatchTypeJSONPatch PatchType = "JSONPatch" +) + +// Operation is the type of resource operation being checked for admission control +type Operation string + +// Operation constants +const ( + Create Operation = "CREATE" + Update Operation = "UPDATE" + Delete Operation = "DELETE" + Connect Operation = "CONNECT" +) diff --git a/vendor/k8s.io/api/admission/v1/types_swagger_doc_generated.go b/vendor/k8s.io/api/admission/v1/types_swagger_doc_generated.go new file mode 100644 index 0000000000..f81594c912 --- /dev/null +++ b/vendor/k8s.io/api/admission/v1/types_swagger_doc_generated.go @@ -0,0 +1,78 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +// This file contains a collection of methods that can be used from go-restful to +// generate Swagger API documentation for its models. Please read this PR for more +// information on the implementation: https://github.com/emicklei/go-restful/pull/215 +// +// TODOs are ignored from the parser (e.g. TODO(andronat):... || TODO:...) if and only if +// they are on one line! For multiple line or blocks that you want to ignore use ---. +// Any context after a --- is ignored. +// +// Those methods can be generated by using hack/update-generated-swagger-docs.sh + +// AUTO-GENERATED FUNCTIONS START HERE. DO NOT EDIT. +var map_AdmissionRequest = map[string]string{ + "": "AdmissionRequest describes the admission.Attributes for the admission request.", + "uid": "UID is an identifier for the individual request/response. It allows us to distinguish instances of requests which are otherwise identical (parallel requests, requests when earlier requests did not modify etc) The UID is meant to track the round trip (request/response) between the KAS and the WebHook, not the user request. It is suitable for correlating log entries between the webhook and apiserver, for either auditing or debugging.", + "kind": "Kind is the fully-qualified type of object being submitted (for example, v1.Pod or autoscaling.v1.Scale)", + "resource": "Resource is the fully-qualified resource being requested (for example, v1.pods)", + "subResource": "SubResource is the subresource being requested, if any (for example, \"status\" or \"scale\")", + "requestKind": "RequestKind is the fully-qualified type of the original API request (for example, v1.Pod or autoscaling.v1.Scale). If this is specified and differs from the value in \"kind\", an equivalent match and conversion was performed.\n\nFor example, if deployments can be modified via apps/v1 and apps/v1beta1, and a webhook registered a rule of `apiGroups:[\"apps\"], apiVersions:[\"v1\"], resources: [\"deployments\"]` and `matchPolicy: Equivalent`, an API request to apps/v1beta1 deployments would be converted and sent to the webhook with `kind: {group:\"apps\", version:\"v1\", kind:\"Deployment\"}` (matching the rule the webhook registered for), and `requestKind: {group:\"apps\", version:\"v1beta1\", kind:\"Deployment\"}` (indicating the kind of the original API request).\n\nSee documentation for the \"matchPolicy\" field in the webhook configuration type for more details.", + "requestResource": "RequestResource is the fully-qualified resource of the original API request (for example, v1.pods). If this is specified and differs from the value in \"resource\", an equivalent match and conversion was performed.\n\nFor example, if deployments can be modified via apps/v1 and apps/v1beta1, and a webhook registered a rule of `apiGroups:[\"apps\"], apiVersions:[\"v1\"], resources: [\"deployments\"]` and `matchPolicy: Equivalent`, an API request to apps/v1beta1 deployments would be converted and sent to the webhook with `resource: {group:\"apps\", version:\"v1\", resource:\"deployments\"}` (matching the resource the webhook registered for), and `requestResource: {group:\"apps\", version:\"v1beta1\", resource:\"deployments\"}` (indicating the resource of the original API request).\n\nSee documentation for the \"matchPolicy\" field in the webhook configuration type.", + "requestSubResource": "RequestSubResource is the name of the subresource of the original API request, if any (for example, \"status\" or \"scale\") If this is specified and differs from the value in \"subResource\", an equivalent match and conversion was performed. See documentation for the \"matchPolicy\" field in the webhook configuration type.", + "name": "Name is the name of the object as presented in the request. On a CREATE operation, the client may omit name and rely on the server to generate the name. If that is the case, this field will contain an empty string.", + "namespace": "Namespace is the namespace associated with the request (if any).", + "operation": "Operation is the operation being performed. This may be different than the operation requested. e.g. a patch can result in either a CREATE or UPDATE Operation.", + "userInfo": "UserInfo is information about the requesting user", + "object": "Object is the object from the incoming request.", + "oldObject": "OldObject is the existing object. Only populated for DELETE and UPDATE requests.", + "dryRun": "DryRun indicates that modifications will definitely not be persisted for this request. Defaults to false.", + "options": "Options is the operation option structure of the operation being performed. e.g. `meta.k8s.io/v1.DeleteOptions` or `meta.k8s.io/v1.CreateOptions`. This may be different than the options the caller provided. e.g. for a patch request the performed Operation might be a CREATE, in which case the Options will a `meta.k8s.io/v1.CreateOptions` even though the caller provided `meta.k8s.io/v1.PatchOptions`.", +} + +func (AdmissionRequest) SwaggerDoc() map[string]string { + return map_AdmissionRequest +} + +var map_AdmissionResponse = map[string]string{ + "": "AdmissionResponse describes an admission response.", + "uid": "UID is an identifier for the individual request/response. This must be copied over from the corresponding AdmissionRequest.", + "allowed": "Allowed indicates whether or not the admission request was permitted.", + "status": "Result contains extra details into why an admission request was denied. This field IS NOT consulted in any way if \"Allowed\" is \"true\".", + "patch": "The patch body. Currently we only support \"JSONPatch\" which implements RFC 6902.", + "patchType": "The type of Patch. Currently we only allow \"JSONPatch\".", + "auditAnnotations": "AuditAnnotations is an unstructured key value map set by remote admission controller (e.g. error=image-blacklisted). MutatingAdmissionWebhook and ValidatingAdmissionWebhook admission controller will prefix the keys with admission webhook name (e.g. imagepolicy.example.com/error=image-blacklisted). AuditAnnotations will be provided by the admission webhook to add additional context to the audit log for this request.", + "warnings": "warnings is a list of warning messages to return to the requesting API client. Warning messages describe a problem the client making the API request should correct or be aware of. Limit warnings to 120 characters if possible. Warnings over 256 characters and large numbers of warnings may be truncated.", +} + +func (AdmissionResponse) SwaggerDoc() map[string]string { + return map_AdmissionResponse +} + +var map_AdmissionReview = map[string]string{ + "": "AdmissionReview describes an admission review request/response.", + "request": "Request describes the attributes for the admission request.", + "response": "Response describes the attributes for the admission response.", +} + +func (AdmissionReview) SwaggerDoc() map[string]string { + return map_AdmissionReview +} + +// AUTO-GENERATED FUNCTIONS END HERE diff --git a/vendor/k8s.io/api/admission/v1/zz_generated.deepcopy.go b/vendor/k8s.io/api/admission/v1/zz_generated.deepcopy.go new file mode 100644 index 0000000000..d356882851 --- /dev/null +++ b/vendor/k8s.io/api/admission/v1/zz_generated.deepcopy.go @@ -0,0 +1,142 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package v1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AdmissionRequest) DeepCopyInto(out *AdmissionRequest) { + *out = *in + out.Kind = in.Kind + out.Resource = in.Resource + if in.RequestKind != nil { + in, out := &in.RequestKind, &out.RequestKind + *out = new(metav1.GroupVersionKind) + **out = **in + } + if in.RequestResource != nil { + in, out := &in.RequestResource, &out.RequestResource + *out = new(metav1.GroupVersionResource) + **out = **in + } + in.UserInfo.DeepCopyInto(&out.UserInfo) + in.Object.DeepCopyInto(&out.Object) + in.OldObject.DeepCopyInto(&out.OldObject) + if in.DryRun != nil { + in, out := &in.DryRun, &out.DryRun + *out = new(bool) + **out = **in + } + in.Options.DeepCopyInto(&out.Options) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AdmissionRequest. +func (in *AdmissionRequest) DeepCopy() *AdmissionRequest { + if in == nil { + return nil + } + out := new(AdmissionRequest) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AdmissionResponse) DeepCopyInto(out *AdmissionResponse) { + *out = *in + if in.Result != nil { + in, out := &in.Result, &out.Result + *out = new(metav1.Status) + (*in).DeepCopyInto(*out) + } + if in.Patch != nil { + in, out := &in.Patch, &out.Patch + *out = make([]byte, len(*in)) + copy(*out, *in) + } + if in.PatchType != nil { + in, out := &in.PatchType, &out.PatchType + *out = new(PatchType) + **out = **in + } + if in.AuditAnnotations != nil { + in, out := &in.AuditAnnotations, &out.AuditAnnotations + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.Warnings != nil { + in, out := &in.Warnings, &out.Warnings + *out = make([]string, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AdmissionResponse. +func (in *AdmissionResponse) DeepCopy() *AdmissionResponse { + if in == nil { + return nil + } + out := new(AdmissionResponse) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AdmissionReview) DeepCopyInto(out *AdmissionReview) { + *out = *in + out.TypeMeta = in.TypeMeta + if in.Request != nil { + in, out := &in.Request, &out.Request + *out = new(AdmissionRequest) + (*in).DeepCopyInto(*out) + } + if in.Response != nil { + in, out := &in.Response, &out.Response + *out = new(AdmissionResponse) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AdmissionReview. +func (in *AdmissionReview) DeepCopy() *AdmissionReview { + if in == nil { + return nil + } + out := new(AdmissionReview) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *AdmissionReview) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} diff --git a/vendor/k8s.io/api/admission/v1beta1/doc.go b/vendor/k8s.io/api/admission/v1beta1/doc.go new file mode 100644 index 0000000000..a5669022a0 --- /dev/null +++ b/vendor/k8s.io/api/admission/v1beta1/doc.go @@ -0,0 +1,24 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// +k8s:deepcopy-gen=package +// +k8s:protobuf-gen=package +// +k8s:openapi-gen=false +// +k8s:prerelease-lifecycle-gen=true + +// +groupName=admission.k8s.io + +package v1beta1 // import "k8s.io/api/admission/v1beta1" diff --git a/vendor/k8s.io/api/admission/v1beta1/generated.pb.go b/vendor/k8s.io/api/admission/v1beta1/generated.pb.go new file mode 100644 index 0000000000..c883918142 --- /dev/null +++ b/vendor/k8s.io/api/admission/v1beta1/generated.pb.go @@ -0,0 +1,1783 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: k8s.io/kubernetes/vendor/k8s.io/api/admission/v1beta1/generated.proto + +package v1beta1 + +import ( + fmt "fmt" + + io "io" + + proto "github.com/gogo/protobuf/proto" + github_com_gogo_protobuf_sortkeys "github.com/gogo/protobuf/sortkeys" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + math "math" + math_bits "math/bits" + reflect "reflect" + strings "strings" + + k8s_io_apimachinery_pkg_types "k8s.io/apimachinery/pkg/types" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +func (m *AdmissionRequest) Reset() { *m = AdmissionRequest{} } +func (*AdmissionRequest) ProtoMessage() {} +func (*AdmissionRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_b87c2352de86eab9, []int{0} +} +func (m *AdmissionRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *AdmissionRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil +} +func (m *AdmissionRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_AdmissionRequest.Merge(m, src) +} +func (m *AdmissionRequest) XXX_Size() int { + return m.Size() +} +func (m *AdmissionRequest) XXX_DiscardUnknown() { + xxx_messageInfo_AdmissionRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_AdmissionRequest proto.InternalMessageInfo + +func (m *AdmissionResponse) Reset() { *m = AdmissionResponse{} } +func (*AdmissionResponse) ProtoMessage() {} +func (*AdmissionResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_b87c2352de86eab9, []int{1} +} +func (m *AdmissionResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *AdmissionResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil +} +func (m *AdmissionResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_AdmissionResponse.Merge(m, src) +} +func (m *AdmissionResponse) XXX_Size() int { + return m.Size() +} +func (m *AdmissionResponse) XXX_DiscardUnknown() { + xxx_messageInfo_AdmissionResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_AdmissionResponse proto.InternalMessageInfo + +func (m *AdmissionReview) Reset() { *m = AdmissionReview{} } +func (*AdmissionReview) ProtoMessage() {} +func (*AdmissionReview) Descriptor() ([]byte, []int) { + return fileDescriptor_b87c2352de86eab9, []int{2} +} +func (m *AdmissionReview) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *AdmissionReview) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil +} +func (m *AdmissionReview) XXX_Merge(src proto.Message) { + xxx_messageInfo_AdmissionReview.Merge(m, src) +} +func (m *AdmissionReview) XXX_Size() int { + return m.Size() +} +func (m *AdmissionReview) XXX_DiscardUnknown() { + xxx_messageInfo_AdmissionReview.DiscardUnknown(m) +} + +var xxx_messageInfo_AdmissionReview proto.InternalMessageInfo + +func init() { + proto.RegisterType((*AdmissionRequest)(nil), "k8s.io.api.admission.v1beta1.AdmissionRequest") + proto.RegisterType((*AdmissionResponse)(nil), "k8s.io.api.admission.v1beta1.AdmissionResponse") + proto.RegisterMapType((map[string]string)(nil), "k8s.io.api.admission.v1beta1.AdmissionResponse.AuditAnnotationsEntry") + proto.RegisterType((*AdmissionReview)(nil), "k8s.io.api.admission.v1beta1.AdmissionReview") +} + +func init() { + proto.RegisterFile("k8s.io/kubernetes/vendor/k8s.io/api/admission/v1beta1/generated.proto", fileDescriptor_b87c2352de86eab9) +} + +var fileDescriptor_b87c2352de86eab9 = []byte{ + // 928 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x56, 0xcb, 0x6e, 0xdb, 0x46, + 0x17, 0x16, 0x23, 0x59, 0x12, 0x47, 0xfe, 0x23, 0x65, 0xf2, 0x17, 0x20, 0x84, 0x80, 0x52, 0xbd, + 0x28, 0x54, 0x20, 0x19, 0xd6, 0x46, 0x1b, 0x18, 0x41, 0x37, 0x66, 0x6d, 0x14, 0x6e, 0x81, 0xd8, + 0x98, 0x44, 0x6d, 0xda, 0x45, 0x81, 0x91, 0x34, 0x91, 0x58, 0x49, 0x33, 0x2c, 0x67, 0x28, 0x57, + 0xbb, 0xee, 0xbb, 0xe9, 0x1b, 0xf4, 0x05, 0xfa, 0x16, 0xdd, 0x78, 0x99, 0x65, 0x56, 0x42, 0xad, + 0xbe, 0x85, 0x57, 0xc5, 0x0c, 0x87, 0x97, 0xc8, 0x76, 0x9a, 0x4b, 0x57, 0xe6, 0xb9, 0x7c, 0xdf, + 0x39, 0xfe, 0x0e, 0xcf, 0xa1, 0xc0, 0xd1, 0x74, 0x5f, 0xa0, 0x80, 0x7b, 0xd3, 0x78, 0x40, 0x23, + 0x46, 0x25, 0x15, 0xde, 0x82, 0xb2, 0x11, 0x8f, 0x3c, 0x13, 0x20, 0x61, 0xe0, 0x91, 0xd1, 0x3c, + 0x10, 0x22, 0xe0, 0xcc, 0x5b, 0xec, 0x0e, 0xa8, 0x24, 0xbb, 0xde, 0x98, 0x32, 0x1a, 0x11, 0x49, + 0x47, 0x28, 0x8c, 0xb8, 0xe4, 0xf0, 0x5e, 0x92, 0x8d, 0x48, 0x18, 0xa0, 0x2c, 0x1b, 0x99, 0xec, + 0xf6, 0x83, 0x71, 0x20, 0x27, 0xf1, 0x00, 0x0d, 0xf9, 0xdc, 0x1b, 0xf3, 0x31, 0xf7, 0x34, 0x68, + 0x10, 0x3f, 0xd7, 0x96, 0x36, 0xf4, 0x53, 0x42, 0xd6, 0xbe, 0x5f, 0x2c, 0x1d, 0xcb, 0x09, 0x65, + 0x32, 0x18, 0x12, 0x99, 0xd4, 0xdf, 0x2c, 0xdd, 0xfe, 0x34, 0xcf, 0x9e, 0x93, 0xe1, 0x24, 0x60, + 0x34, 0x5a, 0x7a, 0xe1, 0x74, 0xac, 0x1c, 0xc2, 0x9b, 0x53, 0x49, 0xae, 0x43, 0x79, 0x37, 0xa1, + 0xa2, 0x98, 0xc9, 0x60, 0x4e, 0xaf, 0x00, 0x1e, 0xfe, 0x1b, 0x40, 0x0c, 0x27, 0x74, 0x4e, 0x36, + 0x71, 0x3b, 0xbf, 0xdb, 0xa0, 0x75, 0x90, 0x2a, 0x82, 0xe9, 0x4f, 0x31, 0x15, 0x12, 0xfa, 0xa0, + 0x1c, 0x07, 0x23, 0xc7, 0xea, 0x5a, 0x3d, 0xdb, 0xff, 0xe4, 0x7c, 0xd5, 0x29, 0xad, 0x57, 0x9d, + 0x72, 0xff, 0xf8, 0xf0, 0x72, 0xd5, 0xf9, 0xf0, 0xa6, 0x42, 0x72, 0x19, 0x52, 0x81, 0xfa, 0xc7, + 0x87, 0x58, 0x81, 0xe1, 0x33, 0x50, 0x99, 0x06, 0x6c, 0xe4, 0xdc, 0xea, 0x5a, 0xbd, 0xc6, 0xde, + 0x43, 0x94, 0x4f, 0x20, 0x83, 0xa1, 0x70, 0x3a, 0x56, 0x0e, 0x81, 0x94, 0x0c, 0x68, 0xb1, 0x8b, + 0xbe, 0x8c, 0x78, 0x1c, 0x7e, 0x43, 0x23, 0xd5, 0xcc, 0xd7, 0x01, 0x1b, 0xf9, 0xdb, 0xa6, 0x78, + 0x45, 0x59, 0x58, 0x33, 0xc2, 0x09, 0xa8, 0x47, 0x54, 0xf0, 0x38, 0x1a, 0x52, 0xa7, 0xac, 0xd9, + 0x1f, 0xbd, 0x3d, 0x3b, 0x36, 0x0c, 0x7e, 0xcb, 0x54, 0xa8, 0xa7, 0x1e, 0x9c, 0xb1, 0xc3, 0xcf, + 0x40, 0x43, 0xc4, 0x83, 0x34, 0xe0, 0x54, 0xb4, 0x1e, 0x77, 0x0d, 0xa0, 0xf1, 0x24, 0x0f, 0xe1, + 0x62, 0x1e, 0x0c, 0x40, 0x23, 0x4a, 0x94, 0x54, 0x5d, 0x3b, 0xff, 0x7b, 0x2f, 0x05, 0x9a, 0xaa, + 0x14, 0xce, 0xe9, 0x70, 0x91, 0x1b, 0x2e, 0x41, 0xd3, 0x98, 0x59, 0x97, 0xb7, 0xdf, 0x5b, 0x92, + 0xbb, 0xeb, 0x55, 0xa7, 0x89, 0x5f, 0xa5, 0xc5, 0x9b, 0x75, 0xe0, 0x57, 0x00, 0x1a, 0x57, 0x41, + 0x08, 0xa7, 0xa9, 0x35, 0x6a, 0x1b, 0x8d, 0x20, 0xbe, 0x92, 0x81, 0xaf, 0x41, 0xc1, 0x2e, 0xa8, + 0x30, 0x32, 0xa7, 0xce, 0x96, 0x46, 0x67, 0x43, 0x7f, 0x4c, 0xe6, 0x14, 0xeb, 0x08, 0xf4, 0x80, + 0xad, 0xfe, 0x8a, 0x90, 0x0c, 0xa9, 0x53, 0xd5, 0x69, 0x77, 0x4c, 0x9a, 0xfd, 0x38, 0x0d, 0xe0, + 0x3c, 0x07, 0x7e, 0x0e, 0x6c, 0x1e, 0xaa, 0x57, 0x3d, 0xe0, 0xcc, 0xa9, 0x69, 0x80, 0x9b, 0x02, + 0x4e, 0xd2, 0xc0, 0x65, 0xd1, 0xc0, 0x39, 0x00, 0x3e, 0x05, 0xf5, 0x58, 0xd0, 0xe8, 0x98, 0x3d, + 0xe7, 0x4e, 0x5d, 0x0b, 0xfa, 0x11, 0x2a, 0xde, 0x90, 0x57, 0xd6, 0x5e, 0x09, 0xd9, 0x37, 0xd9, + 0xf9, 0xfb, 0x94, 0x7a, 0x70, 0xc6, 0x04, 0xfb, 0xa0, 0xca, 0x07, 0x3f, 0xd2, 0xa1, 0x74, 0x6c, + 0xcd, 0xf9, 0xe0, 0xc6, 0x21, 0x99, 0xad, 0x45, 0x98, 0x9c, 0x1d, 0xfd, 0x2c, 0x29, 0x53, 0xf3, + 0xf1, 0x6f, 0x1b, 0xea, 0xea, 0x89, 0x26, 0xc1, 0x86, 0x0c, 0xfe, 0x00, 0x6c, 0x3e, 0x1b, 0x25, + 0x4e, 0x07, 0xbc, 0x0b, 0x73, 0x26, 0xe5, 0x49, 0xca, 0x83, 0x73, 0x4a, 0xb8, 0x03, 0xaa, 0xa3, + 0x68, 0x89, 0x63, 0xe6, 0x34, 0xba, 0x56, 0xaf, 0xee, 0x03, 0xd5, 0xc3, 0xa1, 0xf6, 0x60, 0x13, + 0x81, 0xcf, 0x40, 0x8d, 0x87, 0x4a, 0x0c, 0xe1, 0x6c, 0xbf, 0x4b, 0x07, 0x4d, 0xd3, 0x41, 0xed, + 0x24, 0x61, 0xc1, 0x29, 0xdd, 0xce, 0x1f, 0x15, 0x70, 0xa7, 0x70, 0xa1, 0x44, 0xc8, 0x99, 0xa0, + 0xff, 0xc9, 0x89, 0xfa, 0x18, 0xd4, 0xc8, 0x6c, 0xc6, 0xcf, 0x68, 0x72, 0xa5, 0xea, 0x79, 0x13, + 0x07, 0x89, 0x1b, 0xa7, 0x71, 0x78, 0x0a, 0xaa, 0x42, 0x12, 0x19, 0x0b, 0x73, 0x71, 0xee, 0xbf, + 0xd9, 0x7a, 0x3d, 0xd1, 0x98, 0x44, 0x30, 0x4c, 0x45, 0x3c, 0x93, 0xd8, 0xf0, 0xc0, 0x0e, 0xd8, + 0x0a, 0x89, 0x1c, 0x4e, 0xf4, 0x55, 0xd9, 0xf6, 0xed, 0xf5, 0xaa, 0xb3, 0x75, 0xaa, 0x1c, 0x38, + 0xf1, 0xc3, 0x7d, 0x60, 0xeb, 0x87, 0xa7, 0xcb, 0x30, 0x5d, 0x8c, 0xb6, 0x1a, 0xd1, 0x69, 0xea, + 0xbc, 0x2c, 0x1a, 0x38, 0x4f, 0x86, 0xbf, 0x5a, 0xa0, 0x45, 0xe2, 0x51, 0x20, 0x0f, 0x18, 0xe3, + 0x92, 0x24, 0x53, 0xa9, 0x76, 0xcb, 0xbd, 0xc6, 0xde, 0x11, 0x7a, 0xdd, 0x97, 0x10, 0x5d, 0xd1, + 0x19, 0x1d, 0x6c, 0xf0, 0x1c, 0x31, 0x19, 0x2d, 0x7d, 0xc7, 0x08, 0xd5, 0xda, 0x0c, 0xe3, 0x2b, + 0x85, 0x61, 0x0f, 0xd4, 0xcf, 0x48, 0xc4, 0x02, 0x36, 0x16, 0x4e, 0xad, 0x5b, 0x56, 0xfb, 0xad, + 0xd6, 0xe3, 0x5b, 0xe3, 0xc3, 0x59, 0xb4, 0xfd, 0x05, 0xf8, 0xe0, 0xda, 0x72, 0xb0, 0x05, 0xca, + 0x53, 0xba, 0x4c, 0x86, 0x8d, 0xd5, 0x23, 0xfc, 0x3f, 0xd8, 0x5a, 0x90, 0x59, 0x4c, 0xf5, 0xe0, + 0x6c, 0x9c, 0x18, 0x8f, 0x6e, 0xed, 0x5b, 0x3b, 0x7f, 0x5a, 0xa0, 0x59, 0xf8, 0x37, 0x16, 0x01, + 0x3d, 0x83, 0x7d, 0x50, 0x33, 0x47, 0x47, 0x73, 0x34, 0xf6, 0xd0, 0x1b, 0xcb, 0xa0, 0x51, 0x7e, + 0x43, 0xbd, 0x14, 0xe9, 0x45, 0x4c, 0xb9, 0xe0, 0x77, 0xfa, 0x43, 0xa4, 0x75, 0x32, 0x9f, 0x39, + 0xef, 0x2d, 0xe5, 0x4d, 0xa4, 0x48, 0x2d, 0x9c, 0xd1, 0xf9, 0xfe, 0xf9, 0x85, 0x5b, 0x7a, 0x71, + 0xe1, 0x96, 0x5e, 0x5e, 0xb8, 0xa5, 0x5f, 0xd6, 0xae, 0x75, 0xbe, 0x76, 0xad, 0x17, 0x6b, 0xd7, + 0x7a, 0xb9, 0x76, 0xad, 0xbf, 0xd6, 0xae, 0xf5, 0xdb, 0xdf, 0x6e, 0xe9, 0xfb, 0x7b, 0xaf, 0xfb, + 0x11, 0xf4, 0x4f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x69, 0x3c, 0x61, 0x0b, 0x3c, 0x09, 0x00, 0x00, +} + +func (m *AdmissionRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *AdmissionRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *AdmissionRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + i -= len(m.RequestSubResource) + copy(dAtA[i:], m.RequestSubResource) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.RequestSubResource))) + i-- + dAtA[i] = 0x7a + if m.RequestResource != nil { + { + size, err := m.RequestResource.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x72 + } + if m.RequestKind != nil { + { + size, err := m.RequestKind.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x6a + } + { + size, err := m.Options.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x62 + if m.DryRun != nil { + i-- + if *m.DryRun { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x58 + } + { + size, err := m.OldObject.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x52 + { + size, err := m.Object.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x4a + { + size, err := m.UserInfo.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x42 + i -= len(m.Operation) + copy(dAtA[i:], m.Operation) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Operation))) + i-- + dAtA[i] = 0x3a + i -= len(m.Namespace) + copy(dAtA[i:], m.Namespace) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Namespace))) + i-- + dAtA[i] = 0x32 + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0x2a + i -= len(m.SubResource) + copy(dAtA[i:], m.SubResource) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.SubResource))) + i-- + dAtA[i] = 0x22 + { + size, err := m.Resource.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + { + size, err := m.Kind.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + i -= len(m.UID) + copy(dAtA[i:], m.UID) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.UID))) + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *AdmissionResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *AdmissionResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *AdmissionResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Warnings) > 0 { + for iNdEx := len(m.Warnings) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Warnings[iNdEx]) + copy(dAtA[i:], m.Warnings[iNdEx]) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Warnings[iNdEx]))) + i-- + dAtA[i] = 0x3a + } + } + if len(m.AuditAnnotations) > 0 { + keysForAuditAnnotations := make([]string, 0, len(m.AuditAnnotations)) + for k := range m.AuditAnnotations { + keysForAuditAnnotations = append(keysForAuditAnnotations, string(k)) + } + github_com_gogo_protobuf_sortkeys.Strings(keysForAuditAnnotations) + for iNdEx := len(keysForAuditAnnotations) - 1; iNdEx >= 0; iNdEx-- { + v := m.AuditAnnotations[string(keysForAuditAnnotations[iNdEx])] + baseI := i + i -= len(v) + copy(dAtA[i:], v) + i = encodeVarintGenerated(dAtA, i, uint64(len(v))) + i-- + dAtA[i] = 0x12 + i -= len(keysForAuditAnnotations[iNdEx]) + copy(dAtA[i:], keysForAuditAnnotations[iNdEx]) + i = encodeVarintGenerated(dAtA, i, uint64(len(keysForAuditAnnotations[iNdEx]))) + i-- + dAtA[i] = 0xa + i = encodeVarintGenerated(dAtA, i, uint64(baseI-i)) + i-- + dAtA[i] = 0x32 + } + } + if m.PatchType != nil { + i -= len(*m.PatchType) + copy(dAtA[i:], *m.PatchType) + i = encodeVarintGenerated(dAtA, i, uint64(len(*m.PatchType))) + i-- + dAtA[i] = 0x2a + } + if m.Patch != nil { + i -= len(m.Patch) + copy(dAtA[i:], m.Patch) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Patch))) + i-- + dAtA[i] = 0x22 + } + if m.Result != nil { + { + size, err := m.Result.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + i-- + if m.Allowed { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x10 + i -= len(m.UID) + copy(dAtA[i:], m.UID) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.UID))) + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *AdmissionReview) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *AdmissionReview) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *AdmissionReview) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Response != nil { + { + size, err := m.Response.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + if m.Request != nil { + { + size, err := m.Request.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintGenerated(dAtA []byte, offset int, v uint64) int { + offset -= sovGenerated(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *AdmissionRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.UID) + n += 1 + l + sovGenerated(uint64(l)) + l = m.Kind.Size() + n += 1 + l + sovGenerated(uint64(l)) + l = m.Resource.Size() + n += 1 + l + sovGenerated(uint64(l)) + l = len(m.SubResource) + n += 1 + l + sovGenerated(uint64(l)) + l = len(m.Name) + n += 1 + l + sovGenerated(uint64(l)) + l = len(m.Namespace) + n += 1 + l + sovGenerated(uint64(l)) + l = len(m.Operation) + n += 1 + l + sovGenerated(uint64(l)) + l = m.UserInfo.Size() + n += 1 + l + sovGenerated(uint64(l)) + l = m.Object.Size() + n += 1 + l + sovGenerated(uint64(l)) + l = m.OldObject.Size() + n += 1 + l + sovGenerated(uint64(l)) + if m.DryRun != nil { + n += 2 + } + l = m.Options.Size() + n += 1 + l + sovGenerated(uint64(l)) + if m.RequestKind != nil { + l = m.RequestKind.Size() + n += 1 + l + sovGenerated(uint64(l)) + } + if m.RequestResource != nil { + l = m.RequestResource.Size() + n += 1 + l + sovGenerated(uint64(l)) + } + l = len(m.RequestSubResource) + n += 1 + l + sovGenerated(uint64(l)) + return n +} + +func (m *AdmissionResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.UID) + n += 1 + l + sovGenerated(uint64(l)) + n += 2 + if m.Result != nil { + l = m.Result.Size() + n += 1 + l + sovGenerated(uint64(l)) + } + if m.Patch != nil { + l = len(m.Patch) + n += 1 + l + sovGenerated(uint64(l)) + } + if m.PatchType != nil { + l = len(*m.PatchType) + n += 1 + l + sovGenerated(uint64(l)) + } + if len(m.AuditAnnotations) > 0 { + for k, v := range m.AuditAnnotations { + _ = k + _ = v + mapEntrySize := 1 + len(k) + sovGenerated(uint64(len(k))) + 1 + len(v) + sovGenerated(uint64(len(v))) + n += mapEntrySize + 1 + sovGenerated(uint64(mapEntrySize)) + } + } + if len(m.Warnings) > 0 { + for _, s := range m.Warnings { + l = len(s) + n += 1 + l + sovGenerated(uint64(l)) + } + } + return n +} + +func (m *AdmissionReview) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Request != nil { + l = m.Request.Size() + n += 1 + l + sovGenerated(uint64(l)) + } + if m.Response != nil { + l = m.Response.Size() + n += 1 + l + sovGenerated(uint64(l)) + } + return n +} + +func sovGenerated(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozGenerated(x uint64) (n int) { + return sovGenerated(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (this *AdmissionRequest) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&AdmissionRequest{`, + `UID:` + fmt.Sprintf("%v", this.UID) + `,`, + `Kind:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.Kind), "GroupVersionKind", "v1.GroupVersionKind", 1), `&`, ``, 1) + `,`, + `Resource:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.Resource), "GroupVersionResource", "v1.GroupVersionResource", 1), `&`, ``, 1) + `,`, + `SubResource:` + fmt.Sprintf("%v", this.SubResource) + `,`, + `Name:` + fmt.Sprintf("%v", this.Name) + `,`, + `Namespace:` + fmt.Sprintf("%v", this.Namespace) + `,`, + `Operation:` + fmt.Sprintf("%v", this.Operation) + `,`, + `UserInfo:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.UserInfo), "UserInfo", "v11.UserInfo", 1), `&`, ``, 1) + `,`, + `Object:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.Object), "RawExtension", "runtime.RawExtension", 1), `&`, ``, 1) + `,`, + `OldObject:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.OldObject), "RawExtension", "runtime.RawExtension", 1), `&`, ``, 1) + `,`, + `DryRun:` + valueToStringGenerated(this.DryRun) + `,`, + `Options:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.Options), "RawExtension", "runtime.RawExtension", 1), `&`, ``, 1) + `,`, + `RequestKind:` + strings.Replace(fmt.Sprintf("%v", this.RequestKind), "GroupVersionKind", "v1.GroupVersionKind", 1) + `,`, + `RequestResource:` + strings.Replace(fmt.Sprintf("%v", this.RequestResource), "GroupVersionResource", "v1.GroupVersionResource", 1) + `,`, + `RequestSubResource:` + fmt.Sprintf("%v", this.RequestSubResource) + `,`, + `}`, + }, "") + return s +} +func (this *AdmissionResponse) String() string { + if this == nil { + return "nil" + } + keysForAuditAnnotations := make([]string, 0, len(this.AuditAnnotations)) + for k := range this.AuditAnnotations { + keysForAuditAnnotations = append(keysForAuditAnnotations, k) + } + github_com_gogo_protobuf_sortkeys.Strings(keysForAuditAnnotations) + mapStringForAuditAnnotations := "map[string]string{" + for _, k := range keysForAuditAnnotations { + mapStringForAuditAnnotations += fmt.Sprintf("%v: %v,", k, this.AuditAnnotations[k]) + } + mapStringForAuditAnnotations += "}" + s := strings.Join([]string{`&AdmissionResponse{`, + `UID:` + fmt.Sprintf("%v", this.UID) + `,`, + `Allowed:` + fmt.Sprintf("%v", this.Allowed) + `,`, + `Result:` + strings.Replace(fmt.Sprintf("%v", this.Result), "Status", "v1.Status", 1) + `,`, + `Patch:` + valueToStringGenerated(this.Patch) + `,`, + `PatchType:` + valueToStringGenerated(this.PatchType) + `,`, + `AuditAnnotations:` + mapStringForAuditAnnotations + `,`, + `Warnings:` + fmt.Sprintf("%v", this.Warnings) + `,`, + `}`, + }, "") + return s +} +func (this *AdmissionReview) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&AdmissionReview{`, + `Request:` + strings.Replace(this.Request.String(), "AdmissionRequest", "AdmissionRequest", 1) + `,`, + `Response:` + strings.Replace(this.Response.String(), "AdmissionResponse", "AdmissionResponse", 1) + `,`, + `}`, + }, "") + return s +} +func valueToStringGenerated(v interface{}) string { + rv := reflect.ValueOf(v) + if rv.IsNil() { + return "nil" + } + pv := reflect.Indirect(rv).Interface() + return fmt.Sprintf("*%v", pv) +} +func (m *AdmissionRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: AdmissionRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: AdmissionRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field UID", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.UID = k8s_io_apimachinery_pkg_types.UID(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Kind", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Kind.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Resource", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Resource.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SubResource", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.SubResource = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Name = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Namespace", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Namespace = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Operation", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Operation = Operation(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field UserInfo", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.UserInfo.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 9: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Object", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Object.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 10: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field OldObject", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.OldObject.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 11: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field DryRun", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + b := bool(v != 0) + m.DryRun = &b + case 12: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Options", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Options.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 13: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RequestKind", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.RequestKind == nil { + m.RequestKind = &v1.GroupVersionKind{} + } + if err := m.RequestKind.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 14: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RequestResource", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.RequestResource == nil { + m.RequestResource = &v1.GroupVersionResource{} + } + if err := m.RequestResource.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 15: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RequestSubResource", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.RequestSubResource = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *AdmissionResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: AdmissionResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: AdmissionResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field UID", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.UID = k8s_io_apimachinery_pkg_types.UID(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Allowed", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Allowed = bool(v != 0) + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Result", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Result == nil { + m.Result = &v1.Status{} + } + if err := m.Result.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Patch", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Patch = append(m.Patch[:0], dAtA[iNdEx:postIndex]...) + if m.Patch == nil { + m.Patch = []byte{} + } + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PatchType", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + s := PatchType(dAtA[iNdEx:postIndex]) + m.PatchType = &s + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AuditAnnotations", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.AuditAnnotations == nil { + m.AuditAnnotations = make(map[string]string) + } + var mapkey string + var mapvalue string + for iNdEx < postIndex { + entryPreIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + if fieldNum == 1 { + var stringLenmapkey uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLenmapkey |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLenmapkey := int(stringLenmapkey) + if intStringLenmapkey < 0 { + return ErrInvalidLengthGenerated + } + postStringIndexmapkey := iNdEx + intStringLenmapkey + if postStringIndexmapkey < 0 { + return ErrInvalidLengthGenerated + } + if postStringIndexmapkey > l { + return io.ErrUnexpectedEOF + } + mapkey = string(dAtA[iNdEx:postStringIndexmapkey]) + iNdEx = postStringIndexmapkey + } else if fieldNum == 2 { + var stringLenmapvalue uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLenmapvalue |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLenmapvalue := int(stringLenmapvalue) + if intStringLenmapvalue < 0 { + return ErrInvalidLengthGenerated + } + postStringIndexmapvalue := iNdEx + intStringLenmapvalue + if postStringIndexmapvalue < 0 { + return ErrInvalidLengthGenerated + } + if postStringIndexmapvalue > l { + return io.ErrUnexpectedEOF + } + mapvalue = string(dAtA[iNdEx:postStringIndexmapvalue]) + iNdEx = postStringIndexmapvalue + } else { + iNdEx = entryPreIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > postIndex { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + m.AuditAnnotations[mapkey] = mapvalue + iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Warnings", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Warnings = append(m.Warnings, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *AdmissionReview) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: AdmissionReview: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: AdmissionReview: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Request", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Request == nil { + m.Request = &AdmissionRequest{} + } + if err := m.Request.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Response", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Response == nil { + m.Response = &AdmissionResponse{} + } + if err := m.Response.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipGenerated(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenerated + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenerated + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenerated + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthGenerated + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupGenerated + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthGenerated + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthGenerated = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowGenerated = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupGenerated = fmt.Errorf("proto: unexpected end of group") +) diff --git a/vendor/k8s.io/api/admission/v1beta1/generated.proto b/vendor/k8s.io/api/admission/v1beta1/generated.proto new file mode 100644 index 0000000000..ff0fa46d25 --- /dev/null +++ b/vendor/k8s.io/api/admission/v1beta1/generated.proto @@ -0,0 +1,167 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + + +// This file was autogenerated by go-to-protobuf. Do not edit it manually! + +syntax = "proto2"; + +package k8s.io.api.admission.v1beta1; + +import "k8s.io/api/authentication/v1/generated.proto"; +import "k8s.io/apimachinery/pkg/apis/meta/v1/generated.proto"; +import "k8s.io/apimachinery/pkg/runtime/generated.proto"; +import "k8s.io/apimachinery/pkg/runtime/schema/generated.proto"; + +// Package-wide variables from generator "generated". +option go_package = "k8s.io/api/admission/v1beta1"; + +// AdmissionRequest describes the admission.Attributes for the admission request. +message AdmissionRequest { + // UID is an identifier for the individual request/response. It allows us to distinguish instances of requests which are + // otherwise identical (parallel requests, requests when earlier requests did not modify etc) + // The UID is meant to track the round trip (request/response) between the KAS and the WebHook, not the user request. + // It is suitable for correlating log entries between the webhook and apiserver, for either auditing or debugging. + optional string uid = 1; + + // Kind is the fully-qualified type of object being submitted (for example, v1.Pod or autoscaling.v1.Scale) + optional k8s.io.apimachinery.pkg.apis.meta.v1.GroupVersionKind kind = 2; + + // Resource is the fully-qualified resource being requested (for example, v1.pods) + optional k8s.io.apimachinery.pkg.apis.meta.v1.GroupVersionResource resource = 3; + + // SubResource is the subresource being requested, if any (for example, "status" or "scale") + // +optional + optional string subResource = 4; + + // RequestKind is the fully-qualified type of the original API request (for example, v1.Pod or autoscaling.v1.Scale). + // If this is specified and differs from the value in "kind", an equivalent match and conversion was performed. + // + // For example, if deployments can be modified via apps/v1 and apps/v1beta1, and a webhook registered a rule of + // `apiGroups:["apps"], apiVersions:["v1"], resources: ["deployments"]` and `matchPolicy: Equivalent`, + // an API request to apps/v1beta1 deployments would be converted and sent to the webhook + // with `kind: {group:"apps", version:"v1", kind:"Deployment"}` (matching the rule the webhook registered for), + // and `requestKind: {group:"apps", version:"v1beta1", kind:"Deployment"}` (indicating the kind of the original API request). + // + // See documentation for the "matchPolicy" field in the webhook configuration type for more details. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.GroupVersionKind requestKind = 13; + + // RequestResource is the fully-qualified resource of the original API request (for example, v1.pods). + // If this is specified and differs from the value in "resource", an equivalent match and conversion was performed. + // + // For example, if deployments can be modified via apps/v1 and apps/v1beta1, and a webhook registered a rule of + // `apiGroups:["apps"], apiVersions:["v1"], resources: ["deployments"]` and `matchPolicy: Equivalent`, + // an API request to apps/v1beta1 deployments would be converted and sent to the webhook + // with `resource: {group:"apps", version:"v1", resource:"deployments"}` (matching the resource the webhook registered for), + // and `requestResource: {group:"apps", version:"v1beta1", resource:"deployments"}` (indicating the resource of the original API request). + // + // See documentation for the "matchPolicy" field in the webhook configuration type. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.GroupVersionResource requestResource = 14; + + // RequestSubResource is the name of the subresource of the original API request, if any (for example, "status" or "scale") + // If this is specified and differs from the value in "subResource", an equivalent match and conversion was performed. + // See documentation for the "matchPolicy" field in the webhook configuration type. + // +optional + optional string requestSubResource = 15; + + // Name is the name of the object as presented in the request. On a CREATE operation, the client may omit name and + // rely on the server to generate the name. If that is the case, this field will contain an empty string. + // +optional + optional string name = 5; + + // Namespace is the namespace associated with the request (if any). + // +optional + optional string namespace = 6; + + // Operation is the operation being performed. This may be different than the operation + // requested. e.g. a patch can result in either a CREATE or UPDATE Operation. + optional string operation = 7; + + // UserInfo is information about the requesting user + optional k8s.io.api.authentication.v1.UserInfo userInfo = 8; + + // Object is the object from the incoming request. + // +optional + optional k8s.io.apimachinery.pkg.runtime.RawExtension object = 9; + + // OldObject is the existing object. Only populated for DELETE and UPDATE requests. + // +optional + optional k8s.io.apimachinery.pkg.runtime.RawExtension oldObject = 10; + + // DryRun indicates that modifications will definitely not be persisted for this request. + // Defaults to false. + // +optional + optional bool dryRun = 11; + + // Options is the operation option structure of the operation being performed. + // e.g. `meta.k8s.io/v1.DeleteOptions` or `meta.k8s.io/v1.CreateOptions`. This may be + // different than the options the caller provided. e.g. for a patch request the performed + // Operation might be a CREATE, in which case the Options will a + // `meta.k8s.io/v1.CreateOptions` even though the caller provided `meta.k8s.io/v1.PatchOptions`. + // +optional + optional k8s.io.apimachinery.pkg.runtime.RawExtension options = 12; +} + +// AdmissionResponse describes an admission response. +message AdmissionResponse { + // UID is an identifier for the individual request/response. + // This should be copied over from the corresponding AdmissionRequest. + optional string uid = 1; + + // Allowed indicates whether or not the admission request was permitted. + optional bool allowed = 2; + + // Result contains extra details into why an admission request was denied. + // This field IS NOT consulted in any way if "Allowed" is "true". + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.Status status = 3; + + // The patch body. Currently we only support "JSONPatch" which implements RFC 6902. + // +optional + optional bytes patch = 4; + + // The type of Patch. Currently we only allow "JSONPatch". + // +optional + optional string patchType = 5; + + // AuditAnnotations is an unstructured key value map set by remote admission controller (e.g. error=image-blacklisted). + // MutatingAdmissionWebhook and ValidatingAdmissionWebhook admission controller will prefix the keys with + // admission webhook name (e.g. imagepolicy.example.com/error=image-blacklisted). AuditAnnotations will be provided by + // the admission webhook to add additional context to the audit log for this request. + // +optional + map auditAnnotations = 6; + + // warnings is a list of warning messages to return to the requesting API client. + // Warning messages describe a problem the client making the API request should correct or be aware of. + // Limit warnings to 120 characters if possible. + // Warnings over 256 characters and large numbers of warnings may be truncated. + // +optional + repeated string warnings = 7; +} + +// AdmissionReview describes an admission review request/response. +message AdmissionReview { + // Request describes the attributes for the admission request. + // +optional + optional AdmissionRequest request = 1; + + // Response describes the attributes for the admission response. + // +optional + optional AdmissionResponse response = 2; +} + diff --git a/vendor/k8s.io/api/admission/v1beta1/register.go b/vendor/k8s.io/api/admission/v1beta1/register.go new file mode 100644 index 0000000000..1c53e755dd --- /dev/null +++ b/vendor/k8s.io/api/admission/v1beta1/register.go @@ -0,0 +1,53 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1beta1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +// GroupName is the group name for this API. +const GroupName = "admission.k8s.io" + +// SchemeGroupVersion is group version used to register these objects +var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1beta1"} + +// Resource takes an unqualified resource and returns a Group qualified GroupResource +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} + +// TODO: move SchemeBuilder with zz_generated.deepcopy.go to k8s.io/api. +// localSchemeBuilder and AddToScheme will stay in k8s.io/kubernetes. +var ( + // SchemeBuilder points to a list of functions added to Scheme. + SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) + localSchemeBuilder = &SchemeBuilder + // AddToScheme is a common registration function for mapping packaged scoped group & version keys to a scheme. + AddToScheme = localSchemeBuilder.AddToScheme +) + +// Adds the list of known types to the given scheme. +func addKnownTypes(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(SchemeGroupVersion, + &AdmissionReview{}, + ) + metav1.AddToGroupVersion(scheme, SchemeGroupVersion) + return nil +} diff --git a/vendor/k8s.io/api/admission/v1beta1/types.go b/vendor/k8s.io/api/admission/v1beta1/types.go new file mode 100644 index 0000000000..00c619d998 --- /dev/null +++ b/vendor/k8s.io/api/admission/v1beta1/types.go @@ -0,0 +1,174 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1beta1 + +import ( + authenticationv1 "k8s.io/api/authentication/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" +) + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +k8s:prerelease-lifecycle-gen:introduced=1.9 +// +k8s:prerelease-lifecycle-gen:deprecated=1.19 +// This API is never server served. It is used for outbound requests from apiservers. This will ensure it never gets served accidentally +// and having the generator against this group will protect future APIs which may be served. +// +k8s:prerelease-lifecycle-gen:replacement=admission.k8s.io,v1,AdmissionReview + +// AdmissionReview describes an admission review request/response. +type AdmissionReview struct { + metav1.TypeMeta `json:",inline"` + // Request describes the attributes for the admission request. + // +optional + Request *AdmissionRequest `json:"request,omitempty" protobuf:"bytes,1,opt,name=request"` + // Response describes the attributes for the admission response. + // +optional + Response *AdmissionResponse `json:"response,omitempty" protobuf:"bytes,2,opt,name=response"` +} + +// AdmissionRequest describes the admission.Attributes for the admission request. +type AdmissionRequest struct { + // UID is an identifier for the individual request/response. It allows us to distinguish instances of requests which are + // otherwise identical (parallel requests, requests when earlier requests did not modify etc) + // The UID is meant to track the round trip (request/response) between the KAS and the WebHook, not the user request. + // It is suitable for correlating log entries between the webhook and apiserver, for either auditing or debugging. + UID types.UID `json:"uid" protobuf:"bytes,1,opt,name=uid"` + // Kind is the fully-qualified type of object being submitted (for example, v1.Pod or autoscaling.v1.Scale) + Kind metav1.GroupVersionKind `json:"kind" protobuf:"bytes,2,opt,name=kind"` + // Resource is the fully-qualified resource being requested (for example, v1.pods) + Resource metav1.GroupVersionResource `json:"resource" protobuf:"bytes,3,opt,name=resource"` + // SubResource is the subresource being requested, if any (for example, "status" or "scale") + // +optional + SubResource string `json:"subResource,omitempty" protobuf:"bytes,4,opt,name=subResource"` + + // RequestKind is the fully-qualified type of the original API request (for example, v1.Pod or autoscaling.v1.Scale). + // If this is specified and differs from the value in "kind", an equivalent match and conversion was performed. + // + // For example, if deployments can be modified via apps/v1 and apps/v1beta1, and a webhook registered a rule of + // `apiGroups:["apps"], apiVersions:["v1"], resources: ["deployments"]` and `matchPolicy: Equivalent`, + // an API request to apps/v1beta1 deployments would be converted and sent to the webhook + // with `kind: {group:"apps", version:"v1", kind:"Deployment"}` (matching the rule the webhook registered for), + // and `requestKind: {group:"apps", version:"v1beta1", kind:"Deployment"}` (indicating the kind of the original API request). + // + // See documentation for the "matchPolicy" field in the webhook configuration type for more details. + // +optional + RequestKind *metav1.GroupVersionKind `json:"requestKind,omitempty" protobuf:"bytes,13,opt,name=requestKind"` + // RequestResource is the fully-qualified resource of the original API request (for example, v1.pods). + // If this is specified and differs from the value in "resource", an equivalent match and conversion was performed. + // + // For example, if deployments can be modified via apps/v1 and apps/v1beta1, and a webhook registered a rule of + // `apiGroups:["apps"], apiVersions:["v1"], resources: ["deployments"]` and `matchPolicy: Equivalent`, + // an API request to apps/v1beta1 deployments would be converted and sent to the webhook + // with `resource: {group:"apps", version:"v1", resource:"deployments"}` (matching the resource the webhook registered for), + // and `requestResource: {group:"apps", version:"v1beta1", resource:"deployments"}` (indicating the resource of the original API request). + // + // See documentation for the "matchPolicy" field in the webhook configuration type. + // +optional + RequestResource *metav1.GroupVersionResource `json:"requestResource,omitempty" protobuf:"bytes,14,opt,name=requestResource"` + // RequestSubResource is the name of the subresource of the original API request, if any (for example, "status" or "scale") + // If this is specified and differs from the value in "subResource", an equivalent match and conversion was performed. + // See documentation for the "matchPolicy" field in the webhook configuration type. + // +optional + RequestSubResource string `json:"requestSubResource,omitempty" protobuf:"bytes,15,opt,name=requestSubResource"` + + // Name is the name of the object as presented in the request. On a CREATE operation, the client may omit name and + // rely on the server to generate the name. If that is the case, this field will contain an empty string. + // +optional + Name string `json:"name,omitempty" protobuf:"bytes,5,opt,name=name"` + // Namespace is the namespace associated with the request (if any). + // +optional + Namespace string `json:"namespace,omitempty" protobuf:"bytes,6,opt,name=namespace"` + // Operation is the operation being performed. This may be different than the operation + // requested. e.g. a patch can result in either a CREATE or UPDATE Operation. + Operation Operation `json:"operation" protobuf:"bytes,7,opt,name=operation"` + // UserInfo is information about the requesting user + UserInfo authenticationv1.UserInfo `json:"userInfo" protobuf:"bytes,8,opt,name=userInfo"` + // Object is the object from the incoming request. + // +optional + Object runtime.RawExtension `json:"object,omitempty" protobuf:"bytes,9,opt,name=object"` + // OldObject is the existing object. Only populated for DELETE and UPDATE requests. + // +optional + OldObject runtime.RawExtension `json:"oldObject,omitempty" protobuf:"bytes,10,opt,name=oldObject"` + // DryRun indicates that modifications will definitely not be persisted for this request. + // Defaults to false. + // +optional + DryRun *bool `json:"dryRun,omitempty" protobuf:"varint,11,opt,name=dryRun"` + // Options is the operation option structure of the operation being performed. + // e.g. `meta.k8s.io/v1.DeleteOptions` or `meta.k8s.io/v1.CreateOptions`. This may be + // different than the options the caller provided. e.g. for a patch request the performed + // Operation might be a CREATE, in which case the Options will a + // `meta.k8s.io/v1.CreateOptions` even though the caller provided `meta.k8s.io/v1.PatchOptions`. + // +optional + Options runtime.RawExtension `json:"options,omitempty" protobuf:"bytes,12,opt,name=options"` +} + +// AdmissionResponse describes an admission response. +type AdmissionResponse struct { + // UID is an identifier for the individual request/response. + // This should be copied over from the corresponding AdmissionRequest. + UID types.UID `json:"uid" protobuf:"bytes,1,opt,name=uid"` + + // Allowed indicates whether or not the admission request was permitted. + Allowed bool `json:"allowed" protobuf:"varint,2,opt,name=allowed"` + + // Result contains extra details into why an admission request was denied. + // This field IS NOT consulted in any way if "Allowed" is "true". + // +optional + Result *metav1.Status `json:"status,omitempty" protobuf:"bytes,3,opt,name=status"` + + // The patch body. Currently we only support "JSONPatch" which implements RFC 6902. + // +optional + Patch []byte `json:"patch,omitempty" protobuf:"bytes,4,opt,name=patch"` + + // The type of Patch. Currently we only allow "JSONPatch". + // +optional + PatchType *PatchType `json:"patchType,omitempty" protobuf:"bytes,5,opt,name=patchType"` + + // AuditAnnotations is an unstructured key value map set by remote admission controller (e.g. error=image-blacklisted). + // MutatingAdmissionWebhook and ValidatingAdmissionWebhook admission controller will prefix the keys with + // admission webhook name (e.g. imagepolicy.example.com/error=image-blacklisted). AuditAnnotations will be provided by + // the admission webhook to add additional context to the audit log for this request. + // +optional + AuditAnnotations map[string]string `json:"auditAnnotations,omitempty" protobuf:"bytes,6,opt,name=auditAnnotations"` + + // warnings is a list of warning messages to return to the requesting API client. + // Warning messages describe a problem the client making the API request should correct or be aware of. + // Limit warnings to 120 characters if possible. + // Warnings over 256 characters and large numbers of warnings may be truncated. + // +optional + Warnings []string `json:"warnings,omitempty" protobuf:"bytes,7,rep,name=warnings"` +} + +// PatchType is the type of patch being used to represent the mutated object +type PatchType string + +// PatchType constants. +const ( + PatchTypeJSONPatch PatchType = "JSONPatch" +) + +// Operation is the type of resource operation being checked for admission control +type Operation string + +// Operation constants +const ( + Create Operation = "CREATE" + Update Operation = "UPDATE" + Delete Operation = "DELETE" + Connect Operation = "CONNECT" +) diff --git a/vendor/k8s.io/api/admission/v1beta1/types_swagger_doc_generated.go b/vendor/k8s.io/api/admission/v1beta1/types_swagger_doc_generated.go new file mode 100644 index 0000000000..13067ad80d --- /dev/null +++ b/vendor/k8s.io/api/admission/v1beta1/types_swagger_doc_generated.go @@ -0,0 +1,78 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1beta1 + +// This file contains a collection of methods that can be used from go-restful to +// generate Swagger API documentation for its models. Please read this PR for more +// information on the implementation: https://github.com/emicklei/go-restful/pull/215 +// +// TODOs are ignored from the parser (e.g. TODO(andronat):... || TODO:...) if and only if +// they are on one line! For multiple line or blocks that you want to ignore use ---. +// Any context after a --- is ignored. +// +// Those methods can be generated by using hack/update-generated-swagger-docs.sh + +// AUTO-GENERATED FUNCTIONS START HERE. DO NOT EDIT. +var map_AdmissionRequest = map[string]string{ + "": "AdmissionRequest describes the admission.Attributes for the admission request.", + "uid": "UID is an identifier for the individual request/response. It allows us to distinguish instances of requests which are otherwise identical (parallel requests, requests when earlier requests did not modify etc) The UID is meant to track the round trip (request/response) between the KAS and the WebHook, not the user request. It is suitable for correlating log entries between the webhook and apiserver, for either auditing or debugging.", + "kind": "Kind is the fully-qualified type of object being submitted (for example, v1.Pod or autoscaling.v1.Scale)", + "resource": "Resource is the fully-qualified resource being requested (for example, v1.pods)", + "subResource": "SubResource is the subresource being requested, if any (for example, \"status\" or \"scale\")", + "requestKind": "RequestKind is the fully-qualified type of the original API request (for example, v1.Pod or autoscaling.v1.Scale). If this is specified and differs from the value in \"kind\", an equivalent match and conversion was performed.\n\nFor example, if deployments can be modified via apps/v1 and apps/v1beta1, and a webhook registered a rule of `apiGroups:[\"apps\"], apiVersions:[\"v1\"], resources: [\"deployments\"]` and `matchPolicy: Equivalent`, an API request to apps/v1beta1 deployments would be converted and sent to the webhook with `kind: {group:\"apps\", version:\"v1\", kind:\"Deployment\"}` (matching the rule the webhook registered for), and `requestKind: {group:\"apps\", version:\"v1beta1\", kind:\"Deployment\"}` (indicating the kind of the original API request).\n\nSee documentation for the \"matchPolicy\" field in the webhook configuration type for more details.", + "requestResource": "RequestResource is the fully-qualified resource of the original API request (for example, v1.pods). If this is specified and differs from the value in \"resource\", an equivalent match and conversion was performed.\n\nFor example, if deployments can be modified via apps/v1 and apps/v1beta1, and a webhook registered a rule of `apiGroups:[\"apps\"], apiVersions:[\"v1\"], resources: [\"deployments\"]` and `matchPolicy: Equivalent`, an API request to apps/v1beta1 deployments would be converted and sent to the webhook with `resource: {group:\"apps\", version:\"v1\", resource:\"deployments\"}` (matching the resource the webhook registered for), and `requestResource: {group:\"apps\", version:\"v1beta1\", resource:\"deployments\"}` (indicating the resource of the original API request).\n\nSee documentation for the \"matchPolicy\" field in the webhook configuration type.", + "requestSubResource": "RequestSubResource is the name of the subresource of the original API request, if any (for example, \"status\" or \"scale\") If this is specified and differs from the value in \"subResource\", an equivalent match and conversion was performed. See documentation for the \"matchPolicy\" field in the webhook configuration type.", + "name": "Name is the name of the object as presented in the request. On a CREATE operation, the client may omit name and rely on the server to generate the name. If that is the case, this field will contain an empty string.", + "namespace": "Namespace is the namespace associated with the request (if any).", + "operation": "Operation is the operation being performed. This may be different than the operation requested. e.g. a patch can result in either a CREATE or UPDATE Operation.", + "userInfo": "UserInfo is information about the requesting user", + "object": "Object is the object from the incoming request.", + "oldObject": "OldObject is the existing object. Only populated for DELETE and UPDATE requests.", + "dryRun": "DryRun indicates that modifications will definitely not be persisted for this request. Defaults to false.", + "options": "Options is the operation option structure of the operation being performed. e.g. `meta.k8s.io/v1.DeleteOptions` or `meta.k8s.io/v1.CreateOptions`. This may be different than the options the caller provided. e.g. for a patch request the performed Operation might be a CREATE, in which case the Options will a `meta.k8s.io/v1.CreateOptions` even though the caller provided `meta.k8s.io/v1.PatchOptions`.", +} + +func (AdmissionRequest) SwaggerDoc() map[string]string { + return map_AdmissionRequest +} + +var map_AdmissionResponse = map[string]string{ + "": "AdmissionResponse describes an admission response.", + "uid": "UID is an identifier for the individual request/response. This should be copied over from the corresponding AdmissionRequest.", + "allowed": "Allowed indicates whether or not the admission request was permitted.", + "status": "Result contains extra details into why an admission request was denied. This field IS NOT consulted in any way if \"Allowed\" is \"true\".", + "patch": "The patch body. Currently we only support \"JSONPatch\" which implements RFC 6902.", + "patchType": "The type of Patch. Currently we only allow \"JSONPatch\".", + "auditAnnotations": "AuditAnnotations is an unstructured key value map set by remote admission controller (e.g. error=image-blacklisted). MutatingAdmissionWebhook and ValidatingAdmissionWebhook admission controller will prefix the keys with admission webhook name (e.g. imagepolicy.example.com/error=image-blacklisted). AuditAnnotations will be provided by the admission webhook to add additional context to the audit log for this request.", + "warnings": "warnings is a list of warning messages to return to the requesting API client. Warning messages describe a problem the client making the API request should correct or be aware of. Limit warnings to 120 characters if possible. Warnings over 256 characters and large numbers of warnings may be truncated.", +} + +func (AdmissionResponse) SwaggerDoc() map[string]string { + return map_AdmissionResponse +} + +var map_AdmissionReview = map[string]string{ + "": "AdmissionReview describes an admission review request/response.", + "request": "Request describes the attributes for the admission request.", + "response": "Response describes the attributes for the admission response.", +} + +func (AdmissionReview) SwaggerDoc() map[string]string { + return map_AdmissionReview +} + +// AUTO-GENERATED FUNCTIONS END HERE diff --git a/vendor/k8s.io/api/admission/v1beta1/zz_generated.deepcopy.go b/vendor/k8s.io/api/admission/v1beta1/zz_generated.deepcopy.go new file mode 100644 index 0000000000..8234b322f9 --- /dev/null +++ b/vendor/k8s.io/api/admission/v1beta1/zz_generated.deepcopy.go @@ -0,0 +1,142 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package v1beta1 + +import ( + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AdmissionRequest) DeepCopyInto(out *AdmissionRequest) { + *out = *in + out.Kind = in.Kind + out.Resource = in.Resource + if in.RequestKind != nil { + in, out := &in.RequestKind, &out.RequestKind + *out = new(v1.GroupVersionKind) + **out = **in + } + if in.RequestResource != nil { + in, out := &in.RequestResource, &out.RequestResource + *out = new(v1.GroupVersionResource) + **out = **in + } + in.UserInfo.DeepCopyInto(&out.UserInfo) + in.Object.DeepCopyInto(&out.Object) + in.OldObject.DeepCopyInto(&out.OldObject) + if in.DryRun != nil { + in, out := &in.DryRun, &out.DryRun + *out = new(bool) + **out = **in + } + in.Options.DeepCopyInto(&out.Options) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AdmissionRequest. +func (in *AdmissionRequest) DeepCopy() *AdmissionRequest { + if in == nil { + return nil + } + out := new(AdmissionRequest) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AdmissionResponse) DeepCopyInto(out *AdmissionResponse) { + *out = *in + if in.Result != nil { + in, out := &in.Result, &out.Result + *out = new(v1.Status) + (*in).DeepCopyInto(*out) + } + if in.Patch != nil { + in, out := &in.Patch, &out.Patch + *out = make([]byte, len(*in)) + copy(*out, *in) + } + if in.PatchType != nil { + in, out := &in.PatchType, &out.PatchType + *out = new(PatchType) + **out = **in + } + if in.AuditAnnotations != nil { + in, out := &in.AuditAnnotations, &out.AuditAnnotations + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.Warnings != nil { + in, out := &in.Warnings, &out.Warnings + *out = make([]string, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AdmissionResponse. +func (in *AdmissionResponse) DeepCopy() *AdmissionResponse { + if in == nil { + return nil + } + out := new(AdmissionResponse) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AdmissionReview) DeepCopyInto(out *AdmissionReview) { + *out = *in + out.TypeMeta = in.TypeMeta + if in.Request != nil { + in, out := &in.Request, &out.Request + *out = new(AdmissionRequest) + (*in).DeepCopyInto(*out) + } + if in.Response != nil { + in, out := &in.Response, &out.Response + *out = new(AdmissionResponse) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AdmissionReview. +func (in *AdmissionReview) DeepCopy() *AdmissionReview { + if in == nil { + return nil + } + out := new(AdmissionReview) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *AdmissionReview) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} diff --git a/vendor/k8s.io/api/admission/v1beta1/zz_generated.prerelease-lifecycle.go b/vendor/k8s.io/api/admission/v1beta1/zz_generated.prerelease-lifecycle.go new file mode 100644 index 0000000000..f96e8a4433 --- /dev/null +++ b/vendor/k8s.io/api/admission/v1beta1/zz_generated.prerelease-lifecycle.go @@ -0,0 +1,50 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by prerelease-lifecycle-gen. DO NOT EDIT. + +package v1beta1 + +import ( + schema "k8s.io/apimachinery/pkg/runtime/schema" +) + +// APILifecycleIntroduced is an autogenerated function, returning the release in which the API struct was introduced as int versions of major and minor for comparison. +// It is controlled by "k8s:prerelease-lifecycle-gen:introduced" tags in types.go. +func (in *AdmissionReview) APILifecycleIntroduced() (major, minor int) { + return 1, 9 +} + +// APILifecycleDeprecated is an autogenerated function, returning the release in which the API struct was or will be deprecated as int versions of major and minor for comparison. +// It is controlled by "k8s:prerelease-lifecycle-gen:deprecated" tags in types.go or "k8s:prerelease-lifecycle-gen:introduced" plus three minor. +func (in *AdmissionReview) APILifecycleDeprecated() (major, minor int) { + return 1, 19 +} + +// APILifecycleReplacement is an autogenerated function, returning the group, version, and kind that should be used instead of this deprecated type. +// It is controlled by "k8s:prerelease-lifecycle-gen:replacement=,," tags in types.go. +func (in *AdmissionReview) APILifecycleReplacement() schema.GroupVersionKind { + return schema.GroupVersionKind{Group: "admission.k8s.io", Version: "v1", Kind: "AdmissionReview"} +} + +// APILifecycleRemoved is an autogenerated function, returning the release in which the API is no longer served as int versions of major and minor for comparison. +// It is controlled by "k8s:prerelease-lifecycle-gen:removed" tags in types.go or "k8s:prerelease-lifecycle-gen:deprecated" plus three minor. +func (in *AdmissionReview) APILifecycleRemoved() (major, minor int) { + return 1, 22 +} diff --git a/vendor/k8s.io/apimachinery/pkg/apis/meta/internalversion/scheme/doc.go b/vendor/k8s.io/apimachinery/pkg/apis/meta/internalversion/scheme/doc.go new file mode 100644 index 0000000000..a45fa2a8a5 --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/apis/meta/internalversion/scheme/doc.go @@ -0,0 +1,17 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package scheme // import "k8s.io/apimachinery/pkg/apis/meta/internalversion/scheme" diff --git a/vendor/k8s.io/apimachinery/pkg/apis/meta/internalversion/scheme/register.go b/vendor/k8s.io/apimachinery/pkg/apis/meta/internalversion/scheme/register.go new file mode 100644 index 0000000000..472a9aeb23 --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/apis/meta/internalversion/scheme/register.go @@ -0,0 +1,39 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package scheme + +import ( + "k8s.io/apimachinery/pkg/apis/meta/internalversion" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/serializer" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" +) + +// Scheme is the registry for any type that adheres to the meta API spec. +var scheme = runtime.NewScheme() + +// Codecs provides access to encoding and decoding for the scheme. +var Codecs = serializer.NewCodecFactory(scheme) + +// ParameterCodec handles versioning of objects that are converted to query parameters. +var ParameterCodec = runtime.NewParameterCodec(scheme) + +// Unlike other API groups, meta internal knows about all meta external versions, but keeps +// the logic for conversion private. +func init() { + utilruntime.Must(internalversion.AddToScheme(scheme)) +} diff --git a/vendor/k8s.io/client-go/metadata/interface.go b/vendor/k8s.io/client-go/metadata/interface.go new file mode 100644 index 0000000000..127c39501a --- /dev/null +++ b/vendor/k8s.io/client-go/metadata/interface.go @@ -0,0 +1,49 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package metadata + +import ( + "context" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/watch" +) + +// Interface allows a caller to get the metadata (in the form of PartialObjectMetadata objects) +// from any Kubernetes compatible resource API. +type Interface interface { + Resource(resource schema.GroupVersionResource) Getter +} + +// ResourceInterface contains the set of methods that may be invoked on objects by their metadata. +// Update is not supported by the server, but Patch can be used for the actions Update would handle. +type ResourceInterface interface { + Delete(ctx context.Context, name string, options metav1.DeleteOptions, subresources ...string) error + DeleteCollection(ctx context.Context, options metav1.DeleteOptions, listOptions metav1.ListOptions) error + Get(ctx context.Context, name string, options metav1.GetOptions, subresources ...string) (*metav1.PartialObjectMetadata, error) + List(ctx context.Context, opts metav1.ListOptions) (*metav1.PartialObjectMetadataList, error) + Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) + Patch(ctx context.Context, name string, pt types.PatchType, data []byte, options metav1.PatchOptions, subresources ...string) (*metav1.PartialObjectMetadata, error) +} + +// Getter handles both namespaced and non-namespaced resource types consistently. +type Getter interface { + Namespace(string) ResourceInterface + ResourceInterface +} diff --git a/vendor/k8s.io/client-go/metadata/metadata.go b/vendor/k8s.io/client-go/metadata/metadata.go new file mode 100644 index 0000000000..8152aa1248 --- /dev/null +++ b/vendor/k8s.io/client-go/metadata/metadata.go @@ -0,0 +1,331 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package metadata + +import ( + "context" + "encoding/json" + "fmt" + "net/http" + "time" + + "k8s.io/klog/v2" + + metainternalversionscheme "k8s.io/apimachinery/pkg/apis/meta/internalversion/scheme" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/runtime/serializer" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/watch" + "k8s.io/client-go/rest" +) + +var deleteScheme = runtime.NewScheme() +var parameterScheme = runtime.NewScheme() +var deleteOptionsCodec = serializer.NewCodecFactory(deleteScheme) +var dynamicParameterCodec = runtime.NewParameterCodec(parameterScheme) + +var versionV1 = schema.GroupVersion{Version: "v1"} + +func init() { + metav1.AddToGroupVersion(parameterScheme, versionV1) + metav1.AddToGroupVersion(deleteScheme, versionV1) +} + +// Client allows callers to retrieve the object metadata for any +// Kubernetes-compatible API endpoint. The client uses the +// meta.k8s.io/v1 PartialObjectMetadata resource to more efficiently +// retrieve just the necessary metadata, but on older servers +// (Kubernetes 1.14 and before) will retrieve the object and then +// convert the metadata. +type Client struct { + client *rest.RESTClient +} + +var _ Interface = &Client{} + +// ConfigFor returns a copy of the provided config with the +// appropriate metadata client defaults set. +func ConfigFor(inConfig *rest.Config) *rest.Config { + config := rest.CopyConfig(inConfig) + config.AcceptContentTypes = "application/vnd.kubernetes.protobuf,application/json" + config.ContentType = "application/vnd.kubernetes.protobuf" + config.NegotiatedSerializer = metainternalversionscheme.Codecs.WithoutConversion() + if config.UserAgent == "" { + config.UserAgent = rest.DefaultKubernetesUserAgent() + } + return config +} + +// NewForConfigOrDie creates a new metadata client for the given config and +// panics if there is an error in the config. +func NewForConfigOrDie(c *rest.Config) Interface { + ret, err := NewForConfig(c) + if err != nil { + panic(err) + } + return ret +} + +// NewForConfig creates a new metadata client that can retrieve object +// metadata details about any Kubernetes object (core, aggregated, or custom +// resource based) in the form of PartialObjectMetadata objects, or returns +// an error. +// NewForConfig is equivalent to NewForConfigAndClient(c, httpClient), +// where httpClient was generated with rest.HTTPClientFor(c). +func NewForConfig(inConfig *rest.Config) (Interface, error) { + config := ConfigFor(inConfig) + + httpClient, err := rest.HTTPClientFor(config) + if err != nil { + return nil, err + } + return NewForConfigAndClient(config, httpClient) +} + +// NewForConfigAndClient creates a new metadata client for the given config and http client. +// Note the http client provided takes precedence over the configured transport values. +func NewForConfigAndClient(inConfig *rest.Config, h *http.Client) (Interface, error) { + config := ConfigFor(inConfig) + // for serializing the options + config.GroupVersion = &schema.GroupVersion{} + config.APIPath = "/this-value-should-never-be-sent" + + restClient, err := rest.RESTClientForConfigAndClient(config, h) + if err != nil { + return nil, err + } + + return &Client{client: restClient}, nil +} + +type client struct { + client *Client + namespace string + resource schema.GroupVersionResource +} + +// Resource returns an interface that can access cluster or namespace +// scoped instances of resource. +func (c *Client) Resource(resource schema.GroupVersionResource) Getter { + return &client{client: c, resource: resource} +} + +// Namespace returns an interface that can access namespace-scoped instances of the +// provided resource. +func (c *client) Namespace(ns string) ResourceInterface { + ret := *c + ret.namespace = ns + return &ret +} + +// Delete removes the provided resource from the server. +func (c *client) Delete(ctx context.Context, name string, opts metav1.DeleteOptions, subresources ...string) error { + if len(name) == 0 { + return fmt.Errorf("name is required") + } + // if DeleteOptions are delivered to Negotiator for serialization, + // HTTP-Request header will bring "Content-Type: application/vnd.kubernetes.protobuf" + // apiextensions-apiserver uses unstructuredNegotiatedSerializer to decode the input, + // server-side will reply with 406 errors. + // The special treatment here is to be compatible with CRD Handler + // see: https://github.com/kubernetes/kubernetes/blob/1a845ccd076bbf1b03420fe694c85a5cd3bd6bed/staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/customresource_handler.go#L843 + deleteOptionsByte, err := runtime.Encode(deleteOptionsCodec.LegacyCodec(schema.GroupVersion{Version: "v1"}), &opts) + if err != nil { + return err + } + + result := c.client.client. + Delete(). + AbsPath(append(c.makeURLSegments(name), subresources...)...). + SetHeader("Content-Type", runtime.ContentTypeJSON). + Body(deleteOptionsByte). + Do(ctx) + return result.Error() +} + +// DeleteCollection triggers deletion of all resources in the specified scope (namespace or cluster). +func (c *client) DeleteCollection(ctx context.Context, opts metav1.DeleteOptions, listOptions metav1.ListOptions) error { + // See comment on Delete + deleteOptionsByte, err := runtime.Encode(deleteOptionsCodec.LegacyCodec(schema.GroupVersion{Version: "v1"}), &opts) + if err != nil { + return err + } + + result := c.client.client. + Delete(). + AbsPath(c.makeURLSegments("")...). + SetHeader("Content-Type", runtime.ContentTypeJSON). + Body(deleteOptionsByte). + SpecificallyVersionedParams(&listOptions, dynamicParameterCodec, versionV1). + Do(ctx) + return result.Error() +} + +// Get returns the resource with name from the specified scope (namespace or cluster). +func (c *client) Get(ctx context.Context, name string, opts metav1.GetOptions, subresources ...string) (*metav1.PartialObjectMetadata, error) { + if len(name) == 0 { + return nil, fmt.Errorf("name is required") + } + result := c.client.client.Get().AbsPath(append(c.makeURLSegments(name), subresources...)...). + SetHeader("Accept", "application/vnd.kubernetes.protobuf;as=PartialObjectMetadata;g=meta.k8s.io;v=v1,application/json;as=PartialObjectMetadata;g=meta.k8s.io;v=v1,application/json"). + SpecificallyVersionedParams(&opts, dynamicParameterCodec, versionV1). + Do(ctx) + if err := result.Error(); err != nil { + return nil, err + } + obj, err := result.Get() + if runtime.IsNotRegisteredError(err) { + klog.V(5).Infof("Unable to retrieve PartialObjectMetadata: %#v", err) + rawBytes, err := result.Raw() + if err != nil { + return nil, err + } + var partial metav1.PartialObjectMetadata + if err := json.Unmarshal(rawBytes, &partial); err != nil { + return nil, fmt.Errorf("unable to decode returned object as PartialObjectMetadata: %v", err) + } + if !isLikelyObjectMetadata(&partial) { + return nil, fmt.Errorf("object does not appear to match the ObjectMeta schema: %#v", partial) + } + partial.TypeMeta = metav1.TypeMeta{} + return &partial, nil + } + if err != nil { + return nil, err + } + partial, ok := obj.(*metav1.PartialObjectMetadata) + if !ok { + return nil, fmt.Errorf("unexpected object, expected PartialObjectMetadata but got %T", obj) + } + return partial, nil +} + +// List returns all resources within the specified scope (namespace or cluster). +func (c *client) List(ctx context.Context, opts metav1.ListOptions) (*metav1.PartialObjectMetadataList, error) { + result := c.client.client.Get().AbsPath(c.makeURLSegments("")...). + SetHeader("Accept", "application/vnd.kubernetes.protobuf;as=PartialObjectMetadataList;g=meta.k8s.io;v=v1,application/json;as=PartialObjectMetadataList;g=meta.k8s.io;v=v1,application/json"). + SpecificallyVersionedParams(&opts, dynamicParameterCodec, versionV1). + Do(ctx) + if err := result.Error(); err != nil { + return nil, err + } + obj, err := result.Get() + if runtime.IsNotRegisteredError(err) { + klog.V(5).Infof("Unable to retrieve PartialObjectMetadataList: %#v", err) + rawBytes, err := result.Raw() + if err != nil { + return nil, err + } + var partial metav1.PartialObjectMetadataList + if err := json.Unmarshal(rawBytes, &partial); err != nil { + return nil, fmt.Errorf("unable to decode returned object as PartialObjectMetadataList: %v", err) + } + partial.TypeMeta = metav1.TypeMeta{} + return &partial, nil + } + if err != nil { + return nil, err + } + partial, ok := obj.(*metav1.PartialObjectMetadataList) + if !ok { + return nil, fmt.Errorf("unexpected object, expected PartialObjectMetadata but got %T", obj) + } + return partial, nil +} + +// Watch finds all changes to the resources in the specified scope (namespace or cluster). +func (c *client) Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + opts.Watch = true + return c.client.client.Get(). + AbsPath(c.makeURLSegments("")...). + SetHeader("Accept", "application/vnd.kubernetes.protobuf;as=PartialObjectMetadata;g=meta.k8s.io;v=v1,application/json;as=PartialObjectMetadata;g=meta.k8s.io;v=v1,application/json"). + SpecificallyVersionedParams(&opts, dynamicParameterCodec, versionV1). + Timeout(timeout). + Watch(ctx) +} + +// Patch modifies the named resource in the specified scope (namespace or cluster). +func (c *client) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (*metav1.PartialObjectMetadata, error) { + if len(name) == 0 { + return nil, fmt.Errorf("name is required") + } + result := c.client.client. + Patch(pt). + AbsPath(append(c.makeURLSegments(name), subresources...)...). + Body(data). + SetHeader("Accept", "application/vnd.kubernetes.protobuf;as=PartialObjectMetadata;g=meta.k8s.io;v=v1,application/json;as=PartialObjectMetadata;g=meta.k8s.io;v=v1,application/json"). + SpecificallyVersionedParams(&opts, dynamicParameterCodec, versionV1). + Do(ctx) + if err := result.Error(); err != nil { + return nil, err + } + obj, err := result.Get() + if runtime.IsNotRegisteredError(err) { + rawBytes, err := result.Raw() + if err != nil { + return nil, err + } + var partial metav1.PartialObjectMetadata + if err := json.Unmarshal(rawBytes, &partial); err != nil { + return nil, fmt.Errorf("unable to decode returned object as PartialObjectMetadata: %v", err) + } + if !isLikelyObjectMetadata(&partial) { + return nil, fmt.Errorf("object does not appear to match the ObjectMeta schema") + } + partial.TypeMeta = metav1.TypeMeta{} + return &partial, nil + } + if err != nil { + return nil, err + } + partial, ok := obj.(*metav1.PartialObjectMetadata) + if !ok { + return nil, fmt.Errorf("unexpected object, expected PartialObjectMetadata but got %T", obj) + } + return partial, nil +} + +func (c *client) makeURLSegments(name string) []string { + url := []string{} + if len(c.resource.Group) == 0 { + url = append(url, "api") + } else { + url = append(url, "apis", c.resource.Group) + } + url = append(url, c.resource.Version) + + if len(c.namespace) > 0 { + url = append(url, "namespaces", c.namespace) + } + url = append(url, c.resource.Resource) + + if len(name) > 0 { + url = append(url, name) + } + + return url +} + +func isLikelyObjectMetadata(meta *metav1.PartialObjectMetadata) bool { + return len(meta.UID) > 0 || !meta.CreationTimestamp.IsZero() || len(meta.Name) > 0 || len(meta.GenerateName) > 0 +} diff --git a/vendor/k8s.io/component-base/LICENSE b/vendor/k8s.io/component-base/LICENSE new file mode 100644 index 0000000000..d645695673 --- /dev/null +++ b/vendor/k8s.io/component-base/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/k8s.io/component-base/config/doc.go b/vendor/k8s.io/component-base/config/doc.go new file mode 100644 index 0000000000..dd0a5a53a7 --- /dev/null +++ b/vendor/k8s.io/component-base/config/doc.go @@ -0,0 +1,19 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// +k8s:deepcopy-gen=package + +package config // import "k8s.io/component-base/config" diff --git a/vendor/k8s.io/component-base/config/types.go b/vendor/k8s.io/component-base/config/types.go new file mode 100644 index 0000000000..e1b9469d76 --- /dev/null +++ b/vendor/k8s.io/component-base/config/types.go @@ -0,0 +1,80 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package config + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// ClientConnectionConfiguration contains details for constructing a client. +type ClientConnectionConfiguration struct { + // kubeconfig is the path to a KubeConfig file. + Kubeconfig string + // acceptContentTypes defines the Accept header sent by clients when connecting to a server, overriding the + // default value of 'application/json'. This field will control all connections to the server used by a particular + // client. + AcceptContentTypes string + // contentType is the content type used when sending data to the server from this client. + ContentType string + // qps controls the number of queries per second allowed for this connection. + QPS float32 + // burst allows extra queries to accumulate when a client is exceeding its rate. + Burst int32 +} + +// LeaderElectionConfiguration defines the configuration of leader election +// clients for components that can run with leader election enabled. +type LeaderElectionConfiguration struct { + // leaderElect enables a leader election client to gain leadership + // before executing the main loop. Enable this when running replicated + // components for high availability. + LeaderElect bool + // leaseDuration is the duration that non-leader candidates will wait + // after observing a leadership renewal until attempting to acquire + // leadership of a led but unrenewed leader slot. This is effectively the + // maximum duration that a leader can be stopped before it is replaced + // by another candidate. This is only applicable if leader election is + // enabled. + LeaseDuration metav1.Duration + // renewDeadline is the interval between attempts by the acting master to + // renew a leadership slot before it stops leading. This must be less + // than or equal to the lease duration. This is only applicable if leader + // election is enabled. + RenewDeadline metav1.Duration + // retryPeriod is the duration the clients should wait between attempting + // acquisition and renewal of a leadership. This is only applicable if + // leader election is enabled. + RetryPeriod metav1.Duration + // resourceLock indicates the resource object type that will be used to lock + // during leader election cycles. + ResourceLock string + // resourceName indicates the name of resource object that will be used to lock + // during leader election cycles. + ResourceName string + // resourceNamespace indicates the namespace of resource object that will be used to lock + // during leader election cycles. + ResourceNamespace string +} + +// DebuggingConfiguration holds configuration for Debugging related features. +type DebuggingConfiguration struct { + // enableProfiling enables profiling via web interface host:port/debug/pprof/ + EnableProfiling bool + // enableContentionProfiling enables block profiling, if + // enableProfiling is true. + EnableContentionProfiling bool +} diff --git a/vendor/k8s.io/component-base/config/v1alpha1/conversion.go b/vendor/k8s.io/component-base/config/v1alpha1/conversion.go new file mode 100644 index 0000000000..e2951e310d --- /dev/null +++ b/vendor/k8s.io/component-base/config/v1alpha1/conversion.go @@ -0,0 +1,53 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + "k8s.io/apimachinery/pkg/conversion" + "k8s.io/component-base/config" +) + +// Important! The public back-and-forth conversion functions for the types in this generic +// package with ComponentConfig types need to be manually exposed like this in order for +// other packages that reference this package to be able to call these conversion functions +// in an autogenerated manner. +// TODO: Fix the bug in conversion-gen so it automatically discovers these Convert_* functions +// in autogenerated code as well. + +func Convert_v1alpha1_ClientConnectionConfiguration_To_config_ClientConnectionConfiguration(in *ClientConnectionConfiguration, out *config.ClientConnectionConfiguration, s conversion.Scope) error { + return autoConvert_v1alpha1_ClientConnectionConfiguration_To_config_ClientConnectionConfiguration(in, out, s) +} + +func Convert_config_ClientConnectionConfiguration_To_v1alpha1_ClientConnectionConfiguration(in *config.ClientConnectionConfiguration, out *ClientConnectionConfiguration, s conversion.Scope) error { + return autoConvert_config_ClientConnectionConfiguration_To_v1alpha1_ClientConnectionConfiguration(in, out, s) +} + +func Convert_v1alpha1_DebuggingConfiguration_To_config_DebuggingConfiguration(in *DebuggingConfiguration, out *config.DebuggingConfiguration, s conversion.Scope) error { + return autoConvert_v1alpha1_DebuggingConfiguration_To_config_DebuggingConfiguration(in, out, s) +} + +func Convert_config_DebuggingConfiguration_To_v1alpha1_DebuggingConfiguration(in *config.DebuggingConfiguration, out *DebuggingConfiguration, s conversion.Scope) error { + return autoConvert_config_DebuggingConfiguration_To_v1alpha1_DebuggingConfiguration(in, out, s) +} + +func Convert_v1alpha1_LeaderElectionConfiguration_To_config_LeaderElectionConfiguration(in *LeaderElectionConfiguration, out *config.LeaderElectionConfiguration, s conversion.Scope) error { + return autoConvert_v1alpha1_LeaderElectionConfiguration_To_config_LeaderElectionConfiguration(in, out, s) +} + +func Convert_config_LeaderElectionConfiguration_To_v1alpha1_LeaderElectionConfiguration(in *config.LeaderElectionConfiguration, out *LeaderElectionConfiguration, s conversion.Scope) error { + return autoConvert_config_LeaderElectionConfiguration_To_v1alpha1_LeaderElectionConfiguration(in, out, s) +} diff --git a/vendor/k8s.io/component-base/config/v1alpha1/defaults.go b/vendor/k8s.io/component-base/config/v1alpha1/defaults.go new file mode 100644 index 0000000000..cd7f820e97 --- /dev/null +++ b/vendor/k8s.io/component-base/config/v1alpha1/defaults.go @@ -0,0 +1,98 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + utilpointer "k8s.io/utils/pointer" +) + +// RecommendedDefaultLeaderElectionConfiguration defaults a pointer to a +// LeaderElectionConfiguration struct. This will set the recommended default +// values, but they may be subject to change between API versions. This function +// is intentionally not registered in the scheme as a "normal" `SetDefaults_Foo` +// function to allow consumers of this type to set whatever defaults for their +// embedded configs. Forcing consumers to use these defaults would be problematic +// as defaulting in the scheme is done as part of the conversion, and there would +// be no easy way to opt-out. Instead, if you want to use this defaulting method +// run it in your wrapper struct of this type in its `SetDefaults_` method. +func RecommendedDefaultLeaderElectionConfiguration(obj *LeaderElectionConfiguration) { + zero := metav1.Duration{} + if obj.LeaseDuration == zero { + obj.LeaseDuration = metav1.Duration{Duration: 15 * time.Second} + } + if obj.RenewDeadline == zero { + obj.RenewDeadline = metav1.Duration{Duration: 10 * time.Second} + } + if obj.RetryPeriod == zero { + obj.RetryPeriod = metav1.Duration{Duration: 2 * time.Second} + } + if obj.ResourceLock == "" { + // TODO(#80289): Figure out how to migrate to LeaseLock at this point. + // This will most probably require going through EndpointsLease first. + obj.ResourceLock = EndpointsResourceLock + } + if obj.LeaderElect == nil { + obj.LeaderElect = utilpointer.BoolPtr(true) + } +} + +// RecommendedDefaultClientConnectionConfiguration defaults a pointer to a +// ClientConnectionConfiguration struct. This will set the recommended default +// values, but they may be subject to change between API versions. This function +// is intentionally not registered in the scheme as a "normal" `SetDefaults_Foo` +// function to allow consumers of this type to set whatever defaults for their +// embedded configs. Forcing consumers to use these defaults would be problematic +// as defaulting in the scheme is done as part of the conversion, and there would +// be no easy way to opt-out. Instead, if you want to use this defaulting method +// run it in your wrapper struct of this type in its `SetDefaults_` method. +func RecommendedDefaultClientConnectionConfiguration(obj *ClientConnectionConfiguration) { + if len(obj.ContentType) == 0 { + obj.ContentType = "application/vnd.kubernetes.protobuf" + } + if obj.QPS == 0.0 { + obj.QPS = 50.0 + } + if obj.Burst == 0 { + obj.Burst = 100 + } +} + +// RecommendedDebuggingConfiguration defaults profiling and debugging configuration. +// This will set the recommended default +// values, but they may be subject to change between API versions. This function +// is intentionally not registered in the scheme as a "normal" `SetDefaults_Foo` +// function to allow consumers of this type to set whatever defaults for their +// embedded configs. Forcing consumers to use these defaults would be problematic +// as defaulting in the scheme is done as part of the conversion, and there would +// be no easy way to opt-out. Instead, if you want to use this defaulting method +// run it in your wrapper struct of this type in its `SetDefaults_` method. +func RecommendedDebuggingConfiguration(obj *DebuggingConfiguration) { + if obj.EnableProfiling == nil { + obj.EnableProfiling = utilpointer.BoolPtr(true) // profile debugging is cheap to have exposed and standard on kube binaries + } +} + +// NewRecommendedDebuggingConfiguration returns the current recommended DebuggingConfiguration. +// This may change between releases as recommendations shift. +func NewRecommendedDebuggingConfiguration() *DebuggingConfiguration { + ret := &DebuggingConfiguration{} + RecommendedDebuggingConfiguration(ret) + return ret +} diff --git a/vendor/k8s.io/component-base/config/v1alpha1/doc.go b/vendor/k8s.io/component-base/config/v1alpha1/doc.go new file mode 100644 index 0000000000..3cd4f4292e --- /dev/null +++ b/vendor/k8s.io/component-base/config/v1alpha1/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// +k8s:deepcopy-gen=package +// +k8s:conversion-gen=k8s.io/component-base/config + +package v1alpha1 // import "k8s.io/component-base/config/v1alpha1" diff --git a/vendor/k8s.io/component-base/config/v1alpha1/register.go b/vendor/k8s.io/component-base/config/v1alpha1/register.go new file mode 100644 index 0000000000..ddc186c9aa --- /dev/null +++ b/vendor/k8s.io/component-base/config/v1alpha1/register.go @@ -0,0 +1,31 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + "k8s.io/apimachinery/pkg/runtime" +) + +var ( + // SchemeBuilder is the scheme builder with scheme init functions to run for this API package + SchemeBuilder runtime.SchemeBuilder + // localSchemeBuilder extends the SchemeBuilder instance with the external types. In this package, + // defaulting and conversion init funcs are registered as well. + localSchemeBuilder = &SchemeBuilder + // AddToScheme is a global function that registers this API group & version to a scheme + AddToScheme = localSchemeBuilder.AddToScheme +) diff --git a/vendor/k8s.io/component-base/config/v1alpha1/types.go b/vendor/k8s.io/component-base/config/v1alpha1/types.go new file mode 100644 index 0000000000..3c5f004f27 --- /dev/null +++ b/vendor/k8s.io/component-base/config/v1alpha1/types.go @@ -0,0 +1,82 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +const EndpointsResourceLock = "endpoints" + +// LeaderElectionConfiguration defines the configuration of leader election +// clients for components that can run with leader election enabled. +type LeaderElectionConfiguration struct { + // leaderElect enables a leader election client to gain leadership + // before executing the main loop. Enable this when running replicated + // components for high availability. + LeaderElect *bool `json:"leaderElect"` + // leaseDuration is the duration that non-leader candidates will wait + // after observing a leadership renewal until attempting to acquire + // leadership of a led but unrenewed leader slot. This is effectively the + // maximum duration that a leader can be stopped before it is replaced + // by another candidate. This is only applicable if leader election is + // enabled. + LeaseDuration metav1.Duration `json:"leaseDuration"` + // renewDeadline is the interval between attempts by the acting master to + // renew a leadership slot before it stops leading. This must be less + // than or equal to the lease duration. This is only applicable if leader + // election is enabled. + RenewDeadline metav1.Duration `json:"renewDeadline"` + // retryPeriod is the duration the clients should wait between attempting + // acquisition and renewal of a leadership. This is only applicable if + // leader election is enabled. + RetryPeriod metav1.Duration `json:"retryPeriod"` + // resourceLock indicates the resource object type that will be used to lock + // during leader election cycles. + ResourceLock string `json:"resourceLock"` + // resourceName indicates the name of resource object that will be used to lock + // during leader election cycles. + ResourceName string `json:"resourceName"` + // resourceName indicates the namespace of resource object that will be used to lock + // during leader election cycles. + ResourceNamespace string `json:"resourceNamespace"` +} + +// DebuggingConfiguration holds configuration for Debugging related features. +type DebuggingConfiguration struct { + // enableProfiling enables profiling via web interface host:port/debug/pprof/ + EnableProfiling *bool `json:"enableProfiling,omitempty"` + // enableContentionProfiling enables block profiling, if + // enableProfiling is true. + EnableContentionProfiling *bool `json:"enableContentionProfiling,omitempty"` +} + +// ClientConnectionConfiguration contains details for constructing a client. +type ClientConnectionConfiguration struct { + // kubeconfig is the path to a KubeConfig file. + Kubeconfig string `json:"kubeconfig"` + // acceptContentTypes defines the Accept header sent by clients when connecting to a server, overriding the + // default value of 'application/json'. This field will control all connections to the server used by a particular + // client. + AcceptContentTypes string `json:"acceptContentTypes"` + // contentType is the content type used when sending data to the server from this client. + ContentType string `json:"contentType"` + // qps controls the number of queries per second allowed for this connection. + QPS float32 `json:"qps"` + // burst allows extra queries to accumulate when a client is exceeding its rate. + Burst int32 `json:"burst"` +} diff --git a/vendor/k8s.io/component-base/config/v1alpha1/zz_generated.conversion.go b/vendor/k8s.io/component-base/config/v1alpha1/zz_generated.conversion.go new file mode 100644 index 0000000000..a911bb50d8 --- /dev/null +++ b/vendor/k8s.io/component-base/config/v1alpha1/zz_generated.conversion.go @@ -0,0 +1,133 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by conversion-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + conversion "k8s.io/apimachinery/pkg/conversion" + runtime "k8s.io/apimachinery/pkg/runtime" + config "k8s.io/component-base/config" +) + +func init() { + localSchemeBuilder.Register(RegisterConversions) +} + +// RegisterConversions adds conversion functions to the given scheme. +// Public to allow building arbitrary schemes. +func RegisterConversions(s *runtime.Scheme) error { + if err := s.AddConversionFunc((*config.ClientConnectionConfiguration)(nil), (*ClientConnectionConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_ClientConnectionConfiguration_To_v1alpha1_ClientConnectionConfiguration(a.(*config.ClientConnectionConfiguration), b.(*ClientConnectionConfiguration), scope) + }); err != nil { + return err + } + if err := s.AddConversionFunc((*config.DebuggingConfiguration)(nil), (*DebuggingConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_DebuggingConfiguration_To_v1alpha1_DebuggingConfiguration(a.(*config.DebuggingConfiguration), b.(*DebuggingConfiguration), scope) + }); err != nil { + return err + } + if err := s.AddConversionFunc((*config.LeaderElectionConfiguration)(nil), (*LeaderElectionConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_LeaderElectionConfiguration_To_v1alpha1_LeaderElectionConfiguration(a.(*config.LeaderElectionConfiguration), b.(*LeaderElectionConfiguration), scope) + }); err != nil { + return err + } + if err := s.AddConversionFunc((*ClientConnectionConfiguration)(nil), (*config.ClientConnectionConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_ClientConnectionConfiguration_To_config_ClientConnectionConfiguration(a.(*ClientConnectionConfiguration), b.(*config.ClientConnectionConfiguration), scope) + }); err != nil { + return err + } + if err := s.AddConversionFunc((*DebuggingConfiguration)(nil), (*config.DebuggingConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_DebuggingConfiguration_To_config_DebuggingConfiguration(a.(*DebuggingConfiguration), b.(*config.DebuggingConfiguration), scope) + }); err != nil { + return err + } + if err := s.AddConversionFunc((*LeaderElectionConfiguration)(nil), (*config.LeaderElectionConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_LeaderElectionConfiguration_To_config_LeaderElectionConfiguration(a.(*LeaderElectionConfiguration), b.(*config.LeaderElectionConfiguration), scope) + }); err != nil { + return err + } + return nil +} + +func autoConvert_v1alpha1_ClientConnectionConfiguration_To_config_ClientConnectionConfiguration(in *ClientConnectionConfiguration, out *config.ClientConnectionConfiguration, s conversion.Scope) error { + out.Kubeconfig = in.Kubeconfig + out.AcceptContentTypes = in.AcceptContentTypes + out.ContentType = in.ContentType + out.QPS = in.QPS + out.Burst = in.Burst + return nil +} + +func autoConvert_config_ClientConnectionConfiguration_To_v1alpha1_ClientConnectionConfiguration(in *config.ClientConnectionConfiguration, out *ClientConnectionConfiguration, s conversion.Scope) error { + out.Kubeconfig = in.Kubeconfig + out.AcceptContentTypes = in.AcceptContentTypes + out.ContentType = in.ContentType + out.QPS = in.QPS + out.Burst = in.Burst + return nil +} + +func autoConvert_v1alpha1_DebuggingConfiguration_To_config_DebuggingConfiguration(in *DebuggingConfiguration, out *config.DebuggingConfiguration, s conversion.Scope) error { + if err := v1.Convert_Pointer_bool_To_bool(&in.EnableProfiling, &out.EnableProfiling, s); err != nil { + return err + } + if err := v1.Convert_Pointer_bool_To_bool(&in.EnableContentionProfiling, &out.EnableContentionProfiling, s); err != nil { + return err + } + return nil +} + +func autoConvert_config_DebuggingConfiguration_To_v1alpha1_DebuggingConfiguration(in *config.DebuggingConfiguration, out *DebuggingConfiguration, s conversion.Scope) error { + if err := v1.Convert_bool_To_Pointer_bool(&in.EnableProfiling, &out.EnableProfiling, s); err != nil { + return err + } + if err := v1.Convert_bool_To_Pointer_bool(&in.EnableContentionProfiling, &out.EnableContentionProfiling, s); err != nil { + return err + } + return nil +} + +func autoConvert_v1alpha1_LeaderElectionConfiguration_To_config_LeaderElectionConfiguration(in *LeaderElectionConfiguration, out *config.LeaderElectionConfiguration, s conversion.Scope) error { + if err := v1.Convert_Pointer_bool_To_bool(&in.LeaderElect, &out.LeaderElect, s); err != nil { + return err + } + out.LeaseDuration = in.LeaseDuration + out.RenewDeadline = in.RenewDeadline + out.RetryPeriod = in.RetryPeriod + out.ResourceLock = in.ResourceLock + out.ResourceName = in.ResourceName + out.ResourceNamespace = in.ResourceNamespace + return nil +} + +func autoConvert_config_LeaderElectionConfiguration_To_v1alpha1_LeaderElectionConfiguration(in *config.LeaderElectionConfiguration, out *LeaderElectionConfiguration, s conversion.Scope) error { + if err := v1.Convert_bool_To_Pointer_bool(&in.LeaderElect, &out.LeaderElect, s); err != nil { + return err + } + out.LeaseDuration = in.LeaseDuration + out.RenewDeadline = in.RenewDeadline + out.RetryPeriod = in.RetryPeriod + out.ResourceLock = in.ResourceLock + out.ResourceName = in.ResourceName + out.ResourceNamespace = in.ResourceNamespace + return nil +} diff --git a/vendor/k8s.io/component-base/config/v1alpha1/zz_generated.deepcopy.go b/vendor/k8s.io/component-base/config/v1alpha1/zz_generated.deepcopy.go new file mode 100644 index 0000000000..92176d9944 --- /dev/null +++ b/vendor/k8s.io/component-base/config/v1alpha1/zz_generated.deepcopy.go @@ -0,0 +1,88 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package v1alpha1 + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClientConnectionConfiguration) DeepCopyInto(out *ClientConnectionConfiguration) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClientConnectionConfiguration. +func (in *ClientConnectionConfiguration) DeepCopy() *ClientConnectionConfiguration { + if in == nil { + return nil + } + out := new(ClientConnectionConfiguration) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DebuggingConfiguration) DeepCopyInto(out *DebuggingConfiguration) { + *out = *in + if in.EnableProfiling != nil { + in, out := &in.EnableProfiling, &out.EnableProfiling + *out = new(bool) + **out = **in + } + if in.EnableContentionProfiling != nil { + in, out := &in.EnableContentionProfiling, &out.EnableContentionProfiling + *out = new(bool) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DebuggingConfiguration. +func (in *DebuggingConfiguration) DeepCopy() *DebuggingConfiguration { + if in == nil { + return nil + } + out := new(DebuggingConfiguration) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LeaderElectionConfiguration) DeepCopyInto(out *LeaderElectionConfiguration) { + *out = *in + if in.LeaderElect != nil { + in, out := &in.LeaderElect, &out.LeaderElect + *out = new(bool) + **out = **in + } + out.LeaseDuration = in.LeaseDuration + out.RenewDeadline = in.RenewDeadline + out.RetryPeriod = in.RetryPeriod + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LeaderElectionConfiguration. +func (in *LeaderElectionConfiguration) DeepCopy() *LeaderElectionConfiguration { + if in == nil { + return nil + } + out := new(LeaderElectionConfiguration) + in.DeepCopyInto(out) + return out +} diff --git a/vendor/k8s.io/component-base/config/zz_generated.deepcopy.go b/vendor/k8s.io/component-base/config/zz_generated.deepcopy.go new file mode 100644 index 0000000000..fb0c1f1e6a --- /dev/null +++ b/vendor/k8s.io/component-base/config/zz_generated.deepcopy.go @@ -0,0 +1,73 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package config + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClientConnectionConfiguration) DeepCopyInto(out *ClientConnectionConfiguration) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClientConnectionConfiguration. +func (in *ClientConnectionConfiguration) DeepCopy() *ClientConnectionConfiguration { + if in == nil { + return nil + } + out := new(ClientConnectionConfiguration) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DebuggingConfiguration) DeepCopyInto(out *DebuggingConfiguration) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DebuggingConfiguration. +func (in *DebuggingConfiguration) DeepCopy() *DebuggingConfiguration { + if in == nil { + return nil + } + out := new(DebuggingConfiguration) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LeaderElectionConfiguration) DeepCopyInto(out *LeaderElectionConfiguration) { + *out = *in + out.LeaseDuration = in.LeaseDuration + out.RenewDeadline = in.RenewDeadline + out.RetryPeriod = in.RetryPeriod + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LeaderElectionConfiguration. +func (in *LeaderElectionConfiguration) DeepCopy() *LeaderElectionConfiguration { + if in == nil { + return nil + } + out := new(LeaderElectionConfiguration) + in.DeepCopyInto(out) + return out +} diff --git a/vendor/modules.txt b/vendor/modules.txt index e6daea049d..beb88e74ea 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -26,6 +26,13 @@ github.com/Azure/go-autorest/logger # github.com/Azure/go-autorest/tracing v0.6.0 ## explicit; go 1.12 github.com/Azure/go-autorest/tracing +# github.com/Microsoft/go-winio v0.6.1 +## explicit; go 1.17 +github.com/Microsoft/go-winio +github.com/Microsoft/go-winio/internal/fs +github.com/Microsoft/go-winio/internal/socket +github.com/Microsoft/go-winio/internal/stringbuffer +github.com/Microsoft/go-winio/pkg/guid # github.com/antlr/antlr4/runtime/Go/antlr v1.4.10 ## explicit; go 1.16 github.com/antlr/antlr4/runtime/Go/antlr @@ -84,6 +91,41 @@ github.com/davecgh/go-spew/spew ## explicit; go 1.12 github.com/dgraph-io/ristretto github.com/dgraph-io/ristretto/z +# github.com/docker/distribution v2.8.2+incompatible +## explicit +github.com/docker/distribution/digestset +github.com/docker/distribution/reference +# github.com/docker/docker v23.0.6+incompatible +## explicit +github.com/docker/docker/api +github.com/docker/docker/api/types +github.com/docker/docker/api/types/blkiodev +github.com/docker/docker/api/types/container +github.com/docker/docker/api/types/events +github.com/docker/docker/api/types/filters +github.com/docker/docker/api/types/image +github.com/docker/docker/api/types/mount +github.com/docker/docker/api/types/network +github.com/docker/docker/api/types/registry +github.com/docker/docker/api/types/strslice +github.com/docker/docker/api/types/swarm +github.com/docker/docker/api/types/swarm/runtime +github.com/docker/docker/api/types/time +github.com/docker/docker/api/types/versions +github.com/docker/docker/api/types/volume +github.com/docker/docker/client +github.com/docker/docker/errdefs +# github.com/docker/go-connections v0.4.0 +## explicit +github.com/docker/go-connections/nat +github.com/docker/go-connections/sockets +github.com/docker/go-connections/tlsconfig +# github.com/docker/go-units v0.5.0 +## explicit +github.com/docker/go-units +# github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 +## explicit; go 1.13 +github.com/dprotaso/go-yit # github.com/emicklei/go-restful/v3 v3.9.0 ## explicit; go 1.13 github.com/emicklei/go-restful/v3 @@ -120,6 +162,16 @@ github.com/go-openapi/jsonreference/internal # github.com/go-openapi/swag v0.22.3 ## explicit; go 1.18 github.com/go-openapi/swag +# github.com/go-playground/locales v0.14.0 +## explicit; go 1.13 +github.com/go-playground/locales +github.com/go-playground/locales/currency +# github.com/go-playground/universal-translator v0.18.0 +## explicit; go 1.13 +github.com/go-playground/universal-translator +# github.com/go-playground/validator/v10 v10.11.1 +## explicit; go 1.13 +github.com/go-playground/validator/v10 # github.com/gogo/protobuf v1.3.2 ## explicit; go 1.15 github.com/gogo/protobuf/proto @@ -211,13 +263,25 @@ github.com/json-iterator/go # github.com/kelseyhightower/envconfig v1.4.0 ## explicit github.com/kelseyhightower/envconfig -# github.com/kiegroup/kie-tools/packages/kn-plugin-workflow v0.28.0 +# github.com/kiegroup/kie-tools/packages/kn-plugin-workflow v0.30.1 ## explicit; go 1.19 github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/command +github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/command/quarkus github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/common github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/metadata github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/pkg/root github.com/kiegroup/kie-tools/packages/kn-plugin-workflow/plugin +# github.com/kiegroup/kogito-serverless-operator/api v1.40.0 +## explicit; go 1.19 +github.com/kiegroup/kogito-serverless-operator/api +github.com/kiegroup/kogito-serverless-operator/api/metadata +github.com/kiegroup/kogito-serverless-operator/api/v1alpha08 +# github.com/kiegroup/kogito-serverless-operator/workflowproj v1.40.0 +## explicit; go 1.19 +github.com/kiegroup/kogito-serverless-operator/workflowproj +# github.com/leodido/go-urn v1.2.1 +## explicit; go 1.13 +github.com/leodido/go-urn # github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de ## explicit github.com/liggitt/tabwriter @@ -253,12 +317,33 @@ github.com/munnerz/goautoneg # github.com/opencontainers/go-digest v1.0.0 ## explicit; go 1.13 github.com/opencontainers/go-digest +# github.com/opencontainers/image-spec v1.0.3-0.20220114050600-8b9d41f48198 +## explicit; go 1.11 +github.com/opencontainers/image-spec/specs-go +github.com/opencontainers/image-spec/specs-go/v1 # github.com/openzipkin/zipkin-go v0.4.0 ## explicit; go 1.14 github.com/openzipkin/zipkin-go/model # github.com/ory/viper v1.7.5 ## explicit; go 1.12 github.com/ory/viper +# github.com/pb33f/libopenapi v0.8.4 +## explicit; go 1.18 +github.com/pb33f/libopenapi +github.com/pb33f/libopenapi/datamodel +github.com/pb33f/libopenapi/datamodel/high +github.com/pb33f/libopenapi/datamodel/high/base +github.com/pb33f/libopenapi/datamodel/high/v2 +github.com/pb33f/libopenapi/datamodel/high/v3 +github.com/pb33f/libopenapi/datamodel/low +github.com/pb33f/libopenapi/datamodel/low/base +github.com/pb33f/libopenapi/datamodel/low/v2 +github.com/pb33f/libopenapi/datamodel/low/v3 +github.com/pb33f/libopenapi/index +github.com/pb33f/libopenapi/resolver +github.com/pb33f/libopenapi/utils +github.com/pb33f/libopenapi/what-changed +github.com/pb33f/libopenapi/what-changed/model # github.com/pelletier/go-toml v1.9.5 ## explicit; go 1.12 github.com/pelletier/go-toml @@ -277,6 +362,7 @@ github.com/pkg/errors # github.com/prometheus/client_golang v1.15.1 ## explicit; go 1.17 github.com/prometheus/client_golang/prometheus +github.com/prometheus/client_golang/prometheus/collectors github.com/prometheus/client_golang/prometheus/internal github.com/prometheus/client_golang/prometheus/promhttp # github.com/prometheus/client_model v0.4.0 @@ -306,13 +392,23 @@ github.com/rickb777/plural # github.com/robfig/cron/v3 v3.0.1 ## explicit; go 1.12 github.com/robfig/cron/v3 -# github.com/rogpeppe/go-internal v1.8.0 -## explicit; go 1.11 # github.com/russross/blackfriday/v2 v2.1.0 ## explicit github.com/russross/blackfriday/v2 +# github.com/santhosh-tekuri/jsonschema/v5 v5.3.0 +## explicit; go 1.15 +github.com/santhosh-tekuri/jsonschema/v5 +# github.com/senseyeio/duration v0.0.0-20180430131211-7c2a214ada46 +## explicit +github.com/senseyeio/duration # github.com/sergi/go-diff v1.2.0 ## explicit; go 1.12 +# github.com/serverlessworkflow/sdk-go/v2 v2.2.3 +## explicit; go 1.19 +github.com/serverlessworkflow/sdk-go/v2/model +github.com/serverlessworkflow/sdk-go/v2/parser +github.com/serverlessworkflow/sdk-go/v2/util/floatstr +github.com/serverlessworkflow/sdk-go/v2/validator # github.com/spf13/afero v1.9.3 ## explicit; go 1.16 github.com/spf13/afero @@ -345,6 +441,9 @@ github.com/spf13/viper/internal/encoding/yaml # github.com/subosito/gotenv v1.4.1 ## explicit; go 1.18 github.com/subosito/gotenv +# github.com/vmware-labs/yaml-jsonpath v0.3.2 +## explicit; go 1.13 +github.com/vmware-labs/yaml-jsonpath/pkg/yamlpath # github.com/xlab/treeprint v1.1.0 ## explicit; go 1.13 github.com/xlab/treeprint @@ -383,8 +482,8 @@ go.uber.org/atomic # go.uber.org/multierr v1.9.0 ## explicit; go 1.19 go.uber.org/multierr -# go.uber.org/zap v1.23.0 -## explicit; go 1.18 +# go.uber.org/zap v1.24.0 +## explicit; go 1.19 go.uber.org/zap go.uber.org/zap/buffer go.uber.org/zap/internal @@ -396,6 +495,7 @@ go.uber.org/zap/zapcore ## explicit; go 1.17 golang.org/x/crypto/pkcs12 golang.org/x/crypto/pkcs12/internal/rc2 +golang.org/x/crypto/sha3 # golang.org/x/mod v0.10.0 ## explicit; go 1.17 golang.org/x/mod/internal/lazyregexp @@ -409,7 +509,9 @@ golang.org/x/net/http2 golang.org/x/net/http2/h2c golang.org/x/net/http2/hpack golang.org/x/net/idna +golang.org/x/net/internal/socks golang.org/x/net/internal/timeseries +golang.org/x/net/proxy golang.org/x/net/trace # golang.org/x/oauth2 v0.7.0 ## explicit; go 1.17 @@ -424,8 +526,10 @@ golang.org/x/oauth2/jwt ## explicit golang.org/x/sync/errgroup golang.org/x/sync/semaphore +golang.org/x/sync/syncmap # golang.org/x/sys v0.8.0 ## explicit; go 1.17 +golang.org/x/sys/cpu golang.org/x/sys/execabs golang.org/x/sys/internal/unsafeheader golang.org/x/sys/plan9 @@ -457,6 +561,7 @@ golang.org/x/text/unicode/norm golang.org/x/time/rate # golang.org/x/tools v0.9.1 ## explicit; go 1.18 +golang.org/x/tools/cmd/stringer golang.org/x/tools/go/ast/astutil golang.org/x/tools/go/gcexportdata golang.org/x/tools/go/internal/packagesdriver @@ -500,7 +605,7 @@ google.golang.org/appengine/urlfetch google.golang.org/genproto/googleapis/api/httpbody google.golang.org/genproto/googleapis/rpc/status google.golang.org/genproto/protobuf/field_mask -# google.golang.org/grpc v1.49.0 +# google.golang.org/grpc v1.51.0 ## explicit; go 1.17 google.golang.org/grpc google.golang.org/grpc/attributes @@ -608,6 +713,8 @@ gotest.tools/v3/internal/format gotest.tools/v3/internal/source # k8s.io/api v0.27.2 => k8s.io/api v0.25.4 ## explicit; go 1.19 +k8s.io/api/admission/v1 +k8s.io/api/admission/v1beta1 k8s.io/api/admissionregistration/v1 k8s.io/api/admissionregistration/v1beta1 k8s.io/api/apiserverinternal/v1alpha1 @@ -669,6 +776,7 @@ k8s.io/apimachinery/pkg/api/meta k8s.io/apimachinery/pkg/api/resource k8s.io/apimachinery/pkg/api/validation k8s.io/apimachinery/pkg/apis/meta/internalversion +k8s.io/apimachinery/pkg/apis/meta/internalversion/scheme k8s.io/apimachinery/pkg/apis/meta/v1 k8s.io/apimachinery/pkg/apis/meta/v1/unstructured k8s.io/apimachinery/pkg/apis/meta/v1/unstructured/unstructuredscheme @@ -815,6 +923,7 @@ k8s.io/client-go/kubernetes/typed/scheduling/v1beta1 k8s.io/client-go/kubernetes/typed/storage/v1 k8s.io/client-go/kubernetes/typed/storage/v1alpha1 k8s.io/client-go/kubernetes/typed/storage/v1beta1 +k8s.io/client-go/metadata k8s.io/client-go/openapi k8s.io/client-go/openapi/cached k8s.io/client-go/pkg/apis/clientauthentication @@ -890,6 +999,10 @@ k8s.io/code-generator/cmd/set-gen k8s.io/code-generator/pkg/namer k8s.io/code-generator/pkg/util k8s.io/code-generator/third_party/forked/golang/reflect +# k8s.io/component-base v0.27.2 +## explicit; go 1.20 +k8s.io/component-base/config +k8s.io/component-base/config/v1alpha1 # k8s.io/gengo v0.0.0-20221011193443-fad74ee6edd9 ## explicit; go 1.13 k8s.io/gengo/args @@ -990,7 +1103,7 @@ knative.dev/networking/pkg/http/probe knative.dev/networking/pkg/http/proxy knative.dev/networking/pkg/http/stats knative.dev/networking/pkg/k8s -# knative.dev/pkg v0.0.0-20230224205330-75da922ef055 => knative.dev/pkg v0.0.0-20230224205330-75da922ef055 +# knative.dev/pkg v0.0.0-20230525143525-9bda38b21643 => knative.dev/pkg v0.0.0-20230224205330-75da922ef055 ## explicit; go 1.18 knative.dev/pkg/apis knative.dev/pkg/apis/duck @@ -1073,6 +1186,49 @@ knative.dev/serving/test/test_images/grpc-ping knative.dev/serving/test/test_images/grpc-ping/proto knative.dev/serving/test/test_images/multicontainer/servingcontainer knative.dev/serving/test/test_images/multicontainer/sidecarcontainer +# sigs.k8s.io/controller-runtime v0.15.0 => sigs.k8s.io/controller-runtime v0.13.0 +## explicit; go 1.17 +sigs.k8s.io/controller-runtime +sigs.k8s.io/controller-runtime/pkg/builder +sigs.k8s.io/controller-runtime/pkg/cache +sigs.k8s.io/controller-runtime/pkg/cache/internal +sigs.k8s.io/controller-runtime/pkg/certwatcher +sigs.k8s.io/controller-runtime/pkg/certwatcher/metrics +sigs.k8s.io/controller-runtime/pkg/client +sigs.k8s.io/controller-runtime/pkg/client/apiutil +sigs.k8s.io/controller-runtime/pkg/client/config +sigs.k8s.io/controller-runtime/pkg/cluster +sigs.k8s.io/controller-runtime/pkg/config +sigs.k8s.io/controller-runtime/pkg/config/v1alpha1 +sigs.k8s.io/controller-runtime/pkg/controller +sigs.k8s.io/controller-runtime/pkg/controller/controllerutil +sigs.k8s.io/controller-runtime/pkg/conversion +sigs.k8s.io/controller-runtime/pkg/event +sigs.k8s.io/controller-runtime/pkg/handler +sigs.k8s.io/controller-runtime/pkg/healthz +sigs.k8s.io/controller-runtime/pkg/internal/controller +sigs.k8s.io/controller-runtime/pkg/internal/controller/metrics +sigs.k8s.io/controller-runtime/pkg/internal/httpserver +sigs.k8s.io/controller-runtime/pkg/internal/log +sigs.k8s.io/controller-runtime/pkg/internal/objectutil +sigs.k8s.io/controller-runtime/pkg/internal/recorder +sigs.k8s.io/controller-runtime/pkg/leaderelection +sigs.k8s.io/controller-runtime/pkg/log +sigs.k8s.io/controller-runtime/pkg/manager +sigs.k8s.io/controller-runtime/pkg/manager/signals +sigs.k8s.io/controller-runtime/pkg/metrics +sigs.k8s.io/controller-runtime/pkg/predicate +sigs.k8s.io/controller-runtime/pkg/ratelimiter +sigs.k8s.io/controller-runtime/pkg/reconcile +sigs.k8s.io/controller-runtime/pkg/recorder +sigs.k8s.io/controller-runtime/pkg/runtime/inject +sigs.k8s.io/controller-runtime/pkg/scheme +sigs.k8s.io/controller-runtime/pkg/source +sigs.k8s.io/controller-runtime/pkg/source/internal +sigs.k8s.io/controller-runtime/pkg/webhook +sigs.k8s.io/controller-runtime/pkg/webhook/admission +sigs.k8s.io/controller-runtime/pkg/webhook/conversion +sigs.k8s.io/controller-runtime/pkg/webhook/internal/metrics # sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd ## explicit; go 1.18 sigs.k8s.io/json @@ -1181,3 +1337,4 @@ sigs.k8s.io/yaml # knative.dev/networking => knative.dev/networking v0.0.0-20230225001731-5e096d63b0cb # knative.dev/pkg => knative.dev/pkg v0.0.0-20230224205330-75da922ef055 # knative.dev/serving => knative.dev/serving v0.36.4 +# sigs.k8s.io/controller-runtime => sigs.k8s.io/controller-runtime v0.13.0 diff --git a/vendor/sigs.k8s.io/controller-runtime/.gitignore b/vendor/sigs.k8s.io/controller-runtime/.gitignore new file mode 100644 index 0000000000..c2c72faf34 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/.gitignore @@ -0,0 +1,24 @@ +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, build with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# editor and IDE paraphernalia +.idea +*.swp +*.swo +*~ + +# Vscode files +.vscode + +# Tools binaries. +hack/tools/bin diff --git a/vendor/sigs.k8s.io/controller-runtime/.golangci.yml b/vendor/sigs.k8s.io/controller-runtime/.golangci.yml new file mode 100644 index 0000000000..7d1d3665ce --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/.golangci.yml @@ -0,0 +1,143 @@ +linters: + disable-all: true + enable: + - asciicheck + - bodyclose + - deadcode + - depguard + - dogsled + - errcheck + - errorlint + - exportloopref + - goconst + - gocritic + - gocyclo + - gofmt + - goimports + - goprintffuncname + - gosec + - gosimple + - govet + - ifshort + - importas + - ineffassign + - misspell + - nakedret + - nilerr + - nolintlint + - prealloc + - revive + - rowserrcheck + - staticcheck + - structcheck + - stylecheck + - typecheck + - unconvert + - unparam + - unused + - varcheck + - whitespace + +linters-settings: + ifshort: + # Maximum length of variable declaration measured in number of characters, after which linter won't suggest using short syntax. + max-decl-chars: 50 + importas: + no-unaliased: true + alias: + # Kubernetes + - pkg: k8s.io/api/core/v1 + alias: corev1 + - pkg: k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1 + alias: apiextensionsv1 + - pkg: k8s.io/apimachinery/pkg/apis/meta/v1 + alias: metav1 + - pkg: k8s.io/apimachinery/pkg/api/errors + alias: apierrors + - pkg: k8s.io/apimachinery/pkg/util/errors + alias: kerrors + # Controller Runtime + - pkg: sigs.k8s.io/controller-runtime + alias: ctrl + staticcheck: + go: "1.19" + stylecheck: + go: "1.19" + depguard: + include-go-root: true + packages: + - io/ioutil # https://go.dev/doc/go1.16#ioutil + +issues: + max-same-issues: 0 + max-issues-per-linter: 0 + # We are disabling default golangci exclusions because we want to help reviewers to focus on reviewing the most relevant + # changes in PRs and avoid nitpicking. + exclude-use-default: false + # List of regexps of issue texts to exclude, empty list by default. + exclude: + # The following are being worked on to remove their exclusion. This list should be reduced or go away all together over time. + # If it is decided they will not be addressed they should be moved above this comment. + - Subprocess launch(ed with variable|ing should be audited) + - (G204|G104|G307) + - "ST1000: at least one file in a package should have a package comment" + exclude-rules: + - linters: + - gosec + text: "G108: Profiling endpoint is automatically exposed on /debug/pprof" + - linters: + - revive + text: "exported: exported method .*\\.(Reconcile|SetupWithManager|SetupWebhookWithManager) should have comment or be unexported" + - linters: + - errcheck + text: Error return value of .((os\.)?std(out|err)\..*|.*Close|.*Flush|os\.Remove(All)?|.*print(f|ln)?|os\.(Un)?Setenv). is not checked + # With Go 1.16, the new embed directive can be used with an un-named import, + # revive (previously, golint) only allows these to be imported in a main.go, which wouldn't work for us. + # This directive allows the embed package to be imported with an underscore everywhere. + - linters: + - revive + source: _ "embed" + # Exclude some packages or code to require comments, for example test code, or fake clients. + - linters: + - revive + text: exported (method|function|type|const) (.+) should have comment or be unexported + source: (func|type).*Fake.* + - linters: + - revive + text: exported (method|function|type|const) (.+) should have comment or be unexported + path: fake_\.go + # Disable unparam "always receives" which might not be really + # useful when building libraries. + - linters: + - unparam + text: always receives + # Dot imports for gomega or ginkgo are allowed + # within test files. + - path: _test\.go + text: should not use dot imports + - path: _test\.go + text: cyclomatic complexity + - path: _test\.go + text: "G107: Potential HTTP request made with variable url" + # Append should be able to assign to a different var/slice. + - linters: + - gocritic + text: "appendAssign: append result not assigned to the same slice" + - linters: + - gocritic + text: "singleCaseSwitch: should rewrite switch statement to if statement" + # It considers all file access to a filename that comes from a variable problematic, + # which is naiv at best. + - linters: + - gosec + text: "G304: Potential file inclusion via variable" + - linters: + - revive + text: "package-comments: should have a package comment" + +run: + timeout: 10m + skip-files: + - "zz_generated.*\\.go$" + - ".*conversion.*\\.go$" + allow-parallel-runners: true diff --git a/vendor/sigs.k8s.io/controller-runtime/CONTRIBUTING.md b/vendor/sigs.k8s.io/controller-runtime/CONTRIBUTING.md new file mode 100644 index 0000000000..2c0ea1f667 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/CONTRIBUTING.md @@ -0,0 +1,19 @@ +# Contributing guidelines + +## Sign the CLA + +Kubernetes projects require that you sign a Contributor License Agreement (CLA) before we can accept your pull requests. + +Please see https://git.k8s.io/community/CLA.md for more info + +## Contributing steps + +1. Submit an issue describing your proposed change to the repo in question. +1. The [repo owners](OWNERS) will respond to your issue promptly. +1. If your proposed change is accepted, and you haven't already done so, sign a Contributor License Agreement (see details above). +1. Fork the desired repo, develop and test your code changes. +1. Submit a pull request. + +## Test locally + +Run the command `make test` to test the changes locally. diff --git a/vendor/sigs.k8s.io/controller-runtime/FAQ.md b/vendor/sigs.k8s.io/controller-runtime/FAQ.md new file mode 100644 index 0000000000..c21b29e287 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/FAQ.md @@ -0,0 +1,81 @@ +# FAQ + +### Q: How do I know which type of object a controller references? + +**A**: Each controller should only reconcile one object type. Other +affected objects should be mapped to a single type of root object, using +the `EnqueueRequestForOwner` or `EnqueueRequestsFromMapFunc` event +handlers, and potentially indices. Then, your Reconcile method should +attempt to reconcile *all* state for that given root objects. + +### Q: How do I have different logic in my reconciler for different types of events (e.g. create, update, delete)? + +**A**: You should not. Reconcile functions should be idempotent, and +should always reconcile state by reading all the state it needs, then +writing updates. This allows your reconciler to correctly respond to +generic events, adjust to skipped or coalesced events, and easily deal +with application startup. The controller will enqueue reconcile requests +for both old and new objects if a mapping changes, but it's your +responsibility to make sure you have enough information to be able clean +up state that's no longer referenced. + +### Q: My cache might be stale if I read from a cache! How should I deal with that? + +**A**: There are several different approaches that can be taken, depending +on your situation. + +- When you can, take advantage of optimistic locking: use deterministic + names for objects you create, so that the Kubernetes API server will + warn you if the object already exists. Many controllers in Kubernetes + take this approach: the StatefulSet controller appends a specific number + to each pod that it creates, while the Deployment controller hashes the + pod template spec and appends that. + +- In the few cases when you cannot take advantage of deterministic names + (e.g. when using generateName), it may be useful in to track which + actions you took, and assume that they need to be repeated if they don't + occur after a given time (e.g. using a requeue result). This is what + the ReplicaSet controller does. + +In general, write your controller with the assumption that information +will eventually be correct, but may be slightly out of date. Make sure +that your reconcile function enforces the entire state of the world each +time it runs. If none of this works for you, you can always construct +a client that reads directly from the API server, but this is generally +considered to be a last resort, and the two approaches above should +generally cover most circumstances. + +### Q: Where's the fake client? How do I use it? + +**A**: The fake client +[exists](https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/client/fake), +but we generally recommend using +[envtest.Environment](https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/envtest#Environment) +to test against a real API server. In our experience, tests using fake +clients gradually re-implement poorly-written impressions of a real API +server, which leads to hard-to-maintain, complex test code. + +### Q: How should I write tests? Any suggestions for getting started? + +- Use the aforementioned + [envtest.Environment](https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/envtest#Environment) + to spin up a real API server instead of trying to mock one out. + +- Structure your tests to check that the state of the world is as you + expect it, *not* that a particular set of API calls were made, when + working with Kubernetes APIs. This will allow you to more easily + refactor and improve the internals of your controllers without changing + your tests. + +- Remember that any time you're interacting with the API server, changes + may have some delay between write time and reconcile time. + +### Q: What are these errors about no Kind being registered for a type? + +**A**: You're probably missing a fully-set-up Scheme. Schemes record the +mapping between Go types and group-version-kinds in Kubernetes. In +general, your application should have its own Scheme containing the types +from the API groups that it needs (be they Kubernetes types or your own). +See the [scheme builder +docs](https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/scheme) for +more information. diff --git a/vendor/sigs.k8s.io/controller-runtime/LICENSE b/vendor/sigs.k8s.io/controller-runtime/LICENSE new file mode 100644 index 0000000000..8dada3edaf --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/sigs.k8s.io/controller-runtime/Makefile b/vendor/sigs.k8s.io/controller-runtime/Makefile new file mode 100644 index 0000000000..36647c697f --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/Makefile @@ -0,0 +1,123 @@ +#!/usr/bin/env bash + +# Copyright 2020 The Kubernetes Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# If you update this file, please follow +# https://suva.sh/posts/well-documented-makefiles + +## -------------------------------------- +## General +## -------------------------------------- + +SHELL:=/usr/bin/env bash +.DEFAULT_GOAL:=help + +# Use GOPROXY environment variable if set +GOPROXY := $(shell go env GOPROXY) +ifeq ($(GOPROXY),) +GOPROXY := https://proxy.golang.org +endif +export GOPROXY + +# Active module mode, as we use go modules to manage dependencies +export GO111MODULE=on + +# Tools. +TOOLS_DIR := hack/tools +TOOLS_BIN_DIR := $(TOOLS_DIR)/bin +GOLANGCI_LINT := $(abspath $(TOOLS_BIN_DIR)/golangci-lint) +GO_APIDIFF := $(TOOLS_BIN_DIR)/go-apidiff +CONTROLLER_GEN := $(TOOLS_BIN_DIR)/controller-gen +ENVTEST_DIR := $(abspath tools/setup-envtest) + +# The help will print out all targets with their descriptions organized bellow their categories. The categories are represented by `##@` and the target descriptions by `##`. +# The awk commands is responsible to read the entire set of makefiles included in this invocation, looking for lines of the file as xyz: ## something, and then pretty-format the target and help. Then, if there's a line with ##@ something, that gets pretty-printed as a category. +# More info over the usage of ANSI control characters for terminal formatting: https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_parameters +# More info over awk command: http://linuxcommand.org/lc3_adv_awk.php +.PHONY: help +help: ## Display this help + @awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST) + +## -------------------------------------- +## Testing +## -------------------------------------- + +.PHONY: test +test: test-tools ## Run the script check-everything.sh which will check all. + TRACE=1 ./hack/check-everything.sh + +.PHONY: test-tools +test-tools: ## tests the tools codebase (setup-envtest) + cd tools/setup-envtest && go test ./... + +## -------------------------------------- +## Binaries +## -------------------------------------- + +$(GO_APIDIFF): $(TOOLS_DIR)/go.mod # Build go-apidiff from tools folder. + cd $(TOOLS_DIR) && go build -tags=tools -o bin/go-apidiff github.com/joelanford/go-apidiff + +$(CONTROLLER_GEN): $(TOOLS_DIR)/go.mod # Build controller-gen from tools folder. + cd $(TOOLS_DIR) && go build -tags=tools -o bin/controller-gen sigs.k8s.io/controller-tools/cmd/controller-gen + +$(GOLANGCI_LINT): .github/workflows/golangci-lint.yml # Download golanci-lint using hack script into tools folder. + hack/ensure-golangci-lint.sh \ + -b $(TOOLS_BIN_DIR) \ + $(shell cat .github/workflows/golangci-lint.yml | grep version | sed 's/.*version: //') + +## -------------------------------------- +## Linting +## -------------------------------------- + +.PHONY: lint +lint: $(GOLANGCI_LINT) ## Lint codebase + $(GOLANGCI_LINT) run -v $(GOLANGCI_LINT_EXTRA_ARGS) + cd tools/setup-envtest; $(GOLANGCI_LINT) run -v $(GOLANGCI_LINT_EXTRA_ARGS) + +.PHONY: lint-fix +lint-fix: $(GOLANGCI_LINT) ## Lint the codebase and run auto-fixers if supported by the linter. + GOLANGCI_LINT_EXTRA_ARGS=--fix $(MAKE) lint + +## -------------------------------------- +## Generate +## -------------------------------------- + +.PHONY: modules +modules: ## Runs go mod to ensure modules are up to date. + go mod tidy + cd $(TOOLS_DIR); go mod tidy + cd $(ENVTEST_DIR); go mod tidy + +.PHONY: generate +generate: $(CONTROLLER_GEN) ## Runs controller-gen for internal types for config file + $(CONTROLLER_GEN) object paths="./pkg/config/v1alpha1/...;./examples/configfile/custom/v1alpha1/..." + +## -------------------------------------- +## Cleanup / Verification +## -------------------------------------- + +.PHONY: clean +clean: ## Cleanup. + $(MAKE) clean-bin + +.PHONY: clean-bin +clean-bin: ## Remove all generated binaries. + rm -rf hack/tools/bin + +.PHONY: verify-modules +verify-modules: modules + @if !(git diff --quiet HEAD -- go.sum go.mod); then \ + echo "go module files are out of date, please run 'make modules'"; exit 1; \ + fi diff --git a/vendor/sigs.k8s.io/controller-runtime/README.md b/vendor/sigs.k8s.io/controller-runtime/README.md new file mode 100644 index 0000000000..cd358b94f9 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/README.md @@ -0,0 +1,66 @@ +[![Go Report Card](https://goreportcard.com/badge/sigs.k8s.io/controller-runtime)](https://goreportcard.com/report/sigs.k8s.io/controller-runtime) +[![godoc](https://pkg.go.dev/badge/sigs.k8s.io/controller-runtime)](https://pkg.go.dev/sigs.k8s.io/controller-runtime) + +# Kubernetes controller-runtime Project + +The Kubernetes controller-runtime Project is a set of go libraries for building +Controllers. It is leveraged by [Kubebuilder](https://book.kubebuilder.io/) and +[Operator SDK](https://github.com/operator-framework/operator-sdk). Both are +a great place to start for new projects. See +[Kubebuilder's Quick Start](https://book.kubebuilder.io/quick-start.html) to +see how it can be used. + +Documentation: + +- [Package overview](https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg) +- [Basic controller using builder](https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/builder#example-Builder) +- [Creating a manager](https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/manager#example-New) +- [Creating a controller](https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/controller#example-New) +- [Examples](https://github.com/kubernetes-sigs/controller-runtime/blob/master/examples) +- [Designs](https://github.com/kubernetes-sigs/controller-runtime/blob/master/designs) + +# Versioning, Maintenance, and Compatibility + +The full documentation can be found at [VERSIONING.md](VERSIONING.md), but TL;DR: + +Users: + +- We follow [Semantic Versioning (semver)](https://semver.org) +- Use releases with your dependency management to ensure that you get compatible code +- The master branch contains all the latest code, some of which may break compatibility (so "normal" `go get` is not recommended) + +Contributors: + +- All code PR must be labeled with :bug: (patch fixes), :sparkles: (backwards-compatible features), or :warning: (breaking changes) +- Breaking changes will find their way into the next major release, other changes will go into an semi-immediate patch or minor release +- For a quick PR template suggesting the right information, use one of these PR templates: + * [Breaking Changes/Features](/.github/PULL_REQUEST_TEMPLATE/breaking_change.md) + * [Backwards-Compatible Features](/.github/PULL_REQUEST_TEMPLATE/compat_feature.md) + * [Bug fixes](/.github/PULL_REQUEST_TEMPLATE/bug_fix.md) + * [Documentation Changes](/.github/PULL_REQUEST_TEMPLATE/docs.md) + * [Test/Build/Other Changes](/.github/PULL_REQUEST_TEMPLATE/other.md) + +## FAQ + +See [FAQ.md](FAQ.md) + +## Community, discussion, contribution, and support + +Learn how to engage with the Kubernetes community on the [community page](http://kubernetes.io/community/). + +controller-runtime is a subproject of the [kubebuilder](https://github.com/kubernetes-sigs/kubebuilder) project +in sig apimachinery. + +You can reach the maintainers of this project at: + +- Slack channel: [#kubebuilder](http://slack.k8s.io/#kubebuilder) +- Google Group: [kubebuilder@googlegroups.com](https://groups.google.com/forum/#!forum/kubebuilder) + +## Contributing +Contributions are greatly appreciated. The maintainers actively manage the issues list, and try to highlight issues suitable for newcomers. +The project follows the typical GitHub pull request model. See [CONTRIBUTING.md](CONTRIBUTING.md) for more details. +Before starting any work, please either comment on an existing issue, or file a new one. + +## Code of conduct + +Participation in the Kubernetes community is governed by the [Kubernetes Code of Conduct](code-of-conduct.md). diff --git a/vendor/sigs.k8s.io/controller-runtime/RELEASE.md b/vendor/sigs.k8s.io/controller-runtime/RELEASE.md new file mode 100644 index 0000000000..134a73a31b --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/RELEASE.md @@ -0,0 +1,47 @@ +# Release Process + +The Kubernetes controller-runtime Project is released on an as-needed basis. The process is as follows: + +**Note:** Releases are done from the `release-MAJOR.MINOR` branches. For PATCH releases is not required +to create a new branch you will just need to ensure that all big fixes are cherry-picked into the respective +`release-MAJOR.MINOR` branch. To know more about versioning check https://semver.org/. + +## How to do a release + +### Create the new branch and the release tag + +1. Create a new branch `git checkout -b release-` from master +2. Push the new branch to the remote repository + +### Now, let's generate the changelog + +1. Create the changelog from the new branch `release-` (`git checkout release-`). +You will need to use the [kubebuilder-release-tools][kubebuilder-release-tools] to generate the notes. See [here][release-notes-generation] + +> **Note** +> - You will need to have checkout locally from the remote repository the previous branch +> - Also, ensure that you fetch all tags from the remote `git fetch --all --tags` + +### Draft a new release from GitHub + +1. Create a new tag with the correct version from the new `release-` branch +2. Add the changelog on it and publish. Now, the code source is released ! + +### Add a new Prow test the for the new branch release + +1. Create a new prow test under [github.com/kubernetes/test-infra/tree/master/config/jobs/kubernetes-sigs/controller-runtime](https://github.com/kubernetes/test-infra/tree/master/config/jobs/kubernetes-sigs/controller-runtime) +for the new `release-` branch. (i.e. for the `0.11.0` release see the PR: https://github.com/kubernetes/test-infra/pull/25205) +2. Ping the infra PR in the controller-runtime slack channel for reviews. + +### Announce the new release: + +1. Publish on the Slack channel the new release, i.e: + +```` +:announce: Controller-Runtime v0.12.0 has been released! +This release includes a Kubernetes dependency bump to v1.24. +For more info, see the release page: https://github.com/kubernetes-sigs/controller-runtime/releases. + :tada: Thanks to all our contributors! +```` + +2. An announcement email is sent to `kubebuilder@googlegroups.com` with the subject `[ANNOUNCE] Controller-Runtime $VERSION is released` diff --git a/vendor/sigs.k8s.io/controller-runtime/SECURITY_CONTACTS b/vendor/sigs.k8s.io/controller-runtime/SECURITY_CONTACTS new file mode 100644 index 0000000000..32e6a3b904 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/SECURITY_CONTACTS @@ -0,0 +1,14 @@ +# Defined below are the security contacts for this repo. +# +# They are the contact point for the Product Security Team to reach out +# to for triaging and handling of incoming issues. +# +# The below names agree to abide by the +# [Embargo Policy](https://github.com/kubernetes/sig-release/blob/master/security-release-process-documentation/security-release-process.md#embargo-policy) +# and will be removed and replaced if they violate that agreement. +# +# DO NOT REPORT SECURITY VULNERABILITIES DIRECTLY TO THESE NAMES, FOLLOW THE +# INSTRUCTIONS AT https://kubernetes.io/security/ + +pwittrock +droot diff --git a/vendor/sigs.k8s.io/controller-runtime/TMP-LOGGING.md b/vendor/sigs.k8s.io/controller-runtime/TMP-LOGGING.md new file mode 100644 index 0000000000..b3cfc66517 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/TMP-LOGGING.md @@ -0,0 +1,169 @@ +Logging Guidelines +================== + +controller-runtime uses a kind of logging called *structured logging*. If +you've used a library like Zap or logrus before, you'll be familiar with +the concepts we use. If you've only used a logging library like the "log" +package (in the Go standard library) or "glog" (in Kubernetes), you'll +need to adjust how you think about logging a bit. + +### Getting Started With Structured Logging + +With structured logging, we associate a *constant* log message with some +variable key-value pairs. For instance, suppose we wanted to log that we +were starting reconciliation on a pod. In the Go standard library logger, +we might write: + +```go +log.Printf("starting reconciliation for pod %s/%s", podNamespace, podName) +``` + +In controller-runtime, we'd instead write: + +```go +logger.Info("starting reconciliation", "pod", req.NamespacedNamed) +``` + +or even write + +```go +func (r *Reconciler) Reconcile(req reconcile.Request) (reconcile.Response, error) { + logger := logger.WithValues("pod", req.NamespacedName) + // do some stuff + logger.Info("starting reconciliation") +} +``` + +Notice how we've broken out the information that we want to convey into +a constant message (`"starting reconciliation"`) and some key-value pairs +that convey variable information (`"pod", req.NamespacedName`). We've +there-by added "structure" to our logs, which makes them easier to save +and search later, as well as correlate with metrics and events. + +All of controller-runtime's logging is done via +[logr](https://github.com/go-logr/logr), a generic interface for +structured logging. You can use whichever logging library you want to +implement the actual mechanics of the logging. controller-runtime +provides some helpers to make it easy to use +[Zap](https://go.uber.org/zap) as the implementation. + +You can configure the logging implementation using +`"sigs.k8s.io/controller-runtime/pkg/log".SetLogger`. That +package also contains the convenience functions for setting up Zap. + +You can get a handle to the the "root" logger using +`"sigs.k8s.io/controller-runtime/pkg/log".Log`, and can then call +`WithName` to create individual named loggers. You can call `WithName` +repeatedly to chain names together: + +```go +logger := log.Log.WithName("controller").WithName("replicaset") +// in reconcile... +logger = logger.WithValues("replicaset", req.NamespacedName) +// later on in reconcile... +logger.Info("doing things with pods", "pod", newPod) +``` + +As seen above, you can also call `WithValue` to create a new sub-logger +that always attaches some key-value pairs to a logger. + +Finally, you can use `V(1)` to mark a particular log line as "debug" logs: + +```go +logger.V(1).Info("this is particularly verbose!", "state of the world", +allKubernetesObjectsEverywhere) +``` + +While it's possible to use higher log levels, it's recommended that you +stick with `V(1)` or `V(0)` (which is equivalent to not specifying `V`), +and then filter later based on key-value pairs or messages; different +numbers tend to lose meaning easily over time, and you'll be left +wondering why particular logs lines are at `V(5)` instead of `V(7)`. + +## Logging errors + +Errors should *always* be logged with `log.Error`, which allows logr +implementations to provide special handling of errors (for instance, +providing stack traces in debug mode). + +It's acceptable to log call `log.Error` with a nil error object. This +conveys that an error occurred in some capacity, but that no actual +`error` object was involved. + +Errors returned by the `Reconcile` implementation of the `Reconciler` interface are commonly logged as a `Reconciler error`. +It's a developer choice to create an additional error log in the `Reconcile` implementation so a more specific file name and line for the error are returned. + +## Logging messages + +- Don't put variable content in your messages -- use key-value pairs for + that. Never use `fmt.Sprintf` in your message. + +- Try to match the terminology in your messages with your key-value pairs + -- for instance, if you have a key-value pairs `api version`, use the + term `APIVersion` instead of `GroupVersion` in your message. + +## Logging Kubernetes Objects + +Kubernetes objects should be logged directly, like `log.Info("this is +a Kubernetes object", "pod", somePod)`. controller-runtime provides +a special encoder for Zap that will transform Kubernetes objects into +`name, namespace, apiVersion, kind` objects, when available and not in +development mode. Other logr implementations should implement similar +logic. + +## Logging Structured Values (Key-Value pairs) + +- Use lower-case, space separated keys. For example `object` for objects, + `api version` for `APIVersion` + +- Be consistent across your application, and with controller-runtime when + possible. + +- Try to be brief but descriptive. + +- Match terminology in keys with terminology in the message. + +- Be careful logging non-Kubernetes objects verbatim if they're very + large. + +### Groups, Versions, and Kinds + +- Kinds should not be logged alone (they're meaningless alone). Use + a `GroupKind` object to log them instead, or a `GroupVersionKind` when + version is relevant. + +- If you need to log an API version string, use `api version` as the key + (formatted as with a `GroupVersion`, or as received directly from API + discovery). + +### Objects and Types + +- If code works with a generic Kubernetes `runtime.Object`, use the + `object` key. For specific objects, prefer the resource name as the key + (e.g. `pod` for `v1.Pod` objects). + +- For non-Kubernetes objects, the `object` key may also be used, if you + accept a generic interface. + +- When logging a raw type, log it using the `type` key, with a value of + `fmt.Sprintf("%T", typ)` + +- If there's specific context around a type, the key may be more specific, + but should end with `type` -- for instance, `OwnerType` should be logged + as `owner` in the context of `log.Error(err, "Could not get ObjectKinds + for OwnerType", `owner type`, fmt.Sprintf("%T"))`. When possible, favor + communicating kind instead. + +### Multiple things + +- When logging multiple things, simply pluralize the key. + +### controller-runtime Specifics + +- Reconcile requests should be logged as `request`, although normal code + should favor logging the key. + +- Reconcile keys should be logged as with the same key as if you were + logging the object directly (e.g. `log.Info("reconciling pod", "pod", + req.NamespacedName)`). This ends up having a similar effect to logging + the object directly. diff --git a/vendor/sigs.k8s.io/controller-runtime/VERSIONING.md b/vendor/sigs.k8s.io/controller-runtime/VERSIONING.md new file mode 100644 index 0000000000..18779000ec --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/VERSIONING.md @@ -0,0 +1,30 @@ +# Versioning and Branching in controller-runtime + +We follow the [common KubeBuilder versioning guidelines][guidelines], and +use the corresponding tooling. + +For the purposes of the aforementioned guidelines, controller-runtime +counts as a "library project", but otherwise follows the guidelines +exactly. + +[guidelines]: https://sigs.k8s.io/kubebuilder-release-tools/VERSIONING.md + +## Compatiblity and Release Support + +For release branches, we generally tend to support backporting one (1) +major release (`release-{X-1}` or `release-0.{Y-1}`), but may go back +further if the need arises and is very pressing (e.g. security updates). + +### Dependency Support + +Note the [guidelines on dependency versions][dep-versions]. Particularly: + +- We **DO** guarantee Kubernetes REST API compability -- if a given + version of controller-runtime stops working with what should be + a supported version of Kubernetes, this is almost certainly a bug. + +- We **DO NOT** guarantee any particular compability matrix between + kubernetes library dependencies (client-go, apimachinery, etc); Such + compability is infeasible due to the way those libraries are versioned. + +[dep-versions]: https://sigs.k8s.io/kubebuilder-release-tools/VERSIONING.md#kubernetes-version-compatibility diff --git a/vendor/sigs.k8s.io/controller-runtime/alias.go b/vendor/sigs.k8s.io/controller-runtime/alias.go new file mode 100644 index 0000000000..29f964dcbe --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/alias.go @@ -0,0 +1,150 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package controllerruntime + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/schema" + "sigs.k8s.io/controller-runtime/pkg/builder" + "sigs.k8s.io/controller-runtime/pkg/client/config" + cfg "sigs.k8s.io/controller-runtime/pkg/config" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/manager" + "sigs.k8s.io/controller-runtime/pkg/manager/signals" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + "sigs.k8s.io/controller-runtime/pkg/scheme" +) + +// Builder builds an Application ControllerManagedBy (e.g. Operator) and returns a manager.Manager to start it. +type Builder = builder.Builder + +// Request contains the information necessary to reconcile a Kubernetes object. This includes the +// information to uniquely identify the object - its Name and Namespace. It does NOT contain information about +// any specific Event or the object contents itself. +type Request = reconcile.Request + +// Result contains the result of a Reconciler invocation. +type Result = reconcile.Result + +// Manager initializes shared dependencies such as Caches and Clients, and provides them to Runnables. +// A Manager is required to create Controllers. +type Manager = manager.Manager + +// Options are the arguments for creating a new Manager. +type Options = manager.Options + +// SchemeBuilder builds a new Scheme for mapping go types to Kubernetes GroupVersionKinds. +type SchemeBuilder = scheme.Builder + +// GroupVersion contains the "group" and the "version", which uniquely identifies the API. +type GroupVersion = schema.GroupVersion + +// GroupResource specifies a Group and a Resource, but does not force a version. This is useful for identifying +// concepts during lookup stages without having partially valid types. +type GroupResource = schema.GroupResource + +// TypeMeta describes an individual object in an API response or request +// with strings representing the type of the object and its API schema version. +// Structures that are versioned or persisted should inline TypeMeta. +// +// +k8s:deepcopy-gen=false +type TypeMeta = metav1.TypeMeta + +// ObjectMeta is metadata that all persisted resources must have, which includes all objects +// users must create. +type ObjectMeta = metav1.ObjectMeta + +var ( + // GetConfigOrDie creates a *rest.Config for talking to a Kubernetes apiserver. + // If --kubeconfig is set, will use the kubeconfig file at that location. Otherwise will assume running + // in cluster and use the cluster provided kubeconfig. + // + // Will log an error and exit if there is an error creating the rest.Config. + GetConfigOrDie = config.GetConfigOrDie + + // GetConfig creates a *rest.Config for talking to a Kubernetes apiserver. + // If --kubeconfig is set, will use the kubeconfig file at that location. Otherwise will assume running + // in cluster and use the cluster provided kubeconfig. + // + // Config precedence + // + // * --kubeconfig flag pointing at a file + // + // * KUBECONFIG environment variable pointing at a file + // + // * In-cluster config if running in cluster + // + // * $HOME/.kube/config if exists. + GetConfig = config.GetConfig + + // ConfigFile returns the cfg.File function for deferred config file loading, + // this is passed into Options{}.From() to populate the Options fields for + // the manager. + ConfigFile = cfg.File + + // NewControllerManagedBy returns a new controller builder that will be started by the provided Manager. + NewControllerManagedBy = builder.ControllerManagedBy + + // NewWebhookManagedBy returns a new webhook builder that will be started by the provided Manager. + NewWebhookManagedBy = builder.WebhookManagedBy + + // NewManager returns a new Manager for creating Controllers. + NewManager = manager.New + + // CreateOrUpdate creates or updates the given object obj in the Kubernetes + // cluster. The object's desired state should be reconciled with the existing + // state using the passed in ReconcileFn. obj must be a struct pointer so that + // obj can be updated with the content returned by the Server. + // + // It returns the executed operation and an error. + CreateOrUpdate = controllerutil.CreateOrUpdate + + // SetControllerReference sets owner as a Controller OwnerReference on owned. + // This is used for garbage collection of the owned object and for + // reconciling the owner object on changes to owned (with a Watch + EnqueueRequestForOwner). + // Since only one OwnerReference can be a controller, it returns an error if + // there is another OwnerReference with Controller flag set. + SetControllerReference = controllerutil.SetControllerReference + + // SetupSignalHandler registered for SIGTERM and SIGINT. A stop channel is returned + // which is closed on one of these signals. If a second signal is caught, the program + // is terminated with exit code 1. + SetupSignalHandler = signals.SetupSignalHandler + + // Log is the base logger used by controller-runtime. It delegates + // to another logr.Logger. You *must* call SetLogger to + // get any actual logging. + Log = log.Log + + // LoggerFrom returns a logger with predefined values from a context.Context. + // The logger, when used with controllers, can be expected to contain basic information about the object + // that's being reconciled like: + // - `reconciler group` and `reconciler kind` coming from the For(...) object passed in when building a controller. + // - `name` and `namespace` injected from the reconciliation request. + // + // This is meant to be used with the context supplied in a struct that satisfies the Reconciler interface. + LoggerFrom = log.FromContext + + // LoggerInto takes a context and sets the logger as one of its keys. + // + // This is meant to be used in reconcilers to enrich the logger within a context with additional values. + LoggerInto = log.IntoContext + + // SetLogger sets a concrete logging implementation for all deferred Loggers. + SetLogger = log.SetLogger +) diff --git a/vendor/sigs.k8s.io/controller-runtime/code-of-conduct.md b/vendor/sigs.k8s.io/controller-runtime/code-of-conduct.md new file mode 100644 index 0000000000..0d15c00cf3 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/code-of-conduct.md @@ -0,0 +1,3 @@ +# Kubernetes Community Code of Conduct + +Please refer to our [Kubernetes Community Code of Conduct](https://git.k8s.io/community/code-of-conduct.md) diff --git a/vendor/sigs.k8s.io/controller-runtime/doc.go b/vendor/sigs.k8s.io/controller-runtime/doc.go new file mode 100644 index 0000000000..fa6c532c49 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/doc.go @@ -0,0 +1,128 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package controllerruntime provides tools to construct Kubernetes-style +// controllers that manipulate both Kubernetes CRDs and aggregated/built-in +// Kubernetes APIs. +// +// It defines easy helpers for the common use cases when building CRDs, built +// on top of customizable layers of abstraction. Common cases should be easy, +// and uncommon cases should be possible. In general, controller-runtime tries +// to guide users towards Kubernetes controller best-practices. +// +// # Getting Started +// +// The main entrypoint for controller-runtime is this root package, which +// contains all of the common types needed to get started building controllers: +// +// import ( +// ctrl "sigs.k8s.io/controller-runtime" +// ) +// +// The examples in this package walk through a basic controller setup. The +// kubebuilder book (https://book.kubebuilder.io) has some more in-depth +// walkthroughs. +// +// controller-runtime favors structs with sane defaults over constructors, so +// it's fairly common to see structs being used directly in controller-runtime. +// +// # Organization +// +// A brief-ish walkthrough of the layout of this library can be found below. Each +// package contains more information about how to use it. +// +// Frequently asked questions about using controller-runtime and designing +// controllers can be found at +// https://github.com/kubernetes-sigs/controller-runtime/blob/master/FAQ.md. +// +// # Managers +// +// Every controller and webhook is ultimately run by a Manager (pkg/manager). A +// manager is responsible for running controllers and webhooks, and setting up +// common dependencies (pkg/runtime/inject), like shared caches and clients, as +// well as managing leader election (pkg/leaderelection). Managers are +// generally configured to gracefully shut down controllers on pod termination +// by wiring up a signal handler (pkg/manager/signals). +// +// # Controllers +// +// Controllers (pkg/controller) use events (pkg/event) to eventually trigger +// reconcile requests. They may be constructed manually, but are often +// constructed with a Builder (pkg/builder), which eases the wiring of event +// sources (pkg/source), like Kubernetes API object changes, to event handlers +// (pkg/handler), like "enqueue a reconcile request for the object owner". +// Predicates (pkg/predicate) can be used to filter which events actually +// trigger reconciles. There are pre-written utilities for the common cases, and +// interfaces and helpers for advanced cases. +// +// # Reconcilers +// +// Controller logic is implemented in terms of Reconcilers (pkg/reconcile). A +// Reconciler implements a function which takes a reconcile Request containing +// the name and namespace of the object to reconcile, reconciles the object, +// and returns a Response or an error indicating whether to requeue for a +// second round of processing. +// +// # Clients and Caches +// +// Reconcilers use Clients (pkg/client) to access API objects. The default +// client provided by the manager reads from a local shared cache (pkg/cache) +// and writes directly to the API server, but clients can be constructed that +// only talk to the API server, without a cache. The Cache will auto-populate +// with watched objects, as well as when other structured objects are +// requested. The default split client does not promise to invalidate the cache +// during writes (nor does it promise sequential create/get coherence), and code +// should not assume a get immediately following a create/update will return +// the updated resource. Caches may also have indexes, which can be created via +// a FieldIndexer (pkg/client) obtained from the manager. Indexes can used to +// quickly and easily look up all objects with certain fields set. Reconcilers +// may retrieve event recorders (pkg/recorder) to emit events using the +// manager. +// +// # Schemes +// +// Clients, Caches, and many other things in Kubernetes use Schemes +// (pkg/scheme) to associate Go types to Kubernetes API Kinds +// (Group-Version-Kinds, to be specific). +// +// # Webhooks +// +// Similarly, webhooks (pkg/webhook/admission) may be implemented directly, but +// are often constructed using a builder (pkg/webhook/admission/builder). They +// are run via a server (pkg/webhook) which is managed by a Manager. +// +// # Logging and Metrics +// +// Logging (pkg/log) in controller-runtime is done via structured logs, using a +// log set of interfaces called logr +// (https://pkg.go.dev/github.com/go-logr/logr). While controller-runtime +// provides easy setup for using Zap (https://go.uber.org/zap, pkg/log/zap), +// you can provide any implementation of logr as the base logger for +// controller-runtime. +// +// Metrics (pkg/metrics) provided by controller-runtime are registered into a +// controller-runtime-specific Prometheus metrics registry. The manager can +// serve these by an HTTP endpoint, and additional metrics may be registered to +// this Registry as normal. +// +// # Testing +// +// You can easily build integration and unit tests for your controllers and +// webhooks using the test Environment (pkg/envtest). This will automatically +// stand up a copy of etcd and kube-apiserver, and provide the correct options +// to connect to the API server. It's designed to work well with the Ginkgo +// testing framework, but should work with any testing setup. +package controllerruntime diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/builder/controller.go b/vendor/sigs.k8s.io/controller-runtime/pkg/builder/controller.go new file mode 100644 index 0000000000..efaf069205 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/builder/controller.go @@ -0,0 +1,333 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package builder + +import ( + "fmt" + "strings" + + "github.com/go-logr/logr" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/klog/v2" + + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/apiutil" + "sigs.k8s.io/controller-runtime/pkg/controller" + "sigs.k8s.io/controller-runtime/pkg/handler" + "sigs.k8s.io/controller-runtime/pkg/manager" + "sigs.k8s.io/controller-runtime/pkg/predicate" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + "sigs.k8s.io/controller-runtime/pkg/source" +) + +// Supporting mocking out functions for testing. +var newController = controller.New +var getGvk = apiutil.GVKForObject + +// project represents other forms that the we can use to +// send/receive a given resource (metadata-only, unstructured, etc). +type objectProjection int + +const ( + // projectAsNormal doesn't change the object from the form given. + projectAsNormal objectProjection = iota + // projectAsMetadata turns this into an metadata-only watch. + projectAsMetadata +) + +// Builder builds a Controller. +type Builder struct { + forInput ForInput + ownsInput []OwnsInput + watchesInput []WatchesInput + mgr manager.Manager + globalPredicates []predicate.Predicate + ctrl controller.Controller + ctrlOptions controller.Options + name string +} + +// ControllerManagedBy returns a new controller builder that will be started by the provided Manager. +func ControllerManagedBy(m manager.Manager) *Builder { + return &Builder{mgr: m} +} + +// ForInput represents the information set by For method. +type ForInput struct { + object client.Object + predicates []predicate.Predicate + objectProjection objectProjection + err error +} + +// For defines the type of Object being *reconciled*, and configures the ControllerManagedBy to respond to create / delete / +// update events by *reconciling the object*. +// This is the equivalent of calling +// Watches(&source.Kind{Type: apiType}, &handler.EnqueueRequestForObject{}). +func (blder *Builder) For(object client.Object, opts ...ForOption) *Builder { + if blder.forInput.object != nil { + blder.forInput.err = fmt.Errorf("For(...) should only be called once, could not assign multiple objects for reconciliation") + return blder + } + input := ForInput{object: object} + for _, opt := range opts { + opt.ApplyToFor(&input) + } + + blder.forInput = input + return blder +} + +// OwnsInput represents the information set by Owns method. +type OwnsInput struct { + object client.Object + predicates []predicate.Predicate + objectProjection objectProjection +} + +// Owns defines types of Objects being *generated* by the ControllerManagedBy, and configures the ControllerManagedBy to respond to +// create / delete / update events by *reconciling the owner object*. This is the equivalent of calling +// Watches(&source.Kind{Type: }, &handler.EnqueueRequestForOwner{OwnerType: apiType, IsController: true}). +func (blder *Builder) Owns(object client.Object, opts ...OwnsOption) *Builder { + input := OwnsInput{object: object} + for _, opt := range opts { + opt.ApplyToOwns(&input) + } + + blder.ownsInput = append(blder.ownsInput, input) + return blder +} + +// WatchesInput represents the information set by Watches method. +type WatchesInput struct { + src source.Source + eventhandler handler.EventHandler + predicates []predicate.Predicate + objectProjection objectProjection +} + +// Watches exposes the lower-level ControllerManagedBy Watches functions through the builder. Consider using +// Owns or For instead of Watches directly. +// Specified predicates are registered only for given source. +func (blder *Builder) Watches(src source.Source, eventhandler handler.EventHandler, opts ...WatchesOption) *Builder { + input := WatchesInput{src: src, eventhandler: eventhandler} + for _, opt := range opts { + opt.ApplyToWatches(&input) + } + + blder.watchesInput = append(blder.watchesInput, input) + return blder +} + +// WithEventFilter sets the event filters, to filter which create/update/delete/generic events eventually +// trigger reconciliations. For example, filtering on whether the resource version has changed. +// Given predicate is added for all watched objects. +// Defaults to the empty list. +func (blder *Builder) WithEventFilter(p predicate.Predicate) *Builder { + blder.globalPredicates = append(blder.globalPredicates, p) + return blder +} + +// WithOptions overrides the controller options use in doController. Defaults to empty. +func (blder *Builder) WithOptions(options controller.Options) *Builder { + blder.ctrlOptions = options + return blder +} + +// WithLogConstructor overrides the controller options's LogConstructor. +func (blder *Builder) WithLogConstructor(logConstructor func(*reconcile.Request) logr.Logger) *Builder { + blder.ctrlOptions.LogConstructor = logConstructor + return blder +} + +// Named sets the name of the controller to the given name. The name shows up +// in metrics, among other things, and thus should be a prometheus compatible name +// (underscores and alphanumeric characters only). +// +// By default, controllers are named using the lowercase version of their kind. +func (blder *Builder) Named(name string) *Builder { + blder.name = name + return blder +} + +// Complete builds the Application Controller. +func (blder *Builder) Complete(r reconcile.Reconciler) error { + _, err := blder.Build(r) + return err +} + +// Build builds the Application Controller and returns the Controller it created. +func (blder *Builder) Build(r reconcile.Reconciler) (controller.Controller, error) { + if r == nil { + return nil, fmt.Errorf("must provide a non-nil Reconciler") + } + if blder.mgr == nil { + return nil, fmt.Errorf("must provide a non-nil Manager") + } + if blder.forInput.err != nil { + return nil, blder.forInput.err + } + // Checking the reconcile type exist or not + if blder.forInput.object == nil { + return nil, fmt.Errorf("must provide an object for reconciliation") + } + + // Set the ControllerManagedBy + if err := blder.doController(r); err != nil { + return nil, err + } + + // Set the Watch + if err := blder.doWatch(); err != nil { + return nil, err + } + + return blder.ctrl, nil +} + +func (blder *Builder) project(obj client.Object, proj objectProjection) (client.Object, error) { + switch proj { + case projectAsNormal: + return obj, nil + case projectAsMetadata: + metaObj := &metav1.PartialObjectMetadata{} + gvk, err := getGvk(obj, blder.mgr.GetScheme()) + if err != nil { + return nil, fmt.Errorf("unable to determine GVK of %T for a metadata-only watch: %w", obj, err) + } + metaObj.SetGroupVersionKind(gvk) + return metaObj, nil + default: + panic(fmt.Sprintf("unexpected projection type %v on type %T, should not be possible since this is an internal field", proj, obj)) + } +} + +func (blder *Builder) doWatch() error { + // Reconcile type + typeForSrc, err := blder.project(blder.forInput.object, blder.forInput.objectProjection) + if err != nil { + return err + } + src := &source.Kind{Type: typeForSrc} + hdler := &handler.EnqueueRequestForObject{} + allPredicates := append(blder.globalPredicates, blder.forInput.predicates...) + if err := blder.ctrl.Watch(src, hdler, allPredicates...); err != nil { + return err + } + + // Watches the managed types + for _, own := range blder.ownsInput { + typeForSrc, err := blder.project(own.object, own.objectProjection) + if err != nil { + return err + } + src := &source.Kind{Type: typeForSrc} + hdler := &handler.EnqueueRequestForOwner{ + OwnerType: blder.forInput.object, + IsController: true, + } + allPredicates := append([]predicate.Predicate(nil), blder.globalPredicates...) + allPredicates = append(allPredicates, own.predicates...) + if err := blder.ctrl.Watch(src, hdler, allPredicates...); err != nil { + return err + } + } + + // Do the watch requests + for _, w := range blder.watchesInput { + allPredicates := append([]predicate.Predicate(nil), blder.globalPredicates...) + allPredicates = append(allPredicates, w.predicates...) + + // If the source of this watch is of type *source.Kind, project it. + if srckind, ok := w.src.(*source.Kind); ok { + typeForSrc, err := blder.project(srckind.Type, w.objectProjection) + if err != nil { + return err + } + srckind.Type = typeForSrc + } + + if err := blder.ctrl.Watch(w.src, w.eventhandler, allPredicates...); err != nil { + return err + } + } + return nil +} + +func (blder *Builder) getControllerName(gvk schema.GroupVersionKind) string { + if blder.name != "" { + return blder.name + } + return strings.ToLower(gvk.Kind) +} + +func (blder *Builder) doController(r reconcile.Reconciler) error { + globalOpts := blder.mgr.GetControllerOptions() + + ctrlOptions := blder.ctrlOptions + if ctrlOptions.Reconciler == nil { + ctrlOptions.Reconciler = r + } + + // Retrieve the GVK from the object we're reconciling + // to prepopulate logger information, and to optionally generate a default name. + gvk, err := getGvk(blder.forInput.object, blder.mgr.GetScheme()) + if err != nil { + return err + } + + // Setup concurrency. + if ctrlOptions.MaxConcurrentReconciles == 0 { + groupKind := gvk.GroupKind().String() + + if concurrency, ok := globalOpts.GroupKindConcurrency[groupKind]; ok && concurrency > 0 { + ctrlOptions.MaxConcurrentReconciles = concurrency + } + } + + // Setup cache sync timeout. + if ctrlOptions.CacheSyncTimeout == 0 && globalOpts.CacheSyncTimeout != nil { + ctrlOptions.CacheSyncTimeout = *globalOpts.CacheSyncTimeout + } + + controllerName := blder.getControllerName(gvk) + + // Setup the logger. + if ctrlOptions.LogConstructor == nil { + log := blder.mgr.GetLogger().WithValues( + "controller", controllerName, + "controllerGroup", gvk.Group, + "controllerKind", gvk.Kind, + ) + + ctrlOptions.LogConstructor = func(req *reconcile.Request) logr.Logger { + log := log + if req != nil { + log = log.WithValues( + gvk.Kind, klog.KRef(req.Namespace, req.Name), + "namespace", req.Namespace, "name", req.Name, + ) + } + return log + } + } + + // Build the controller and return. + blder.ctrl, err = newController(controllerName, blder.mgr, ctrlOptions) + return err +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/builder/doc.go b/vendor/sigs.k8s.io/controller-runtime/pkg/builder/doc.go new file mode 100644 index 0000000000..e4df1b709f --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/builder/doc.go @@ -0,0 +1,28 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package builder wraps other controller-runtime libraries and exposes simple +// patterns for building common Controllers. +// +// Projects built with the builder package can trivially be rebased on top of the underlying +// packages if the project requires more customized behavior in the future. +package builder + +import ( + logf "sigs.k8s.io/controller-runtime/pkg/internal/log" +) + +var log = logf.RuntimeLog.WithName("builder") diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/builder/options.go b/vendor/sigs.k8s.io/controller-runtime/pkg/builder/options.go new file mode 100644 index 0000000000..c738ba7d10 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/builder/options.go @@ -0,0 +1,140 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package builder + +import ( + "sigs.k8s.io/controller-runtime/pkg/predicate" +) + +// {{{ "Functional" Option Interfaces + +// ForOption is some configuration that modifies options for a For request. +type ForOption interface { + // ApplyToFor applies this configuration to the given for input. + ApplyToFor(*ForInput) +} + +// OwnsOption is some configuration that modifies options for a owns request. +type OwnsOption interface { + // ApplyToOwns applies this configuration to the given owns input. + ApplyToOwns(*OwnsInput) +} + +// WatchesOption is some configuration that modifies options for a watches request. +type WatchesOption interface { + // ApplyToWatches applies this configuration to the given watches options. + ApplyToWatches(*WatchesInput) +} + +// }}} + +// {{{ Multi-Type Options + +// WithPredicates sets the given predicates list. +func WithPredicates(predicates ...predicate.Predicate) Predicates { + return Predicates{ + predicates: predicates, + } +} + +// Predicates filters events before enqueuing the keys. +type Predicates struct { + predicates []predicate.Predicate +} + +// ApplyToFor applies this configuration to the given ForInput options. +func (w Predicates) ApplyToFor(opts *ForInput) { + opts.predicates = w.predicates +} + +// ApplyToOwns applies this configuration to the given OwnsInput options. +func (w Predicates) ApplyToOwns(opts *OwnsInput) { + opts.predicates = w.predicates +} + +// ApplyToWatches applies this configuration to the given WatchesInput options. +func (w Predicates) ApplyToWatches(opts *WatchesInput) { + opts.predicates = w.predicates +} + +var _ ForOption = &Predicates{} +var _ OwnsOption = &Predicates{} +var _ WatchesOption = &Predicates{} + +// }}} + +// {{{ For & Owns Dual-Type options + +// asProjection configures the projection (currently only metadata) on the input. +// Currently only metadata is supported. We might want to expand +// this to arbitrary non-special local projections in the future. +type projectAs objectProjection + +// ApplyToFor applies this configuration to the given ForInput options. +func (p projectAs) ApplyToFor(opts *ForInput) { + opts.objectProjection = objectProjection(p) +} + +// ApplyToOwns applies this configuration to the given OwnsInput options. +func (p projectAs) ApplyToOwns(opts *OwnsInput) { + opts.objectProjection = objectProjection(p) +} + +// ApplyToWatches applies this configuration to the given WatchesInput options. +func (p projectAs) ApplyToWatches(opts *WatchesInput) { + opts.objectProjection = objectProjection(p) +} + +var ( + // OnlyMetadata tells the controller to *only* cache metadata, and to watch + // the the API server in metadata-only form. This is useful when watching + // lots of objects, really big objects, or objects for which you only know + // the the GVK, but not the structure. You'll need to pass + // metav1.PartialObjectMetadata to the client when fetching objects in your + // reconciler, otherwise you'll end up with a duplicate structured or + // unstructured cache. + // + // When watching a resource with OnlyMetadata, for example the v1.Pod, you + // should not Get and List using the v1.Pod type. Instead, you should use + // the special metav1.PartialObjectMetadata type. + // + // ❌ Incorrect: + // + // pod := &v1.Pod{} + // mgr.GetClient().Get(ctx, nsAndName, pod) + // + // ✅ Correct: + // + // pod := &metav1.PartialObjectMetadata{} + // pod.SetGroupVersionKind(schema.GroupVersionKind{ + // Group: "", + // Version: "v1", + // Kind: "Pod", + // }) + // mgr.GetClient().Get(ctx, nsAndName, pod) + // + // In the first case, controller-runtime will create another cache for the + // concrete type on top of the metadata cache; this increases memory + // consumption and leads to race conditions as caches are not in sync. + OnlyMetadata = projectAs(projectAsMetadata) + + _ ForOption = OnlyMetadata + _ OwnsOption = OnlyMetadata + _ WatchesOption = OnlyMetadata +) + +// }}} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/builder/webhook.go b/vendor/sigs.k8s.io/controller-runtime/pkg/builder/webhook.go new file mode 100644 index 0000000000..534e6d64cd --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/builder/webhook.go @@ -0,0 +1,216 @@ +/* +Copyright 2019 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package builder + +import ( + "errors" + "net/http" + "net/url" + "strings" + + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/client-go/rest" + "sigs.k8s.io/controller-runtime/pkg/client/apiutil" + "sigs.k8s.io/controller-runtime/pkg/manager" + "sigs.k8s.io/controller-runtime/pkg/webhook/admission" + "sigs.k8s.io/controller-runtime/pkg/webhook/conversion" +) + +// WebhookBuilder builds a Webhook. +type WebhookBuilder struct { + apiType runtime.Object + withDefaulter admission.CustomDefaulter + withValidator admission.CustomValidator + gvk schema.GroupVersionKind + mgr manager.Manager + config *rest.Config + recoverPanic bool +} + +// WebhookManagedBy allows inform its manager.Manager. +func WebhookManagedBy(m manager.Manager) *WebhookBuilder { + return &WebhookBuilder{mgr: m} +} + +// TODO(droot): update the GoDoc for conversion. + +// For takes a runtime.Object which should be a CR. +// If the given object implements the admission.Defaulter interface, a MutatingWebhook will be wired for this type. +// If the given object implements the admission.Validator interface, a ValidatingWebhook will be wired for this type. +func (blder *WebhookBuilder) For(apiType runtime.Object) *WebhookBuilder { + blder.apiType = apiType + return blder +} + +// WithDefaulter takes a admission.WithDefaulter interface, a MutatingWebhook will be wired for this type. +func (blder *WebhookBuilder) WithDefaulter(defaulter admission.CustomDefaulter) *WebhookBuilder { + blder.withDefaulter = defaulter + return blder +} + +// WithValidator takes a admission.WithValidator interface, a ValidatingWebhook will be wired for this type. +func (blder *WebhookBuilder) WithValidator(validator admission.CustomValidator) *WebhookBuilder { + blder.withValidator = validator + return blder +} + +// RecoverPanic indicates whether the panic caused by webhook should be recovered. +func (blder *WebhookBuilder) RecoverPanic() *WebhookBuilder { + blder.recoverPanic = true + return blder +} + +// Complete builds the webhook. +func (blder *WebhookBuilder) Complete() error { + // Set the Config + blder.loadRestConfig() + + // Set the Webhook if needed + return blder.registerWebhooks() +} + +func (blder *WebhookBuilder) loadRestConfig() { + if blder.config == nil { + blder.config = blder.mgr.GetConfig() + } +} + +func (blder *WebhookBuilder) registerWebhooks() error { + typ, err := blder.getType() + if err != nil { + return err + } + + // Create webhook(s) for each type + blder.gvk, err = apiutil.GVKForObject(typ, blder.mgr.GetScheme()) + if err != nil { + return err + } + + blder.registerDefaultingWebhook() + blder.registerValidatingWebhook() + + err = blder.registerConversionWebhook() + if err != nil { + return err + } + return nil +} + +// registerDefaultingWebhook registers a defaulting webhook if th. +func (blder *WebhookBuilder) registerDefaultingWebhook() { + mwh := blder.getDefaultingWebhook() + if mwh != nil { + path := generateMutatePath(blder.gvk) + + // Checking if the path is already registered. + // If so, just skip it. + if !blder.isAlreadyHandled(path) { + log.Info("Registering a mutating webhook", + "GVK", blder.gvk, + "path", path) + blder.mgr.GetWebhookServer().Register(path, mwh) + } + } +} + +func (blder *WebhookBuilder) getDefaultingWebhook() *admission.Webhook { + if defaulter := blder.withDefaulter; defaulter != nil { + return admission.WithCustomDefaulter(blder.apiType, defaulter).WithRecoverPanic(blder.recoverPanic) + } + if defaulter, ok := blder.apiType.(admission.Defaulter); ok { + return admission.DefaultingWebhookFor(defaulter).WithRecoverPanic(blder.recoverPanic) + } + log.Info( + "skip registering a mutating webhook, object does not implement admission.Defaulter or WithDefaulter wasn't called", + "GVK", blder.gvk) + return nil +} + +func (blder *WebhookBuilder) registerValidatingWebhook() { + vwh := blder.getValidatingWebhook() + if vwh != nil { + path := generateValidatePath(blder.gvk) + + // Checking if the path is already registered. + // If so, just skip it. + if !blder.isAlreadyHandled(path) { + log.Info("Registering a validating webhook", + "GVK", blder.gvk, + "path", path) + blder.mgr.GetWebhookServer().Register(path, vwh) + } + } +} + +func (blder *WebhookBuilder) getValidatingWebhook() *admission.Webhook { + if validator := blder.withValidator; validator != nil { + return admission.WithCustomValidator(blder.apiType, validator).WithRecoverPanic(blder.recoverPanic) + } + if validator, ok := blder.apiType.(admission.Validator); ok { + return admission.ValidatingWebhookFor(validator).WithRecoverPanic(blder.recoverPanic) + } + log.Info( + "skip registering a validating webhook, object does not implement admission.Validator or WithValidator wasn't called", + "GVK", blder.gvk) + return nil +} + +func (blder *WebhookBuilder) registerConversionWebhook() error { + ok, err := conversion.IsConvertible(blder.mgr.GetScheme(), blder.apiType) + if err != nil { + log.Error(err, "conversion check failed", "GVK", blder.gvk) + return err + } + if ok { + if !blder.isAlreadyHandled("/convert") { + blder.mgr.GetWebhookServer().Register("/convert", &conversion.Webhook{}) + } + log.Info("Conversion webhook enabled", "GVK", blder.gvk) + } + + return nil +} + +func (blder *WebhookBuilder) getType() (runtime.Object, error) { + if blder.apiType != nil { + return blder.apiType, nil + } + return nil, errors.New("For() must be called with a valid object") +} + +func (blder *WebhookBuilder) isAlreadyHandled(path string) bool { + if blder.mgr.GetWebhookServer().WebhookMux == nil { + return false + } + h, p := blder.mgr.GetWebhookServer().WebhookMux.Handler(&http.Request{URL: &url.URL{Path: path}}) + if p == path && h != nil { + return true + } + return false +} + +func generateMutatePath(gvk schema.GroupVersionKind) string { + return "/mutate-" + strings.ReplaceAll(gvk.Group, ".", "-") + "-" + + gvk.Version + "-" + strings.ToLower(gvk.Kind) +} + +func generateValidatePath(gvk schema.GroupVersionKind) string { + return "/validate-" + strings.ReplaceAll(gvk.Group, ".", "-") + "-" + + gvk.Version + "-" + strings.ToLower(gvk.Kind) +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/cache/cache.go b/vendor/sigs.k8s.io/controller-runtime/pkg/cache/cache.go new file mode 100644 index 0000000000..3ff41ffe63 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/cache/cache.go @@ -0,0 +1,275 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package cache + +import ( + "context" + "fmt" + "time" + + "k8s.io/apimachinery/pkg/api/meta" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/client-go/kubernetes/scheme" + "k8s.io/client-go/rest" + toolscache "k8s.io/client-go/tools/cache" + "sigs.k8s.io/controller-runtime/pkg/cache/internal" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/apiutil" + logf "sigs.k8s.io/controller-runtime/pkg/internal/log" +) + +var log = logf.RuntimeLog.WithName("object-cache") + +// Cache knows how to load Kubernetes objects, fetch informers to request +// to receive events for Kubernetes objects (at a low-level), +// and add indices to fields on the objects stored in the cache. +type Cache interface { + // Cache acts as a client to objects stored in the cache. + client.Reader + + // Cache loads informers and adds field indices. + Informers +} + +// Informers knows how to create or fetch informers for different +// group-version-kinds, and add indices to those informers. It's safe to call +// GetInformer from multiple threads. +type Informers interface { + // GetInformer fetches or constructs an informer for the given object that corresponds to a single + // API kind and resource. + GetInformer(ctx context.Context, obj client.Object) (Informer, error) + + // GetInformerForKind is similar to GetInformer, except that it takes a group-version-kind, instead + // of the underlying object. + GetInformerForKind(ctx context.Context, gvk schema.GroupVersionKind) (Informer, error) + + // Start runs all the informers known to this cache until the context is closed. + // It blocks. + Start(ctx context.Context) error + + // WaitForCacheSync waits for all the caches to sync. Returns false if it could not sync a cache. + WaitForCacheSync(ctx context.Context) bool + + // Informers knows how to add indices to the caches (informers) that it manages. + client.FieldIndexer +} + +// Informer - informer allows you interact with the underlying informer. +type Informer interface { + // AddEventHandler adds an event handler to the shared informer using the shared informer's resync + // period. Events to a single handler are delivered sequentially, but there is no coordination + // between different handlers. + AddEventHandler(handler toolscache.ResourceEventHandler) + // AddEventHandlerWithResyncPeriod adds an event handler to the shared informer using the + // specified resync period. Events to a single handler are delivered sequentially, but there is + // no coordination between different handlers. + AddEventHandlerWithResyncPeriod(handler toolscache.ResourceEventHandler, resyncPeriod time.Duration) + // AddIndexers adds more indexers to this store. If you call this after you already have data + // in the store, the results are undefined. + AddIndexers(indexers toolscache.Indexers) error + // HasSynced return true if the informers underlying store has synced. + HasSynced() bool +} + +// ObjectSelector is an alias name of internal.Selector. +type ObjectSelector internal.Selector + +// SelectorsByObject associate a client.Object's GVK to a field/label selector. +// There is also `DefaultSelector` to set a global default (which will be overridden by +// a more specific setting here, if any). +type SelectorsByObject map[client.Object]ObjectSelector + +// Options are the optional arguments for creating a new InformersMap object. +type Options struct { + // Scheme is the scheme to use for mapping objects to GroupVersionKinds + Scheme *runtime.Scheme + + // Mapper is the RESTMapper to use for mapping GroupVersionKinds to Resources + Mapper meta.RESTMapper + + // Resync is the base frequency the informers are resynced. + // Defaults to defaultResyncTime. + // A 10 percent jitter will be added to the Resync period between informers + // So that all informers will not send list requests simultaneously. + Resync *time.Duration + + // Namespace restricts the cache's ListWatch to the desired namespace + // Default watches all namespaces + Namespace string + + // SelectorsByObject restricts the cache's ListWatch to the desired + // fields per GVK at the specified object, the map's value must implement + // Selector [1] using for example a Set [2] + // [1] https://pkg.go.dev/k8s.io/apimachinery/pkg/fields#Selector + // [2] https://pkg.go.dev/k8s.io/apimachinery/pkg/fields#Set + SelectorsByObject SelectorsByObject + + // DefaultSelector will be used as selectors for all object types + // that do not have a selector in SelectorsByObject defined. + DefaultSelector ObjectSelector + + // UnsafeDisableDeepCopyByObject indicates not to deep copy objects during get or + // list objects per GVK at the specified object. + // Be very careful with this, when enabled you must DeepCopy any object before mutating it, + // otherwise you will mutate the object in the cache. + UnsafeDisableDeepCopyByObject DisableDeepCopyByObject + + // TransformByObject is a map from GVKs to transformer functions which + // get applied when objects of the transformation are about to be committed + // to cache. + // + // This function is called both for new objects to enter the cache, + // and for updated objects. + TransformByObject TransformByObject + + // DefaultTransform is the transform used for all GVKs which do + // not have an explicit transform func set in TransformByObject + DefaultTransform toolscache.TransformFunc +} + +var defaultResyncTime = 10 * time.Hour + +// New initializes and returns a new Cache. +func New(config *rest.Config, opts Options) (Cache, error) { + opts, err := defaultOpts(config, opts) + if err != nil { + return nil, err + } + selectorsByGVK, err := convertToSelectorsByGVK(opts.SelectorsByObject, opts.DefaultSelector, opts.Scheme) + if err != nil { + return nil, err + } + disableDeepCopyByGVK, err := convertToDisableDeepCopyByGVK(opts.UnsafeDisableDeepCopyByObject, opts.Scheme) + if err != nil { + return nil, err + } + transformByGVK, err := convertToTransformByKindAndGVK(opts.TransformByObject, opts.DefaultTransform, opts.Scheme) + if err != nil { + return nil, err + } + + im := internal.NewInformersMap(config, opts.Scheme, opts.Mapper, *opts.Resync, opts.Namespace, selectorsByGVK, disableDeepCopyByGVK, transformByGVK) + return &informerCache{InformersMap: im}, nil +} + +// BuilderWithOptions returns a Cache constructor that will build the a cache +// honoring the options argument, this is useful to specify options like +// SelectorsByObject +// WARNING: If SelectorsByObject is specified, filtered out resources are not +// returned. +// WARNING: If UnsafeDisableDeepCopy is enabled, you must DeepCopy any object +// returned from cache get/list before mutating it. +func BuilderWithOptions(options Options) NewCacheFunc { + return func(config *rest.Config, opts Options) (Cache, error) { + if options.Scheme == nil { + options.Scheme = opts.Scheme + } + if options.Mapper == nil { + options.Mapper = opts.Mapper + } + if options.Resync == nil { + options.Resync = opts.Resync + } + if options.Namespace == "" { + options.Namespace = opts.Namespace + } + if opts.Resync == nil { + opts.Resync = options.Resync + } + + return New(config, options) + } +} + +func defaultOpts(config *rest.Config, opts Options) (Options, error) { + // Use the default Kubernetes Scheme if unset + if opts.Scheme == nil { + opts.Scheme = scheme.Scheme + } + + // Construct a new Mapper if unset + if opts.Mapper == nil { + var err error + opts.Mapper, err = apiutil.NewDiscoveryRESTMapper(config) + if err != nil { + log.WithName("setup").Error(err, "Failed to get API Group-Resources") + return opts, fmt.Errorf("could not create RESTMapper from config") + } + } + + // Default the resync period to 10 hours if unset + if opts.Resync == nil { + opts.Resync = &defaultResyncTime + } + return opts, nil +} + +func convertToSelectorsByGVK(selectorsByObject SelectorsByObject, defaultSelector ObjectSelector, scheme *runtime.Scheme) (internal.SelectorsByGVK, error) { + selectorsByGVK := internal.SelectorsByGVK{} + for object, selector := range selectorsByObject { + gvk, err := apiutil.GVKForObject(object, scheme) + if err != nil { + return nil, err + } + selectorsByGVK[gvk] = internal.Selector(selector) + } + selectorsByGVK[schema.GroupVersionKind{}] = internal.Selector(defaultSelector) + return selectorsByGVK, nil +} + +// DisableDeepCopyByObject associate a client.Object's GVK to disable DeepCopy during get or list from cache. +type DisableDeepCopyByObject map[client.Object]bool + +var _ client.Object = &ObjectAll{} + +// ObjectAll is the argument to represent all objects' types. +type ObjectAll struct { + client.Object +} + +func convertToDisableDeepCopyByGVK(disableDeepCopyByObject DisableDeepCopyByObject, scheme *runtime.Scheme) (internal.DisableDeepCopyByGVK, error) { + disableDeepCopyByGVK := internal.DisableDeepCopyByGVK{} + for obj, disable := range disableDeepCopyByObject { + switch obj.(type) { + case ObjectAll, *ObjectAll: + disableDeepCopyByGVK[internal.GroupVersionKindAll] = disable + default: + gvk, err := apiutil.GVKForObject(obj, scheme) + if err != nil { + return nil, err + } + disableDeepCopyByGVK[gvk] = disable + } + } + return disableDeepCopyByGVK, nil +} + +// TransformByObject associate a client.Object's GVK to a transformer function +// to be applied when storing the object into the cache. +type TransformByObject map[client.Object]toolscache.TransformFunc + +func convertToTransformByKindAndGVK(t TransformByObject, defaultTransform toolscache.TransformFunc, scheme *runtime.Scheme) (internal.TransformFuncByObject, error) { + result := internal.NewTransformFuncByObject() + for obj, transformation := range t { + if err := result.Set(obj, scheme, transformation); err != nil { + return nil, err + } + } + result.SetDefault(defaultTransform) + return result, nil +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/cache/doc.go b/vendor/sigs.k8s.io/controller-runtime/pkg/cache/doc.go new file mode 100644 index 0000000000..e1742ac0f3 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/cache/doc.go @@ -0,0 +1,19 @@ +/* +Copyright 2019 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package cache provides object caches that act as caching client.Reader +// instances and help drive Kubernetes-object-based event handlers. +package cache diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/cache/informer_cache.go b/vendor/sigs.k8s.io/controller-runtime/pkg/cache/informer_cache.go new file mode 100644 index 0000000000..08e4e6df59 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/cache/informer_cache.go @@ -0,0 +1,217 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package cache + +import ( + "context" + "fmt" + "reflect" + "strings" + + apimeta "k8s.io/apimachinery/pkg/api/meta" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/client-go/tools/cache" + "sigs.k8s.io/controller-runtime/pkg/cache/internal" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/apiutil" +) + +var ( + _ Informers = &informerCache{} + _ client.Reader = &informerCache{} + _ Cache = &informerCache{} +) + +// ErrCacheNotStarted is returned when trying to read from the cache that wasn't started. +type ErrCacheNotStarted struct{} + +func (*ErrCacheNotStarted) Error() string { + return "the cache is not started, can not read objects" +} + +// informerCache is a Kubernetes Object cache populated from InformersMap. informerCache wraps an InformersMap. +type informerCache struct { + *internal.InformersMap +} + +// Get implements Reader. +func (ip *informerCache) Get(ctx context.Context, key client.ObjectKey, out client.Object, opts ...client.GetOption) error { + gvk, err := apiutil.GVKForObject(out, ip.Scheme) + if err != nil { + return err + } + + started, cache, err := ip.InformersMap.Get(ctx, gvk, out) + if err != nil { + return err + } + + if !started { + return &ErrCacheNotStarted{} + } + return cache.Reader.Get(ctx, key, out) +} + +// List implements Reader. +func (ip *informerCache) List(ctx context.Context, out client.ObjectList, opts ...client.ListOption) error { + gvk, cacheTypeObj, err := ip.objectTypeForListObject(out) + if err != nil { + return err + } + + started, cache, err := ip.InformersMap.Get(ctx, *gvk, cacheTypeObj) + if err != nil { + return err + } + + if !started { + return &ErrCacheNotStarted{} + } + + return cache.Reader.List(ctx, out, opts...) +} + +// objectTypeForListObject tries to find the runtime.Object and associated GVK +// for a single object corresponding to the passed-in list type. We need them +// because they are used as cache map key. +func (ip *informerCache) objectTypeForListObject(list client.ObjectList) (*schema.GroupVersionKind, runtime.Object, error) { + gvk, err := apiutil.GVKForObject(list, ip.Scheme) + if err != nil { + return nil, nil, err + } + + // we need the non-list GVK, so chop off the "List" from the end of the kind + if strings.HasSuffix(gvk.Kind, "List") && apimeta.IsListType(list) { + gvk.Kind = gvk.Kind[:len(gvk.Kind)-4] + } + + _, isUnstructured := list.(*unstructured.UnstructuredList) + var cacheTypeObj runtime.Object + if isUnstructured { + u := &unstructured.Unstructured{} + u.SetGroupVersionKind(gvk) + cacheTypeObj = u + } else { + itemsPtr, err := apimeta.GetItemsPtr(list) + if err != nil { + return nil, nil, err + } + // http://knowyourmeme.com/memes/this-is-fine + elemType := reflect.Indirect(reflect.ValueOf(itemsPtr)).Type().Elem() + if elemType.Kind() != reflect.Ptr { + elemType = reflect.PtrTo(elemType) + } + + cacheTypeValue := reflect.Zero(elemType) + var ok bool + cacheTypeObj, ok = cacheTypeValue.Interface().(runtime.Object) + if !ok { + return nil, nil, fmt.Errorf("cannot get cache for %T, its element %T is not a runtime.Object", list, cacheTypeValue.Interface()) + } + } + + return &gvk, cacheTypeObj, nil +} + +// GetInformerForKind returns the informer for the GroupVersionKind. +func (ip *informerCache) GetInformerForKind(ctx context.Context, gvk schema.GroupVersionKind) (Informer, error) { + // Map the gvk to an object + obj, err := ip.Scheme.New(gvk) + if err != nil { + return nil, err + } + + _, i, err := ip.InformersMap.Get(ctx, gvk, obj) + if err != nil { + return nil, err + } + return i.Informer, err +} + +// GetInformer returns the informer for the obj. +func (ip *informerCache) GetInformer(ctx context.Context, obj client.Object) (Informer, error) { + gvk, err := apiutil.GVKForObject(obj, ip.Scheme) + if err != nil { + return nil, err + } + + _, i, err := ip.InformersMap.Get(ctx, gvk, obj) + if err != nil { + return nil, err + } + return i.Informer, err +} + +// NeedLeaderElection implements the LeaderElectionRunnable interface +// to indicate that this can be started without requiring the leader lock. +func (ip *informerCache) NeedLeaderElection() bool { + return false +} + +// IndexField adds an indexer to the underlying cache, using extraction function to get +// value(s) from the given field. This index can then be used by passing a field selector +// to List. For one-to-one compatibility with "normal" field selectors, only return one value. +// The values may be anything. They will automatically be prefixed with the namespace of the +// given object, if present. The objects passed are guaranteed to be objects of the correct type. +func (ip *informerCache) IndexField(ctx context.Context, obj client.Object, field string, extractValue client.IndexerFunc) error { + informer, err := ip.GetInformer(ctx, obj) + if err != nil { + return err + } + return indexByField(informer, field, extractValue) +} + +func indexByField(indexer Informer, field string, extractor client.IndexerFunc) error { + indexFunc := func(objRaw interface{}) ([]string, error) { + // TODO(directxman12): check if this is the correct type? + obj, isObj := objRaw.(client.Object) + if !isObj { + return nil, fmt.Errorf("object of type %T is not an Object", objRaw) + } + meta, err := apimeta.Accessor(obj) + if err != nil { + return nil, err + } + ns := meta.GetNamespace() + + rawVals := extractor(obj) + var vals []string + if ns == "" { + // if we're not doubling the keys for the namespaced case, just create a new slice with same length + vals = make([]string, len(rawVals)) + } else { + // if we need to add non-namespaced versions too, double the length + vals = make([]string, len(rawVals)*2) + } + for i, rawVal := range rawVals { + // save a namespaced variant, so that we can ask + // "what are all the object matching a given index *in a given namespace*" + vals[i] = internal.KeyToNamespacedKey(ns, rawVal) + if ns != "" { + // if we have a namespace, also inject a special index key for listing + // regardless of the object namespace + vals[i+len(rawVals)] = internal.KeyToNamespacedKey("", rawVal) + } + } + + return vals, nil + } + + return indexer.AddIndexers(cache.Indexers{internal.FieldIndexName(field): indexFunc}) +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/cache/internal/cache_reader.go b/vendor/sigs.k8s.io/controller-runtime/pkg/cache/internal/cache_reader.go new file mode 100644 index 0000000000..9c2255123c --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/cache/internal/cache_reader.go @@ -0,0 +1,218 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package internal + +import ( + "context" + "fmt" + "reflect" + + apierrors "k8s.io/apimachinery/pkg/api/errors" + apimeta "k8s.io/apimachinery/pkg/api/meta" + "k8s.io/apimachinery/pkg/fields" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/selection" + "k8s.io/client-go/tools/cache" + + "sigs.k8s.io/controller-runtime/pkg/client" +) + +// CacheReader is a client.Reader. +var _ client.Reader = &CacheReader{} + +// CacheReader wraps a cache.Index to implement the client.CacheReader interface for a single type. +type CacheReader struct { + // indexer is the underlying indexer wrapped by this cache. + indexer cache.Indexer + + // groupVersionKind is the group-version-kind of the resource. + groupVersionKind schema.GroupVersionKind + + // scopeName is the scope of the resource (namespaced or cluster-scoped). + scopeName apimeta.RESTScopeName + + // disableDeepCopy indicates not to deep copy objects during get or list objects. + // Be very careful with this, when enabled you must DeepCopy any object before mutating it, + // otherwise you will mutate the object in the cache. + disableDeepCopy bool +} + +// Get checks the indexer for the object and writes a copy of it if found. +func (c *CacheReader) Get(_ context.Context, key client.ObjectKey, out client.Object, opts ...client.GetOption) error { + if c.scopeName == apimeta.RESTScopeNameRoot { + key.Namespace = "" + } + storeKey := objectKeyToStoreKey(key) + + // Lookup the object from the indexer cache + obj, exists, err := c.indexer.GetByKey(storeKey) + if err != nil { + return err + } + + // Not found, return an error + if !exists { + // Resource gets transformed into Kind in the error anyway, so this is fine + return apierrors.NewNotFound(schema.GroupResource{ + Group: c.groupVersionKind.Group, + Resource: c.groupVersionKind.Kind, + }, key.Name) + } + + // Verify the result is a runtime.Object + if _, isObj := obj.(runtime.Object); !isObj { + // This should never happen + return fmt.Errorf("cache contained %T, which is not an Object", obj) + } + + if c.disableDeepCopy { + // skip deep copy which might be unsafe + // you must DeepCopy any object before mutating it outside + } else { + // deep copy to avoid mutating cache + obj = obj.(runtime.Object).DeepCopyObject() + } + + // Copy the value of the item in the cache to the returned value + // TODO(directxman12): this is a terrible hack, pls fix (we should have deepcopyinto) + outVal := reflect.ValueOf(out) + objVal := reflect.ValueOf(obj) + if !objVal.Type().AssignableTo(outVal.Type()) { + return fmt.Errorf("cache had type %s, but %s was asked for", objVal.Type(), outVal.Type()) + } + reflect.Indirect(outVal).Set(reflect.Indirect(objVal)) + if !c.disableDeepCopy { + out.GetObjectKind().SetGroupVersionKind(c.groupVersionKind) + } + + return nil +} + +// List lists items out of the indexer and writes them to out. +func (c *CacheReader) List(_ context.Context, out client.ObjectList, opts ...client.ListOption) error { + var objs []interface{} + var err error + + listOpts := client.ListOptions{} + listOpts.ApplyOptions(opts) + + switch { + case listOpts.FieldSelector != nil: + // TODO(directxman12): support more complicated field selectors by + // combining multiple indices, GetIndexers, etc + field, val, requiresExact := requiresExactMatch(listOpts.FieldSelector) + if !requiresExact { + return fmt.Errorf("non-exact field matches are not supported by the cache") + } + // list all objects by the field selector. If this is namespaced and we have one, ask for the + // namespaced index key. Otherwise, ask for the non-namespaced variant by using the fake "all namespaces" + // namespace. + objs, err = c.indexer.ByIndex(FieldIndexName(field), KeyToNamespacedKey(listOpts.Namespace, val)) + case listOpts.Namespace != "": + objs, err = c.indexer.ByIndex(cache.NamespaceIndex, listOpts.Namespace) + default: + objs = c.indexer.List() + } + if err != nil { + return err + } + var labelSel labels.Selector + if listOpts.LabelSelector != nil { + labelSel = listOpts.LabelSelector + } + + limitSet := listOpts.Limit > 0 + + runtimeObjs := make([]runtime.Object, 0, len(objs)) + for _, item := range objs { + // if the Limit option is set and the number of items + // listed exceeds this limit, then stop reading. + if limitSet && int64(len(runtimeObjs)) >= listOpts.Limit { + break + } + obj, isObj := item.(runtime.Object) + if !isObj { + return fmt.Errorf("cache contained %T, which is not an Object", obj) + } + meta, err := apimeta.Accessor(obj) + if err != nil { + return err + } + if labelSel != nil { + lbls := labels.Set(meta.GetLabels()) + if !labelSel.Matches(lbls) { + continue + } + } + + var outObj runtime.Object + if c.disableDeepCopy { + // skip deep copy which might be unsafe + // you must DeepCopy any object before mutating it outside + outObj = obj + } else { + outObj = obj.DeepCopyObject() + outObj.GetObjectKind().SetGroupVersionKind(c.groupVersionKind) + } + runtimeObjs = append(runtimeObjs, outObj) + } + return apimeta.SetList(out, runtimeObjs) +} + +// objectKeyToStorageKey converts an object key to store key. +// It's akin to MetaNamespaceKeyFunc. It's separate from +// String to allow keeping the key format easily in sync with +// MetaNamespaceKeyFunc. +func objectKeyToStoreKey(k client.ObjectKey) string { + if k.Namespace == "" { + return k.Name + } + return k.Namespace + "/" + k.Name +} + +// requiresExactMatch checks if the given field selector is of the form `k=v` or `k==v`. +func requiresExactMatch(sel fields.Selector) (field, val string, required bool) { + reqs := sel.Requirements() + if len(reqs) != 1 { + return "", "", false + } + req := reqs[0] + if req.Operator != selection.Equals && req.Operator != selection.DoubleEquals { + return "", "", false + } + return req.Field, req.Value, true +} + +// FieldIndexName constructs the name of the index over the given field, +// for use with an indexer. +func FieldIndexName(field string) string { + return "field:" + field +} + +// noNamespaceNamespace is used as the "namespace" when we want to list across all namespaces. +const allNamespacesNamespace = "__all_namespaces" + +// KeyToNamespacedKey prefixes the given index key with a namespace +// for use in field selector indexes. +func KeyToNamespacedKey(ns string, baseKey string) string { + if ns != "" { + return ns + "/" + baseKey + } + return allNamespacesNamespace + "/" + baseKey +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/cache/internal/deleg_map.go b/vendor/sigs.k8s.io/controller-runtime/pkg/cache/internal/deleg_map.go new file mode 100644 index 0000000000..27f46e3278 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/cache/internal/deleg_map.go @@ -0,0 +1,126 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package internal + +import ( + "context" + "time" + + "k8s.io/apimachinery/pkg/api/meta" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/cache" +) + +// InformersMap create and caches Informers for (runtime.Object, schema.GroupVersionKind) pairs. +// It uses a standard parameter codec constructed based on the given generated Scheme. +type InformersMap struct { + // we abstract over the details of structured/unstructured/metadata with the specificInformerMaps + // TODO(directxman12): genericize this over different projections now that we have 3 different maps + + structured *specificInformersMap + unstructured *specificInformersMap + metadata *specificInformersMap + + // Scheme maps runtime.Objects to GroupVersionKinds + Scheme *runtime.Scheme +} + +// NewInformersMap creates a new InformersMap that can create informers for +// both structured and unstructured objects. +func NewInformersMap(config *rest.Config, + scheme *runtime.Scheme, + mapper meta.RESTMapper, + resync time.Duration, + namespace string, + selectors SelectorsByGVK, + disableDeepCopy DisableDeepCopyByGVK, + transformers TransformFuncByObject, +) *InformersMap { + return &InformersMap{ + structured: newStructuredInformersMap(config, scheme, mapper, resync, namespace, selectors, disableDeepCopy, transformers), + unstructured: newUnstructuredInformersMap(config, scheme, mapper, resync, namespace, selectors, disableDeepCopy, transformers), + metadata: newMetadataInformersMap(config, scheme, mapper, resync, namespace, selectors, disableDeepCopy, transformers), + + Scheme: scheme, + } +} + +// Start calls Run on each of the informers and sets started to true. Blocks on the context. +func (m *InformersMap) Start(ctx context.Context) error { + go m.structured.Start(ctx) + go m.unstructured.Start(ctx) + go m.metadata.Start(ctx) + <-ctx.Done() + return nil +} + +// WaitForCacheSync waits until all the caches have been started and synced. +func (m *InformersMap) WaitForCacheSync(ctx context.Context) bool { + syncedFuncs := append([]cache.InformerSynced(nil), m.structured.HasSyncedFuncs()...) + syncedFuncs = append(syncedFuncs, m.unstructured.HasSyncedFuncs()...) + syncedFuncs = append(syncedFuncs, m.metadata.HasSyncedFuncs()...) + + if !m.structured.waitForStarted(ctx) { + return false + } + if !m.unstructured.waitForStarted(ctx) { + return false + } + if !m.metadata.waitForStarted(ctx) { + return false + } + return cache.WaitForCacheSync(ctx.Done(), syncedFuncs...) +} + +// Get will create a new Informer and add it to the map of InformersMap if none exists. Returns +// the Informer from the map. +func (m *InformersMap) Get(ctx context.Context, gvk schema.GroupVersionKind, obj runtime.Object) (bool, *MapEntry, error) { + switch obj.(type) { + case *unstructured.Unstructured: + return m.unstructured.Get(ctx, gvk, obj) + case *unstructured.UnstructuredList: + return m.unstructured.Get(ctx, gvk, obj) + case *metav1.PartialObjectMetadata: + return m.metadata.Get(ctx, gvk, obj) + case *metav1.PartialObjectMetadataList: + return m.metadata.Get(ctx, gvk, obj) + default: + return m.structured.Get(ctx, gvk, obj) + } +} + +// newStructuredInformersMap creates a new InformersMap for structured objects. +func newStructuredInformersMap(config *rest.Config, scheme *runtime.Scheme, mapper meta.RESTMapper, resync time.Duration, + namespace string, selectors SelectorsByGVK, disableDeepCopy DisableDeepCopyByGVK, transformers TransformFuncByObject) *specificInformersMap { + return newSpecificInformersMap(config, scheme, mapper, resync, namespace, selectors, disableDeepCopy, transformers, createStructuredListWatch) +} + +// newUnstructuredInformersMap creates a new InformersMap for unstructured objects. +func newUnstructuredInformersMap(config *rest.Config, scheme *runtime.Scheme, mapper meta.RESTMapper, resync time.Duration, + namespace string, selectors SelectorsByGVK, disableDeepCopy DisableDeepCopyByGVK, transformers TransformFuncByObject) *specificInformersMap { + return newSpecificInformersMap(config, scheme, mapper, resync, namespace, selectors, disableDeepCopy, transformers, createUnstructuredListWatch) +} + +// newMetadataInformersMap creates a new InformersMap for metadata-only objects. +func newMetadataInformersMap(config *rest.Config, scheme *runtime.Scheme, mapper meta.RESTMapper, resync time.Duration, + namespace string, selectors SelectorsByGVK, disableDeepCopy DisableDeepCopyByGVK, transformers TransformFuncByObject) *specificInformersMap { + return newSpecificInformersMap(config, scheme, mapper, resync, namespace, selectors, disableDeepCopy, transformers, createMetadataListWatch) +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/cache/internal/disabledeepcopy.go b/vendor/sigs.k8s.io/controller-runtime/pkg/cache/internal/disabledeepcopy.go new file mode 100644 index 0000000000..54bd7eec93 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/cache/internal/disabledeepcopy.go @@ -0,0 +1,35 @@ +/* +Copyright 2021 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package internal + +import "k8s.io/apimachinery/pkg/runtime/schema" + +// GroupVersionKindAll is the argument to represent all GroupVersionKind types. +var GroupVersionKindAll = schema.GroupVersionKind{} + +// DisableDeepCopyByGVK associate a GroupVersionKind to disable DeepCopy during get or list from cache. +type DisableDeepCopyByGVK map[schema.GroupVersionKind]bool + +// IsDisabled returns whether a GroupVersionKind is disabled DeepCopy. +func (disableByGVK DisableDeepCopyByGVK) IsDisabled(gvk schema.GroupVersionKind) bool { + if d, ok := disableByGVK[gvk]; ok { + return d + } else if d, ok = disableByGVK[GroupVersionKindAll]; ok { + return d + } + return false +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/cache/internal/informers_map.go b/vendor/sigs.k8s.io/controller-runtime/pkg/cache/internal/informers_map.go new file mode 100644 index 0000000000..1524d2316f --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/cache/internal/informers_map.go @@ -0,0 +1,480 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package internal + +import ( + "context" + "fmt" + "math/rand" + "sync" + "time" + + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/api/meta" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/runtime/serializer" + "k8s.io/apimachinery/pkg/watch" + "k8s.io/client-go/dynamic" + "k8s.io/client-go/metadata" + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/cache" + + "sigs.k8s.io/controller-runtime/pkg/client/apiutil" +) + +func init() { + rand.Seed(time.Now().UnixNano()) +} + +// clientListWatcherFunc knows how to create a ListWatcher. +type createListWatcherFunc func(gvk schema.GroupVersionKind, ip *specificInformersMap) (*cache.ListWatch, error) + +// newSpecificInformersMap returns a new specificInformersMap (like +// the generical InformersMap, except that it doesn't implement WaitForCacheSync). +func newSpecificInformersMap(config *rest.Config, + scheme *runtime.Scheme, + mapper meta.RESTMapper, + resync time.Duration, + namespace string, + selectors SelectorsByGVK, + disableDeepCopy DisableDeepCopyByGVK, + transformers TransformFuncByObject, + createListWatcher createListWatcherFunc, +) *specificInformersMap { + ip := &specificInformersMap{ + config: config, + Scheme: scheme, + mapper: mapper, + informersByGVK: make(map[schema.GroupVersionKind]*MapEntry), + codecs: serializer.NewCodecFactory(scheme), + paramCodec: runtime.NewParameterCodec(scheme), + resync: resync, + startWait: make(chan struct{}), + createListWatcher: createListWatcher, + namespace: namespace, + selectors: selectors.forGVK, + disableDeepCopy: disableDeepCopy, + transformers: transformers, + } + return ip +} + +// MapEntry contains the cached data for an Informer. +type MapEntry struct { + // Informer is the cached informer + Informer cache.SharedIndexInformer + + // CacheReader wraps Informer and implements the CacheReader interface for a single type + Reader CacheReader +} + +// specificInformersMap create and caches Informers for (runtime.Object, schema.GroupVersionKind) pairs. +// It uses a standard parameter codec constructed based on the given generated Scheme. +type specificInformersMap struct { + // Scheme maps runtime.Objects to GroupVersionKinds + Scheme *runtime.Scheme + + // config is used to talk to the apiserver + config *rest.Config + + // mapper maps GroupVersionKinds to Resources + mapper meta.RESTMapper + + // informersByGVK is the cache of informers keyed by groupVersionKind + informersByGVK map[schema.GroupVersionKind]*MapEntry + + // codecs is used to create a new REST client + codecs serializer.CodecFactory + + // paramCodec is used by list and watch + paramCodec runtime.ParameterCodec + + // stop is the stop channel to stop informers + stop <-chan struct{} + + // resync is the base frequency the informers are resynced + // a 10 percent jitter will be added to the resync period between informers + // so that all informers will not send list requests simultaneously. + resync time.Duration + + // mu guards access to the map + mu sync.RWMutex + + // start is true if the informers have been started + started bool + + // startWait is a channel that is closed after the + // informer has been started. + startWait chan struct{} + + // createClient knows how to create a client and a list object, + // and allows for abstracting over the particulars of structured vs + // unstructured objects. + createListWatcher createListWatcherFunc + + // namespace is the namespace that all ListWatches are restricted to + // default or empty string means all namespaces + namespace string + + // selectors are the label or field selectors that will be added to the + // ListWatch ListOptions. + selectors func(gvk schema.GroupVersionKind) Selector + + // disableDeepCopy indicates not to deep copy objects during get or list objects. + disableDeepCopy DisableDeepCopyByGVK + + // transform funcs are applied to objects before they are committed to the cache + transformers TransformFuncByObject +} + +// Start calls Run on each of the informers and sets started to true. Blocks on the context. +// It doesn't return start because it can't return an error, and it's not a runnable directly. +func (ip *specificInformersMap) Start(ctx context.Context) { + func() { + ip.mu.Lock() + defer ip.mu.Unlock() + + // Set the stop channel so it can be passed to informers that are added later + ip.stop = ctx.Done() + + // Start each informer + for _, informer := range ip.informersByGVK { + go informer.Informer.Run(ctx.Done()) + } + + // Set started to true so we immediately start any informers added later. + ip.started = true + close(ip.startWait) + }() + <-ctx.Done() +} + +func (ip *specificInformersMap) waitForStarted(ctx context.Context) bool { + select { + case <-ip.startWait: + return true + case <-ctx.Done(): + return false + } +} + +// HasSyncedFuncs returns all the HasSynced functions for the informers in this map. +func (ip *specificInformersMap) HasSyncedFuncs() []cache.InformerSynced { + ip.mu.RLock() + defer ip.mu.RUnlock() + syncedFuncs := make([]cache.InformerSynced, 0, len(ip.informersByGVK)) + for _, informer := range ip.informersByGVK { + syncedFuncs = append(syncedFuncs, informer.Informer.HasSynced) + } + return syncedFuncs +} + +// Get will create a new Informer and add it to the map of specificInformersMap if none exists. Returns +// the Informer from the map. +func (ip *specificInformersMap) Get(ctx context.Context, gvk schema.GroupVersionKind, obj runtime.Object) (bool, *MapEntry, error) { + // Return the informer if it is found + i, started, ok := func() (*MapEntry, bool, bool) { + ip.mu.RLock() + defer ip.mu.RUnlock() + i, ok := ip.informersByGVK[gvk] + return i, ip.started, ok + }() + + if !ok { + var err error + if i, started, err = ip.addInformerToMap(gvk, obj); err != nil { + return started, nil, err + } + } + + if started && !i.Informer.HasSynced() { + // Wait for it to sync before returning the Informer so that folks don't read from a stale cache. + if !cache.WaitForCacheSync(ctx.Done(), i.Informer.HasSynced) { + return started, nil, apierrors.NewTimeoutError(fmt.Sprintf("failed waiting for %T Informer to sync", obj), 0) + } + } + + return started, i, nil +} + +func (ip *specificInformersMap) addInformerToMap(gvk schema.GroupVersionKind, obj runtime.Object) (*MapEntry, bool, error) { + ip.mu.Lock() + defer ip.mu.Unlock() + + // Check the cache to see if we already have an Informer. If we do, return the Informer. + // This is for the case where 2 routines tried to get the informer when it wasn't in the map + // so neither returned early, but the first one created it. + if i, ok := ip.informersByGVK[gvk]; ok { + return i, ip.started, nil + } + + // Create a NewSharedIndexInformer and add it to the map. + var lw *cache.ListWatch + lw, err := ip.createListWatcher(gvk, ip) + if err != nil { + return nil, false, err + } + ni := cache.NewSharedIndexInformer(lw, obj, resyncPeriod(ip.resync)(), cache.Indexers{ + cache.NamespaceIndex: cache.MetaNamespaceIndexFunc, + }) + + // Check to see if there is a transformer for this gvk + if err := ni.SetTransform(ip.transformers.Get(gvk)); err != nil { + return nil, false, err + } + + rm, err := ip.mapper.RESTMapping(gvk.GroupKind(), gvk.Version) + if err != nil { + return nil, false, err + } + + i := &MapEntry{ + Informer: ni, + Reader: CacheReader{ + indexer: ni.GetIndexer(), + groupVersionKind: gvk, + scopeName: rm.Scope.Name(), + disableDeepCopy: ip.disableDeepCopy.IsDisabled(gvk), + }, + } + ip.informersByGVK[gvk] = i + + // Start the Informer if need by + // TODO(seans): write thorough tests and document what happens here - can you add indexers? + // can you add eventhandlers? + if ip.started { + go i.Informer.Run(ip.stop) + } + return i, ip.started, nil +} + +// newListWatch returns a new ListWatch object that can be used to create a SharedIndexInformer. +func createStructuredListWatch(gvk schema.GroupVersionKind, ip *specificInformersMap) (*cache.ListWatch, error) { + // Kubernetes APIs work against Resources, not GroupVersionKinds. Map the + // groupVersionKind to the Resource API we will use. + mapping, err := ip.mapper.RESTMapping(gvk.GroupKind(), gvk.Version) + if err != nil { + return nil, err + } + + client, err := apiutil.RESTClientForGVK(gvk, false, ip.config, ip.codecs) + if err != nil { + return nil, err + } + listGVK := gvk.GroupVersion().WithKind(gvk.Kind + "List") + listObj, err := ip.Scheme.New(listGVK) + if err != nil { + return nil, err + } + + // TODO: the functions that make use of this ListWatch should be adapted to + // pass in their own contexts instead of relying on this fixed one here. + ctx := context.TODO() + // Create a new ListWatch for the obj + return &cache.ListWatch{ + ListFunc: func(opts metav1.ListOptions) (runtime.Object, error) { + ip.selectors(gvk).ApplyToList(&opts) + res := listObj.DeepCopyObject() + namespace := restrictNamespaceBySelector(ip.namespace, ip.selectors(gvk)) + isNamespaceScoped := namespace != "" && mapping.Scope.Name() != meta.RESTScopeNameRoot + err := client.Get().NamespaceIfScoped(namespace, isNamespaceScoped).Resource(mapping.Resource.Resource).VersionedParams(&opts, ip.paramCodec).Do(ctx).Into(res) + return res, err + }, + // Setup the watch function + WatchFunc: func(opts metav1.ListOptions) (watch.Interface, error) { + ip.selectors(gvk).ApplyToList(&opts) + // Watch needs to be set to true separately + opts.Watch = true + namespace := restrictNamespaceBySelector(ip.namespace, ip.selectors(gvk)) + isNamespaceScoped := namespace != "" && mapping.Scope.Name() != meta.RESTScopeNameRoot + return client.Get().NamespaceIfScoped(namespace, isNamespaceScoped).Resource(mapping.Resource.Resource).VersionedParams(&opts, ip.paramCodec).Watch(ctx) + }, + }, nil +} + +func createUnstructuredListWatch(gvk schema.GroupVersionKind, ip *specificInformersMap) (*cache.ListWatch, error) { + // Kubernetes APIs work against Resources, not GroupVersionKinds. Map the + // groupVersionKind to the Resource API we will use. + mapping, err := ip.mapper.RESTMapping(gvk.GroupKind(), gvk.Version) + if err != nil { + return nil, err + } + + // If the rest configuration has a negotiated serializer passed in, + // we should remove it and use the one that the dynamic client sets for us. + cfg := rest.CopyConfig(ip.config) + cfg.NegotiatedSerializer = nil + dynamicClient, err := dynamic.NewForConfig(cfg) + if err != nil { + return nil, err + } + + // TODO: the functions that make use of this ListWatch should be adapted to + // pass in their own contexts instead of relying on this fixed one here. + ctx := context.TODO() + // Create a new ListWatch for the obj + return &cache.ListWatch{ + ListFunc: func(opts metav1.ListOptions) (runtime.Object, error) { + ip.selectors(gvk).ApplyToList(&opts) + namespace := restrictNamespaceBySelector(ip.namespace, ip.selectors(gvk)) + if namespace != "" && mapping.Scope.Name() != meta.RESTScopeNameRoot { + return dynamicClient.Resource(mapping.Resource).Namespace(namespace).List(ctx, opts) + } + return dynamicClient.Resource(mapping.Resource).List(ctx, opts) + }, + // Setup the watch function + WatchFunc: func(opts metav1.ListOptions) (watch.Interface, error) { + ip.selectors(gvk).ApplyToList(&opts) + // Watch needs to be set to true separately + opts.Watch = true + namespace := restrictNamespaceBySelector(ip.namespace, ip.selectors(gvk)) + if namespace != "" && mapping.Scope.Name() != meta.RESTScopeNameRoot { + return dynamicClient.Resource(mapping.Resource).Namespace(namespace).Watch(ctx, opts) + } + return dynamicClient.Resource(mapping.Resource).Watch(ctx, opts) + }, + }, nil +} + +func createMetadataListWatch(gvk schema.GroupVersionKind, ip *specificInformersMap) (*cache.ListWatch, error) { + // Kubernetes APIs work against Resources, not GroupVersionKinds. Map the + // groupVersionKind to the Resource API we will use. + mapping, err := ip.mapper.RESTMapping(gvk.GroupKind(), gvk.Version) + if err != nil { + return nil, err + } + + // Always clear the negotiated serializer and use the one + // set from the metadata client. + cfg := rest.CopyConfig(ip.config) + cfg.NegotiatedSerializer = nil + + // grab the metadata client + client, err := metadata.NewForConfig(cfg) + if err != nil { + return nil, err + } + + // TODO: the functions that make use of this ListWatch should be adapted to + // pass in their own contexts instead of relying on this fixed one here. + ctx := context.TODO() + + // create the relevant listwatch + return &cache.ListWatch{ + ListFunc: func(opts metav1.ListOptions) (runtime.Object, error) { + ip.selectors(gvk).ApplyToList(&opts) + + var ( + list *metav1.PartialObjectMetadataList + err error + ) + namespace := restrictNamespaceBySelector(ip.namespace, ip.selectors(gvk)) + if namespace != "" && mapping.Scope.Name() != meta.RESTScopeNameRoot { + list, err = client.Resource(mapping.Resource).Namespace(namespace).List(ctx, opts) + } else { + list, err = client.Resource(mapping.Resource).List(ctx, opts) + } + if list != nil { + for i := range list.Items { + list.Items[i].SetGroupVersionKind(gvk) + } + } + return list, err + }, + // Setup the watch function + WatchFunc: func(opts metav1.ListOptions) (watch.Interface, error) { + ip.selectors(gvk).ApplyToList(&opts) + // Watch needs to be set to true separately + opts.Watch = true + + var ( + watcher watch.Interface + err error + ) + namespace := restrictNamespaceBySelector(ip.namespace, ip.selectors(gvk)) + if namespace != "" && mapping.Scope.Name() != meta.RESTScopeNameRoot { + watcher, err = client.Resource(mapping.Resource).Namespace(namespace).Watch(ctx, opts) + } else { + watcher, err = client.Resource(mapping.Resource).Watch(ctx, opts) + } + if watcher != nil { + watcher = newGVKFixupWatcher(gvk, watcher) + } + return watcher, err + }, + }, nil +} + +// newGVKFixupWatcher adds a wrapper that preserves the GVK information when +// events come in. +// +// This works around a bug where GVK information is not passed into mapping +// functions when using the OnlyMetadata option in the builder. +// This issue is most likely caused by kubernetes/kubernetes#80609. +// See kubernetes-sigs/controller-runtime#1484. +// +// This was originally implemented as a cache.ResourceEventHandler wrapper but +// that contained a data race which was resolved by setting the GVK in a watch +// wrapper, before the objects are written to the cache. +// See kubernetes-sigs/controller-runtime#1650. +// +// The original watch wrapper was found to be incompatible with +// k8s.io/client-go/tools/cache.Reflector so it has been re-implemented as a +// watch.Filter which is compatible. +// See kubernetes-sigs/controller-runtime#1789. +func newGVKFixupWatcher(gvk schema.GroupVersionKind, watcher watch.Interface) watch.Interface { + return watch.Filter( + watcher, + func(in watch.Event) (watch.Event, bool) { + in.Object.GetObjectKind().SetGroupVersionKind(gvk) + return in, true + }, + ) +} + +// resyncPeriod returns a function which generates a duration each time it is +// invoked; this is so that multiple controllers don't get into lock-step and all +// hammer the apiserver with list requests simultaneously. +func resyncPeriod(resync time.Duration) func() time.Duration { + return func() time.Duration { + // the factor will fall into [0.9, 1.1) + factor := rand.Float64()/5.0 + 0.9 //nolint:gosec + return time.Duration(float64(resync.Nanoseconds()) * factor) + } +} + +// restrictNamespaceBySelector returns either a global restriction for all ListWatches +// if not default/empty, or the namespace that a ListWatch for the specific resource +// is restricted to, based on a specified field selector for metadata.namespace field. +func restrictNamespaceBySelector(namespaceOpt string, s Selector) string { + if namespaceOpt != "" { + // namespace is already restricted + return namespaceOpt + } + fieldSelector := s.Field + if fieldSelector == nil || fieldSelector.Empty() { + return "" + } + // check whether a selector includes the namespace field + value, found := fieldSelector.RequiresExactMatch("metadata.namespace") + if found { + return value + } + return "" +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/cache/internal/selector.go b/vendor/sigs.k8s.io/controller-runtime/pkg/cache/internal/selector.go new file mode 100644 index 0000000000..4eff32fb35 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/cache/internal/selector.go @@ -0,0 +1,54 @@ +/* +Copyright 2021 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package internal + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/fields" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +// SelectorsByGVK associate a GroupVersionKind to a field/label selector. +type SelectorsByGVK map[schema.GroupVersionKind]Selector + +func (s SelectorsByGVK) forGVK(gvk schema.GroupVersionKind) Selector { + if specific, found := s[gvk]; found { + return specific + } + if defaultSelector, found := s[schema.GroupVersionKind{}]; found { + return defaultSelector + } + + return Selector{} +} + +// Selector specify the label/field selector to fill in ListOptions. +type Selector struct { + Label labels.Selector + Field fields.Selector +} + +// ApplyToList fill in ListOptions LabelSelector and FieldSelector if needed. +func (s Selector) ApplyToList(listOpts *metav1.ListOptions) { + if s.Label != nil { + listOpts.LabelSelector = s.Label.String() + } + if s.Field != nil { + listOpts.FieldSelector = s.Field.String() + } +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/cache/internal/transformers.go b/vendor/sigs.k8s.io/controller-runtime/pkg/cache/internal/transformers.go new file mode 100644 index 0000000000..8cf642c4bd --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/cache/internal/transformers.go @@ -0,0 +1,50 @@ +package internal + +import ( + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/client-go/tools/cache" + "sigs.k8s.io/controller-runtime/pkg/client/apiutil" +) + +// TransformFuncByObject provides access to the correct transform function for +// any given GVK. +type TransformFuncByObject interface { + Set(runtime.Object, *runtime.Scheme, cache.TransformFunc) error + Get(schema.GroupVersionKind) cache.TransformFunc + SetDefault(transformer cache.TransformFunc) +} + +type transformFuncByGVK struct { + defaultTransform cache.TransformFunc + transformers map[schema.GroupVersionKind]cache.TransformFunc +} + +// NewTransformFuncByObject creates a new TransformFuncByObject instance. +func NewTransformFuncByObject() TransformFuncByObject { + return &transformFuncByGVK{ + transformers: make(map[schema.GroupVersionKind]cache.TransformFunc), + defaultTransform: nil, + } +} + +func (t *transformFuncByGVK) SetDefault(transformer cache.TransformFunc) { + t.defaultTransform = transformer +} + +func (t *transformFuncByGVK) Set(obj runtime.Object, scheme *runtime.Scheme, transformer cache.TransformFunc) error { + gvk, err := apiutil.GVKForObject(obj, scheme) + if err != nil { + return err + } + + t.transformers[gvk] = transformer + return nil +} + +func (t transformFuncByGVK) Get(gvk schema.GroupVersionKind) cache.TransformFunc { + if val, ok := t.transformers[gvk]; ok { + return val + } + return t.defaultTransform +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/cache/multi_namespace_cache.go b/vendor/sigs.k8s.io/controller-runtime/pkg/cache/multi_namespace_cache.go new file mode 100644 index 0000000000..64514c0c55 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/cache/multi_namespace_cache.go @@ -0,0 +1,331 @@ +/* +Copyright 2019 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package cache + +import ( + "context" + "fmt" + "time" + + corev1 "k8s.io/api/core/v1" + apimeta "k8s.io/apimachinery/pkg/api/meta" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/client-go/rest" + toolscache "k8s.io/client-go/tools/cache" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/internal/objectutil" +) + +// NewCacheFunc - Function for creating a new cache from the options and a rest config. +type NewCacheFunc func(config *rest.Config, opts Options) (Cache, error) + +// a new global namespaced cache to handle cluster scoped resources. +const globalCache = "_cluster-scope" + +// MultiNamespacedCacheBuilder - Builder function to create a new multi-namespaced cache. +// This will scope the cache to a list of namespaces. Listing for all namespaces +// will list for all the namespaces that this knows about. By default this will create +// a global cache for cluster scoped resource. Note that this is not intended +// to be used for excluding namespaces, this is better done via a Predicate. Also note that +// you may face performance issues when using this with a high number of namespaces. +func MultiNamespacedCacheBuilder(namespaces []string) NewCacheFunc { + return func(config *rest.Config, opts Options) (Cache, error) { + opts, err := defaultOpts(config, opts) + if err != nil { + return nil, err + } + + caches := map[string]Cache{} + + // create a cache for cluster scoped resources + gCache, err := New(config, opts) + if err != nil { + return nil, fmt.Errorf("error creating global cache: %w", err) + } + + for _, ns := range namespaces { + opts.Namespace = ns + c, err := New(config, opts) + if err != nil { + return nil, err + } + caches[ns] = c + } + return &multiNamespaceCache{namespaceToCache: caches, Scheme: opts.Scheme, RESTMapper: opts.Mapper, clusterCache: gCache}, nil + } +} + +// multiNamespaceCache knows how to handle multiple namespaced caches +// Use this feature when scoping permissions for your +// operator to a list of namespaces instead of watching every namespace +// in the cluster. +type multiNamespaceCache struct { + namespaceToCache map[string]Cache + Scheme *runtime.Scheme + RESTMapper apimeta.RESTMapper + clusterCache Cache +} + +var _ Cache = &multiNamespaceCache{} + +// Methods for multiNamespaceCache to conform to the Informers interface. +func (c *multiNamespaceCache) GetInformer(ctx context.Context, obj client.Object) (Informer, error) { + informers := map[string]Informer{} + + // If the object is clusterscoped, get the informer from clusterCache, + // if not use the namespaced caches. + isNamespaced, err := objectutil.IsAPINamespaced(obj, c.Scheme, c.RESTMapper) + if err != nil { + return nil, err + } + if !isNamespaced { + clusterCacheInf, err := c.clusterCache.GetInformer(ctx, obj) + if err != nil { + return nil, err + } + informers[globalCache] = clusterCacheInf + + return &multiNamespaceInformer{namespaceToInformer: informers}, nil + } + + for ns, cache := range c.namespaceToCache { + informer, err := cache.GetInformer(ctx, obj) + if err != nil { + return nil, err + } + informers[ns] = informer + } + + return &multiNamespaceInformer{namespaceToInformer: informers}, nil +} + +func (c *multiNamespaceCache) GetInformerForKind(ctx context.Context, gvk schema.GroupVersionKind) (Informer, error) { + informers := map[string]Informer{} + + // If the object is clusterscoped, get the informer from clusterCache, + // if not use the namespaced caches. + isNamespaced, err := objectutil.IsAPINamespacedWithGVK(gvk, c.Scheme, c.RESTMapper) + if err != nil { + return nil, err + } + if !isNamespaced { + clusterCacheInf, err := c.clusterCache.GetInformerForKind(ctx, gvk) + if err != nil { + return nil, err + } + informers[globalCache] = clusterCacheInf + + return &multiNamespaceInformer{namespaceToInformer: informers}, nil + } + + for ns, cache := range c.namespaceToCache { + informer, err := cache.GetInformerForKind(ctx, gvk) + if err != nil { + return nil, err + } + informers[ns] = informer + } + + return &multiNamespaceInformer{namespaceToInformer: informers}, nil +} + +func (c *multiNamespaceCache) Start(ctx context.Context) error { + // start global cache + go func() { + err := c.clusterCache.Start(ctx) + if err != nil { + log.Error(err, "cluster scoped cache failed to start") + } + }() + + // start namespaced caches + for ns, cache := range c.namespaceToCache { + go func(ns string, cache Cache) { + err := cache.Start(ctx) + if err != nil { + log.Error(err, "multinamespace cache failed to start namespaced informer", "namespace", ns) + } + }(ns, cache) + } + + <-ctx.Done() + return nil +} + +func (c *multiNamespaceCache) WaitForCacheSync(ctx context.Context) bool { + synced := true + for _, cache := range c.namespaceToCache { + if s := cache.WaitForCacheSync(ctx); !s { + synced = s + } + } + + // check if cluster scoped cache has synced + if !c.clusterCache.WaitForCacheSync(ctx) { + synced = false + } + return synced +} + +func (c *multiNamespaceCache) IndexField(ctx context.Context, obj client.Object, field string, extractValue client.IndexerFunc) error { + isNamespaced, err := objectutil.IsAPINamespaced(obj, c.Scheme, c.RESTMapper) + if err != nil { + return nil //nolint:nilerr + } + + if !isNamespaced { + return c.clusterCache.IndexField(ctx, obj, field, extractValue) + } + + for _, cache := range c.namespaceToCache { + if err := cache.IndexField(ctx, obj, field, extractValue); err != nil { + return err + } + } + return nil +} + +func (c *multiNamespaceCache) Get(ctx context.Context, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error { + isNamespaced, err := objectutil.IsAPINamespaced(obj, c.Scheme, c.RESTMapper) + if err != nil { + return err + } + + if !isNamespaced { + // Look into the global cache to fetch the object + return c.clusterCache.Get(ctx, key, obj) + } + + cache, ok := c.namespaceToCache[key.Namespace] + if !ok { + return fmt.Errorf("unable to get: %v because of unknown namespace for the cache", key) + } + return cache.Get(ctx, key, obj) +} + +// List multi namespace cache will get all the objects in the namespaces that the cache is watching if asked for all namespaces. +func (c *multiNamespaceCache) List(ctx context.Context, list client.ObjectList, opts ...client.ListOption) error { + listOpts := client.ListOptions{} + listOpts.ApplyOptions(opts) + + isNamespaced, err := objectutil.IsAPINamespaced(list, c.Scheme, c.RESTMapper) + if err != nil { + return err + } + + if !isNamespaced { + // Look at the global cache to get the objects with the specified GVK + return c.clusterCache.List(ctx, list, opts...) + } + + if listOpts.Namespace != corev1.NamespaceAll { + cache, ok := c.namespaceToCache[listOpts.Namespace] + if !ok { + return fmt.Errorf("unable to get: %v because of unknown namespace for the cache", listOpts.Namespace) + } + return cache.List(ctx, list, opts...) + } + + listAccessor, err := apimeta.ListAccessor(list) + if err != nil { + return err + } + + allItems, err := apimeta.ExtractList(list) + if err != nil { + return err + } + + limitSet := listOpts.Limit > 0 + + var resourceVersion string + for _, cache := range c.namespaceToCache { + listObj := list.DeepCopyObject().(client.ObjectList) + err = cache.List(ctx, listObj, &listOpts) + if err != nil { + return err + } + items, err := apimeta.ExtractList(listObj) + if err != nil { + return err + } + accessor, err := apimeta.ListAccessor(listObj) + if err != nil { + return fmt.Errorf("object: %T must be a list type", list) + } + allItems = append(allItems, items...) + // The last list call should have the most correct resource version. + resourceVersion = accessor.GetResourceVersion() + if limitSet { + // decrement Limit by the number of items + // fetched from the current namespace. + listOpts.Limit -= int64(len(items)) + // if a Limit was set and the number of + // items read has reached this set limit, + // then stop reading. + if listOpts.Limit == 0 { + break + } + } + } + listAccessor.SetResourceVersion(resourceVersion) + + return apimeta.SetList(list, allItems) +} + +// multiNamespaceInformer knows how to handle interacting with the underlying informer across multiple namespaces. +type multiNamespaceInformer struct { + namespaceToInformer map[string]Informer +} + +var _ Informer = &multiNamespaceInformer{} + +// AddEventHandler adds the handler to each namespaced informer. +func (i *multiNamespaceInformer) AddEventHandler(handler toolscache.ResourceEventHandler) { + for _, informer := range i.namespaceToInformer { + informer.AddEventHandler(handler) + } +} + +// AddEventHandlerWithResyncPeriod adds the handler with a resync period to each namespaced informer. +func (i *multiNamespaceInformer) AddEventHandlerWithResyncPeriod(handler toolscache.ResourceEventHandler, resyncPeriod time.Duration) { + for _, informer := range i.namespaceToInformer { + informer.AddEventHandlerWithResyncPeriod(handler, resyncPeriod) + } +} + +// AddIndexers adds the indexer for each namespaced informer. +func (i *multiNamespaceInformer) AddIndexers(indexers toolscache.Indexers) error { + for _, informer := range i.namespaceToInformer { + err := informer.AddIndexers(indexers) + if err != nil { + return err + } + } + return nil +} + +// HasSynced checks if each namespaced informer has synced. +func (i *multiNamespaceInformer) HasSynced() bool { + for _, informer := range i.namespaceToInformer { + if ok := informer.HasSynced(); !ok { + return ok + } + } + return true +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/certwatcher/certwatcher.go b/vendor/sigs.k8s.io/controller-runtime/pkg/certwatcher/certwatcher.go new file mode 100644 index 0000000000..1030013db3 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/certwatcher/certwatcher.go @@ -0,0 +1,166 @@ +/* +Copyright 2021 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package certwatcher + +import ( + "context" + "crypto/tls" + "sync" + + "github.com/fsnotify/fsnotify" + "sigs.k8s.io/controller-runtime/pkg/certwatcher/metrics" + logf "sigs.k8s.io/controller-runtime/pkg/internal/log" +) + +var log = logf.RuntimeLog.WithName("certwatcher") + +// CertWatcher watches certificate and key files for changes. When either file +// changes, it reads and parses both and calls an optional callback with the new +// certificate. +type CertWatcher struct { + sync.RWMutex + + currentCert *tls.Certificate + watcher *fsnotify.Watcher + + certPath string + keyPath string +} + +// New returns a new CertWatcher watching the given certificate and key. +func New(certPath, keyPath string) (*CertWatcher, error) { + var err error + + cw := &CertWatcher{ + certPath: certPath, + keyPath: keyPath, + } + + // Initial read of certificate and key. + if err := cw.ReadCertificate(); err != nil { + return nil, err + } + + cw.watcher, err = fsnotify.NewWatcher() + if err != nil { + return nil, err + } + + return cw, nil +} + +// GetCertificate fetches the currently loaded certificate, which may be nil. +func (cw *CertWatcher) GetCertificate(_ *tls.ClientHelloInfo) (*tls.Certificate, error) { + cw.RLock() + defer cw.RUnlock() + return cw.currentCert, nil +} + +// Start starts the watch on the certificate and key files. +func (cw *CertWatcher) Start(ctx context.Context) error { + files := []string{cw.certPath, cw.keyPath} + + for _, f := range files { + if err := cw.watcher.Add(f); err != nil { + return err + } + } + + go cw.Watch() + + log.Info("Starting certificate watcher") + + // Block until the context is done. + <-ctx.Done() + + return cw.watcher.Close() +} + +// Watch reads events from the watcher's channel and reacts to changes. +func (cw *CertWatcher) Watch() { + for { + select { + case event, ok := <-cw.watcher.Events: + // Channel is closed. + if !ok { + return + } + + cw.handleEvent(event) + + case err, ok := <-cw.watcher.Errors: + // Channel is closed. + if !ok { + return + } + + log.Error(err, "certificate watch error") + } + } +} + +// ReadCertificate reads the certificate and key files from disk, parses them, +// and updates the current certificate on the watcher. If a callback is set, it +// is invoked with the new certificate. +func (cw *CertWatcher) ReadCertificate() error { + metrics.ReadCertificateTotal.Inc() + cert, err := tls.LoadX509KeyPair(cw.certPath, cw.keyPath) + if err != nil { + metrics.ReadCertificateErrors.Inc() + return err + } + + cw.Lock() + cw.currentCert = &cert + cw.Unlock() + + log.Info("Updated current TLS certificate") + + return nil +} + +func (cw *CertWatcher) handleEvent(event fsnotify.Event) { + // Only care about events which may modify the contents of the file. + if !(isWrite(event) || isRemove(event) || isCreate(event)) { + return + } + + log.V(1).Info("certificate event", "event", event) + + // If the file was removed, re-add the watch. + if isRemove(event) { + if err := cw.watcher.Add(event.Name); err != nil { + log.Error(err, "error re-watching file") + } + } + + if err := cw.ReadCertificate(); err != nil { + log.Error(err, "error re-reading certificate") + } +} + +func isWrite(event fsnotify.Event) bool { + return event.Op&fsnotify.Write == fsnotify.Write +} + +func isCreate(event fsnotify.Event) bool { + return event.Op&fsnotify.Create == fsnotify.Create +} + +func isRemove(event fsnotify.Event) bool { + return event.Op&fsnotify.Remove == fsnotify.Remove +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/certwatcher/doc.go b/vendor/sigs.k8s.io/controller-runtime/pkg/certwatcher/doc.go new file mode 100644 index 0000000000..40c2fc0bfb --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/certwatcher/doc.go @@ -0,0 +1,23 @@ +/* +Copyright 2021 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* +Package certwatcher is a helper for reloading Certificates from disk to be used +with tls servers. It provides a helper func `GetCertificate` which can be +called from `tls.Config` and passed into your tls.Listener. For a detailed +example server view pkg/webhook/server.go. +*/ +package certwatcher diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/certwatcher/metrics/metrics.go b/vendor/sigs.k8s.io/controller-runtime/pkg/certwatcher/metrics/metrics.go new file mode 100644 index 0000000000..05869eff03 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/certwatcher/metrics/metrics.go @@ -0,0 +1,45 @@ +/* +Copyright 2022 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package metrics + +import ( + "github.com/prometheus/client_golang/prometheus" + "sigs.k8s.io/controller-runtime/pkg/metrics" +) + +var ( + // ReadCertificateTotal is a prometheus counter metrics which holds the total + // number of certificate reads. + ReadCertificateTotal = prometheus.NewCounter(prometheus.CounterOpts{ + Name: "certwatcher_read_certificate_total", + Help: "Total number of certificate reads", + }) + + // ReadCertificateErrors is a prometheus counter metrics which holds the total + // number of errors from certificate read. + ReadCertificateErrors = prometheus.NewCounter(prometheus.CounterOpts{ + Name: "certwatcher_read_certificate_errors_total", + Help: "Total number of certificate read errors", + }) +) + +func init() { + metrics.Registry.MustRegister( + ReadCertificateTotal, + ReadCertificateErrors, + ) +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/client/apiutil/apimachinery.go b/vendor/sigs.k8s.io/controller-runtime/pkg/client/apiutil/apimachinery.go new file mode 100644 index 0000000000..c92b0eaaec --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/client/apiutil/apimachinery.go @@ -0,0 +1,196 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package apiutil contains utilities for working with raw Kubernetes +// API machinery, such as creating RESTMappers and raw REST clients, +// and extracting the GVK of an object. +package apiutil + +import ( + "fmt" + "reflect" + "sync" + + "k8s.io/apimachinery/pkg/api/meta" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/runtime/serializer" + "k8s.io/client-go/discovery" + clientgoscheme "k8s.io/client-go/kubernetes/scheme" + "k8s.io/client-go/rest" + "k8s.io/client-go/restmapper" +) + +var ( + protobufScheme = runtime.NewScheme() + protobufSchemeLock sync.RWMutex +) + +func init() { + // Currently only enabled for built-in resources which are guaranteed to implement Protocol Buffers. + // For custom resources, CRDs can not support Protocol Buffers but Aggregated API can. + // See doc: https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/#advanced-features-and-flexibility + if err := clientgoscheme.AddToScheme(protobufScheme); err != nil { + panic(err) + } +} + +// AddToProtobufScheme add the given SchemeBuilder into protobufScheme, which should +// be additional types that do support protobuf. +func AddToProtobufScheme(addToScheme func(*runtime.Scheme) error) error { + protobufSchemeLock.Lock() + defer protobufSchemeLock.Unlock() + return addToScheme(protobufScheme) +} + +// NewDiscoveryRESTMapper constructs a new RESTMapper based on discovery +// information fetched by a new client with the given config. +func NewDiscoveryRESTMapper(c *rest.Config) (meta.RESTMapper, error) { + // Get a mapper + dc, err := discovery.NewDiscoveryClientForConfig(c) + if err != nil { + return nil, err + } + gr, err := restmapper.GetAPIGroupResources(dc) + if err != nil { + return nil, err + } + return restmapper.NewDiscoveryRESTMapper(gr), nil +} + +// GVKForObject finds the GroupVersionKind associated with the given object, if there is only a single such GVK. +func GVKForObject(obj runtime.Object, scheme *runtime.Scheme) (schema.GroupVersionKind, error) { + // TODO(directxman12): do we want to generalize this to arbitrary container types? + // I think we'd need a generalized form of scheme or something. It's a + // shame there's not a reliable "GetGVK" interface that works by default + // for unpopulated static types and populated "dynamic" types + // (unstructured, partial, etc) + + // check for PartialObjectMetadata, which is analogous to unstructured, but isn't handled by ObjectKinds + _, isPartial := obj.(*metav1.PartialObjectMetadata) //nolint:ifshort + _, isPartialList := obj.(*metav1.PartialObjectMetadataList) + if isPartial || isPartialList { + // we require that the GVK be populated in order to recognize the object + gvk := obj.GetObjectKind().GroupVersionKind() + if len(gvk.Kind) == 0 { + return schema.GroupVersionKind{}, runtime.NewMissingKindErr("unstructured object has no kind") + } + if len(gvk.Version) == 0 { + return schema.GroupVersionKind{}, runtime.NewMissingVersionErr("unstructured object has no version") + } + return gvk, nil + } + + gvks, isUnversioned, err := scheme.ObjectKinds(obj) + if err != nil { + return schema.GroupVersionKind{}, err + } + if isUnversioned { + return schema.GroupVersionKind{}, fmt.Errorf("cannot create group-version-kind for unversioned type %T", obj) + } + + if len(gvks) < 1 { + return schema.GroupVersionKind{}, fmt.Errorf("no group-version-kinds associated with type %T", obj) + } + if len(gvks) > 1 { + // this should only trigger for things like metav1.XYZ -- + // normal versioned types should be fine + return schema.GroupVersionKind{}, fmt.Errorf( + "multiple group-version-kinds associated with type %T, refusing to guess at one", obj) + } + return gvks[0], nil +} + +// RESTClientForGVK constructs a new rest.Interface capable of accessing the resource associated +// with the given GroupVersionKind. The REST client will be configured to use the negotiated serializer from +// baseConfig, if set, otherwise a default serializer will be set. +func RESTClientForGVK(gvk schema.GroupVersionKind, isUnstructured bool, baseConfig *rest.Config, codecs serializer.CodecFactory) (rest.Interface, error) { + return rest.RESTClientFor(createRestConfig(gvk, isUnstructured, baseConfig, codecs)) +} + +// serializerWithDecodedGVK is a CodecFactory that overrides the DecoderToVersion of a WithoutConversionCodecFactory +// in order to avoid clearing the GVK from the decoded object. +// +// See https://github.com/kubernetes/kubernetes/issues/80609. +type serializerWithDecodedGVK struct { + serializer.WithoutConversionCodecFactory +} + +// DecoderToVersion returns an decoder that does not do conversion. +func (f serializerWithDecodedGVK) DecoderToVersion(serializer runtime.Decoder, _ runtime.GroupVersioner) runtime.Decoder { + return serializer +} + +// createRestConfig copies the base config and updates needed fields for a new rest config. +func createRestConfig(gvk schema.GroupVersionKind, isUnstructured bool, baseConfig *rest.Config, codecs serializer.CodecFactory) *rest.Config { + gv := gvk.GroupVersion() + + cfg := rest.CopyConfig(baseConfig) + cfg.GroupVersion = &gv + if gvk.Group == "" { + cfg.APIPath = "/api" + } else { + cfg.APIPath = "/apis" + } + if cfg.UserAgent == "" { + cfg.UserAgent = rest.DefaultKubernetesUserAgent() + } + // TODO(FillZpp): In the long run, we want to check discovery or something to make sure that this is actually true. + if cfg.ContentType == "" && !isUnstructured { + protobufSchemeLock.RLock() + if protobufScheme.Recognizes(gvk) { + cfg.ContentType = runtime.ContentTypeProtobuf + } + protobufSchemeLock.RUnlock() + } + + if isUnstructured { + // If the object is unstructured, we need to preserve the GVK information. + // Use our own custom serializer. + cfg.NegotiatedSerializer = serializerWithDecodedGVK{serializer.WithoutConversionCodecFactory{CodecFactory: codecs}} + } else { + cfg.NegotiatedSerializer = serializerWithTargetZeroingDecode{NegotiatedSerializer: serializer.WithoutConversionCodecFactory{CodecFactory: codecs}} + } + + return cfg +} + +type serializerWithTargetZeroingDecode struct { + runtime.NegotiatedSerializer +} + +func (s serializerWithTargetZeroingDecode) DecoderToVersion(serializer runtime.Decoder, r runtime.GroupVersioner) runtime.Decoder { + return targetZeroingDecoder{upstream: s.NegotiatedSerializer.DecoderToVersion(serializer, r)} +} + +type targetZeroingDecoder struct { + upstream runtime.Decoder +} + +func (t targetZeroingDecoder) Decode(data []byte, defaults *schema.GroupVersionKind, into runtime.Object) (runtime.Object, *schema.GroupVersionKind, error) { + zero(into) + return t.upstream.Decode(data, defaults, into) +} + +// zero zeros the value of a pointer. +func zero(x interface{}) { + if x == nil { + return + } + res := reflect.ValueOf(x).Elem() + res.Set(reflect.Zero(res.Type())) +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/client/apiutil/dynamicrestmapper.go b/vendor/sigs.k8s.io/controller-runtime/pkg/client/apiutil/dynamicrestmapper.go new file mode 100644 index 0000000000..8b7c1c4b68 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/client/apiutil/dynamicrestmapper.go @@ -0,0 +1,290 @@ +/* +Copyright 2019 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package apiutil + +import ( + "sync" + "sync/atomic" + + "golang.org/x/time/rate" + "k8s.io/apimachinery/pkg/api/meta" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/client-go/discovery" + "k8s.io/client-go/rest" + "k8s.io/client-go/restmapper" +) + +// dynamicRESTMapper is a RESTMapper that dynamically discovers resource +// types at runtime. +type dynamicRESTMapper struct { + mu sync.RWMutex // protects the following fields + staticMapper meta.RESTMapper + limiter *rate.Limiter + newMapper func() (meta.RESTMapper, error) + + lazy bool + // Used for lazy init. + inited uint32 + initMtx sync.Mutex +} + +// DynamicRESTMapperOption is a functional option on the dynamicRESTMapper. +type DynamicRESTMapperOption func(*dynamicRESTMapper) error + +// WithLimiter sets the RESTMapper's underlying limiter to lim. +func WithLimiter(lim *rate.Limiter) DynamicRESTMapperOption { + return func(drm *dynamicRESTMapper) error { + drm.limiter = lim + return nil + } +} + +// WithLazyDiscovery prevents the RESTMapper from discovering REST mappings +// until an API call is made. +var WithLazyDiscovery DynamicRESTMapperOption = func(drm *dynamicRESTMapper) error { + drm.lazy = true + return nil +} + +// WithCustomMapper supports setting a custom RESTMapper refresher instead of +// the default method, which uses a discovery client. +// +// This exists mainly for testing, but can be useful if you need tighter control +// over how discovery is performed, which discovery endpoints are queried, etc. +func WithCustomMapper(newMapper func() (meta.RESTMapper, error)) DynamicRESTMapperOption { + return func(drm *dynamicRESTMapper) error { + drm.newMapper = newMapper + return nil + } +} + +// NewDynamicRESTMapper returns a dynamic RESTMapper for cfg. The dynamic +// RESTMapper dynamically discovers resource types at runtime. opts +// configure the RESTMapper. +func NewDynamicRESTMapper(cfg *rest.Config, opts ...DynamicRESTMapperOption) (meta.RESTMapper, error) { + client, err := discovery.NewDiscoveryClientForConfig(cfg) + if err != nil { + return nil, err + } + drm := &dynamicRESTMapper{ + limiter: rate.NewLimiter(rate.Limit(defaultRefillRate), defaultLimitSize), + newMapper: func() (meta.RESTMapper, error) { + groupResources, err := restmapper.GetAPIGroupResources(client) + if err != nil { + return nil, err + } + return restmapper.NewDiscoveryRESTMapper(groupResources), nil + }, + } + for _, opt := range opts { + if err = opt(drm); err != nil { + return nil, err + } + } + if !drm.lazy { + if err := drm.setStaticMapper(); err != nil { + return nil, err + } + } + return drm, nil +} + +var ( + // defaultRefilRate is the default rate at which potential calls are + // added back to the "bucket" of allowed calls. + defaultRefillRate = 5 + // defaultLimitSize is the default starting/max number of potential calls + // per second. Once a call is used, it's added back to the bucket at a rate + // of defaultRefillRate per second. + defaultLimitSize = 5 +) + +// setStaticMapper sets drm's staticMapper by querying its client, regardless +// of reload backoff. +func (drm *dynamicRESTMapper) setStaticMapper() error { + newMapper, err := drm.newMapper() + if err != nil { + return err + } + drm.staticMapper = newMapper + return nil +} + +// init initializes drm only once if drm is lazy. +func (drm *dynamicRESTMapper) init() (err error) { + // skip init if drm is not lazy or has initialized + if !drm.lazy || atomic.LoadUint32(&drm.inited) != 0 { + return nil + } + + drm.initMtx.Lock() + defer drm.initMtx.Unlock() + if drm.inited == 0 { + if err = drm.setStaticMapper(); err == nil { + atomic.StoreUint32(&drm.inited, 1) + } + } + return err +} + +// checkAndReload attempts to call the given callback, which is assumed to be dependent +// on the data in the restmapper. +// +// If the callback returns an error matching meta.IsNoMatchErr, it will attempt to reload +// the RESTMapper's data and re-call the callback once that's occurred. +// If the callback returns any other error, the function will return immediately regardless. +// +// It will take care of ensuring that reloads are rate-limited and that extraneous calls +// aren't made. If a reload would exceed the limiters rate, it returns the error return by +// the callback. +// It's thread-safe, and worries about thread-safety for the callback (so the callback does +// not need to attempt to lock the restmapper). +func (drm *dynamicRESTMapper) checkAndReload(checkNeedsReload func() error) error { + // first, check the common path -- data is fresh enough + // (use an IIFE for the lock's defer) + err := func() error { + drm.mu.RLock() + defer drm.mu.RUnlock() + + return checkNeedsReload() + }() + + needsReload := meta.IsNoMatchError(err) + if !needsReload { + return err + } + + // if the data wasn't fresh, we'll need to try and update it, so grab the lock... + drm.mu.Lock() + defer drm.mu.Unlock() + + // ... and double-check that we didn't reload in the meantime + err = checkNeedsReload() + needsReload = meta.IsNoMatchError(err) + if !needsReload { + return err + } + + // we're still stale, so grab a rate-limit token if we can... + if !drm.limiter.Allow() { + // return error from static mapper here, we have refreshed often enough (exceeding rate of provided limiter) + // so that client's can handle this the same way as a "normal" NoResourceMatchError / NoKindMatchError + return err + } + + // ...reload... + if err := drm.setStaticMapper(); err != nil { + return err + } + + // ...and return the results of the closure regardless + return checkNeedsReload() +} + +// TODO: wrap reload errors on NoKindMatchError with go 1.13 errors. + +func (drm *dynamicRESTMapper) KindFor(resource schema.GroupVersionResource) (schema.GroupVersionKind, error) { + if err := drm.init(); err != nil { + return schema.GroupVersionKind{}, err + } + var gvk schema.GroupVersionKind + err := drm.checkAndReload(func() error { + var err error + gvk, err = drm.staticMapper.KindFor(resource) + return err + }) + return gvk, err +} + +func (drm *dynamicRESTMapper) KindsFor(resource schema.GroupVersionResource) ([]schema.GroupVersionKind, error) { + if err := drm.init(); err != nil { + return nil, err + } + var gvks []schema.GroupVersionKind + err := drm.checkAndReload(func() error { + var err error + gvks, err = drm.staticMapper.KindsFor(resource) + return err + }) + return gvks, err +} + +func (drm *dynamicRESTMapper) ResourceFor(input schema.GroupVersionResource) (schema.GroupVersionResource, error) { + if err := drm.init(); err != nil { + return schema.GroupVersionResource{}, err + } + + var gvr schema.GroupVersionResource + err := drm.checkAndReload(func() error { + var err error + gvr, err = drm.staticMapper.ResourceFor(input) + return err + }) + return gvr, err +} + +func (drm *dynamicRESTMapper) ResourcesFor(input schema.GroupVersionResource) ([]schema.GroupVersionResource, error) { + if err := drm.init(); err != nil { + return nil, err + } + var gvrs []schema.GroupVersionResource + err := drm.checkAndReload(func() error { + var err error + gvrs, err = drm.staticMapper.ResourcesFor(input) + return err + }) + return gvrs, err +} + +func (drm *dynamicRESTMapper) RESTMapping(gk schema.GroupKind, versions ...string) (*meta.RESTMapping, error) { + if err := drm.init(); err != nil { + return nil, err + } + var mapping *meta.RESTMapping + err := drm.checkAndReload(func() error { + var err error + mapping, err = drm.staticMapper.RESTMapping(gk, versions...) + return err + }) + return mapping, err +} + +func (drm *dynamicRESTMapper) RESTMappings(gk schema.GroupKind, versions ...string) ([]*meta.RESTMapping, error) { + if err := drm.init(); err != nil { + return nil, err + } + var mappings []*meta.RESTMapping + err := drm.checkAndReload(func() error { + var err error + mappings, err = drm.staticMapper.RESTMappings(gk, versions...) + return err + }) + return mappings, err +} + +func (drm *dynamicRESTMapper) ResourceSingularizer(resource string) (string, error) { + if err := drm.init(); err != nil { + return "", err + } + var singular string + err := drm.checkAndReload(func() error { + var err error + singular, err = drm.staticMapper.ResourceSingularizer(resource) + return err + }) + return singular, err +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/client/client.go b/vendor/sigs.k8s.io/controller-runtime/pkg/client/client.go new file mode 100644 index 0000000000..730e0ba910 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/client/client.go @@ -0,0 +1,327 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package client + +import ( + "context" + "fmt" + "strings" + + "k8s.io/apimachinery/pkg/api/meta" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/runtime/serializer" + "k8s.io/client-go/kubernetes/scheme" + "k8s.io/client-go/metadata" + "k8s.io/client-go/rest" + + "sigs.k8s.io/controller-runtime/pkg/client/apiutil" + "sigs.k8s.io/controller-runtime/pkg/log" +) + +// WarningHandlerOptions are options for configuring a +// warning handler for the client which is responsible +// for surfacing API Server warnings. +type WarningHandlerOptions struct { + // SuppressWarnings decides if the warnings from the + // API server are suppressed or surfaced in the client. + SuppressWarnings bool + // AllowDuplicateLogs does not deduplicate the to-be + // logged surfaced warnings messages. See + // log.WarningHandlerOptions for considerations + // regarding deduplication + AllowDuplicateLogs bool +} + +// Options are creation options for a Client. +type Options struct { + // Scheme, if provided, will be used to map go structs to GroupVersionKinds + Scheme *runtime.Scheme + + // Mapper, if provided, will be used to map GroupVersionKinds to Resources + Mapper meta.RESTMapper + + // Opts is used to configure the warning handler responsible for + // surfacing and handling warnings messages sent by the API server. + Opts WarningHandlerOptions +} + +// New returns a new Client using the provided config and Options. +// The returned client reads *and* writes directly from the server +// (it doesn't use object caches). It understands how to work with +// normal types (both custom resources and aggregated/built-in resources), +// as well as unstructured types. +// +// In the case of normal types, the scheme will be used to look up the +// corresponding group, version, and kind for the given type. In the +// case of unstructured types, the group, version, and kind will be extracted +// from the corresponding fields on the object. +func New(config *rest.Config, options Options) (Client, error) { + return newClient(config, options) +} + +func newClient(config *rest.Config, options Options) (*client, error) { + if config == nil { + return nil, fmt.Errorf("must provide non-nil rest.Config to client.New") + } + + if !options.Opts.SuppressWarnings { + // surface warnings + logger := log.Log.WithName("KubeAPIWarningLogger") + // Set a WarningHandler, the default WarningHandler + // is log.KubeAPIWarningLogger with deduplication enabled. + // See log.KubeAPIWarningLoggerOptions for considerations + // regarding deduplication. + config = rest.CopyConfig(config) + config.WarningHandler = log.NewKubeAPIWarningLogger( + logger, + log.KubeAPIWarningLoggerOptions{ + Deduplicate: !options.Opts.AllowDuplicateLogs, + }, + ) + } + + // Init a scheme if none provided + if options.Scheme == nil { + options.Scheme = scheme.Scheme + } + + // Init a Mapper if none provided + if options.Mapper == nil { + var err error + options.Mapper, err = apiutil.NewDynamicRESTMapper(config) + if err != nil { + return nil, err + } + } + + clientcache := &clientCache{ + config: config, + scheme: options.Scheme, + mapper: options.Mapper, + codecs: serializer.NewCodecFactory(options.Scheme), + + structuredResourceByType: make(map[schema.GroupVersionKind]*resourceMeta), + unstructuredResourceByType: make(map[schema.GroupVersionKind]*resourceMeta), + } + + rawMetaClient, err := metadata.NewForConfig(config) + if err != nil { + return nil, fmt.Errorf("unable to construct metadata-only client for use as part of client: %w", err) + } + + c := &client{ + typedClient: typedClient{ + cache: clientcache, + paramCodec: runtime.NewParameterCodec(options.Scheme), + }, + unstructuredClient: unstructuredClient{ + cache: clientcache, + paramCodec: noConversionParamCodec{}, + }, + metadataClient: metadataClient{ + client: rawMetaClient, + restMapper: options.Mapper, + }, + scheme: options.Scheme, + mapper: options.Mapper, + } + + return c, nil +} + +var _ Client = &client{} + +// client is a client.Client that reads and writes directly from/to an API server. It lazily initializes +// new clients at the time they are used, and caches the client. +type client struct { + typedClient typedClient + unstructuredClient unstructuredClient + metadataClient metadataClient + scheme *runtime.Scheme + mapper meta.RESTMapper +} + +// resetGroupVersionKind is a helper function to restore and preserve GroupVersionKind on an object. +func (c *client) resetGroupVersionKind(obj runtime.Object, gvk schema.GroupVersionKind) { + if gvk != schema.EmptyObjectKind.GroupVersionKind() { + if v, ok := obj.(schema.ObjectKind); ok { + v.SetGroupVersionKind(gvk) + } + } +} + +// Scheme returns the scheme this client is using. +func (c *client) Scheme() *runtime.Scheme { + return c.scheme +} + +// RESTMapper returns the scheme this client is using. +func (c *client) RESTMapper() meta.RESTMapper { + return c.mapper +} + +// Create implements client.Client. +func (c *client) Create(ctx context.Context, obj Object, opts ...CreateOption) error { + switch obj.(type) { + case *unstructured.Unstructured: + return c.unstructuredClient.Create(ctx, obj, opts...) + case *metav1.PartialObjectMetadata: + return fmt.Errorf("cannot create using only metadata") + default: + return c.typedClient.Create(ctx, obj, opts...) + } +} + +// Update implements client.Client. +func (c *client) Update(ctx context.Context, obj Object, opts ...UpdateOption) error { + defer c.resetGroupVersionKind(obj, obj.GetObjectKind().GroupVersionKind()) + switch obj.(type) { + case *unstructured.Unstructured: + return c.unstructuredClient.Update(ctx, obj, opts...) + case *metav1.PartialObjectMetadata: + return fmt.Errorf("cannot update using only metadata -- did you mean to patch?") + default: + return c.typedClient.Update(ctx, obj, opts...) + } +} + +// Delete implements client.Client. +func (c *client) Delete(ctx context.Context, obj Object, opts ...DeleteOption) error { + switch obj.(type) { + case *unstructured.Unstructured: + return c.unstructuredClient.Delete(ctx, obj, opts...) + case *metav1.PartialObjectMetadata: + return c.metadataClient.Delete(ctx, obj, opts...) + default: + return c.typedClient.Delete(ctx, obj, opts...) + } +} + +// DeleteAllOf implements client.Client. +func (c *client) DeleteAllOf(ctx context.Context, obj Object, opts ...DeleteAllOfOption) error { + switch obj.(type) { + case *unstructured.Unstructured: + return c.unstructuredClient.DeleteAllOf(ctx, obj, opts...) + case *metav1.PartialObjectMetadata: + return c.metadataClient.DeleteAllOf(ctx, obj, opts...) + default: + return c.typedClient.DeleteAllOf(ctx, obj, opts...) + } +} + +// Patch implements client.Client. +func (c *client) Patch(ctx context.Context, obj Object, patch Patch, opts ...PatchOption) error { + defer c.resetGroupVersionKind(obj, obj.GetObjectKind().GroupVersionKind()) + switch obj.(type) { + case *unstructured.Unstructured: + return c.unstructuredClient.Patch(ctx, obj, patch, opts...) + case *metav1.PartialObjectMetadata: + return c.metadataClient.Patch(ctx, obj, patch, opts...) + default: + return c.typedClient.Patch(ctx, obj, patch, opts...) + } +} + +// Get implements client.Client. +func (c *client) Get(ctx context.Context, key ObjectKey, obj Object, opts ...GetOption) error { + switch obj.(type) { + case *unstructured.Unstructured: + return c.unstructuredClient.Get(ctx, key, obj, opts...) + case *metav1.PartialObjectMetadata: + // Metadata only object should always preserve the GVK coming in from the caller. + defer c.resetGroupVersionKind(obj, obj.GetObjectKind().GroupVersionKind()) + return c.metadataClient.Get(ctx, key, obj, opts...) + default: + return c.typedClient.Get(ctx, key, obj, opts...) + } +} + +// List implements client.Client. +func (c *client) List(ctx context.Context, obj ObjectList, opts ...ListOption) error { + switch x := obj.(type) { + case *unstructured.UnstructuredList: + return c.unstructuredClient.List(ctx, obj, opts...) + case *metav1.PartialObjectMetadataList: + // Metadata only object should always preserve the GVK. + gvk := obj.GetObjectKind().GroupVersionKind() + defer c.resetGroupVersionKind(obj, gvk) + + // Call the list client. + if err := c.metadataClient.List(ctx, obj, opts...); err != nil { + return err + } + + // Restore the GVK for each item in the list. + itemGVK := schema.GroupVersionKind{ + Group: gvk.Group, + Version: gvk.Version, + // TODO: this is producing unsafe guesses that don't actually work, + // but it matches ~99% of the cases out there. + Kind: strings.TrimSuffix(gvk.Kind, "List"), + } + for i := range x.Items { + item := &x.Items[i] + item.SetGroupVersionKind(itemGVK) + } + + return nil + default: + return c.typedClient.List(ctx, obj, opts...) + } +} + +// Status implements client.StatusClient. +func (c *client) Status() StatusWriter { + return &statusWriter{client: c} +} + +// statusWriter is client.StatusWriter that writes status subresource. +type statusWriter struct { + client *client +} + +// ensure statusWriter implements client.StatusWriter. +var _ StatusWriter = &statusWriter{} + +// Update implements client.StatusWriter. +func (sw *statusWriter) Update(ctx context.Context, obj Object, opts ...UpdateOption) error { + defer sw.client.resetGroupVersionKind(obj, obj.GetObjectKind().GroupVersionKind()) + switch obj.(type) { + case *unstructured.Unstructured: + return sw.client.unstructuredClient.UpdateStatus(ctx, obj, opts...) + case *metav1.PartialObjectMetadata: + return fmt.Errorf("cannot update status using only metadata -- did you mean to patch?") + default: + return sw.client.typedClient.UpdateStatus(ctx, obj, opts...) + } +} + +// Patch implements client.Client. +func (sw *statusWriter) Patch(ctx context.Context, obj Object, patch Patch, opts ...PatchOption) error { + defer sw.client.resetGroupVersionKind(obj, obj.GetObjectKind().GroupVersionKind()) + switch obj.(type) { + case *unstructured.Unstructured: + return sw.client.unstructuredClient.PatchStatus(ctx, obj, patch, opts...) + case *metav1.PartialObjectMetadata: + return sw.client.metadataClient.PatchStatus(ctx, obj, patch, opts...) + default: + return sw.client.typedClient.PatchStatus(ctx, obj, patch, opts...) + } +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/client/client_cache.go b/vendor/sigs.k8s.io/controller-runtime/pkg/client/client_cache.go new file mode 100644 index 0000000000..857a0b38a7 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/client/client_cache.go @@ -0,0 +1,150 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package client + +import ( + "strings" + "sync" + + "k8s.io/apimachinery/pkg/api/meta" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/runtime/serializer" + "k8s.io/client-go/rest" + "sigs.k8s.io/controller-runtime/pkg/client/apiutil" +) + +// clientCache creates and caches rest clients and metadata for Kubernetes types. +type clientCache struct { + // config is the rest.Config to talk to an apiserver + config *rest.Config + + // scheme maps go structs to GroupVersionKinds + scheme *runtime.Scheme + + // mapper maps GroupVersionKinds to Resources + mapper meta.RESTMapper + + // codecs are used to create a REST client for a gvk + codecs serializer.CodecFactory + + // structuredResourceByType caches structured type metadata + structuredResourceByType map[schema.GroupVersionKind]*resourceMeta + // unstructuredResourceByType caches unstructured type metadata + unstructuredResourceByType map[schema.GroupVersionKind]*resourceMeta + mu sync.RWMutex +} + +// newResource maps obj to a Kubernetes Resource and constructs a client for that Resource. +// If the object is a list, the resource represents the item's type instead. +func (c *clientCache) newResource(gvk schema.GroupVersionKind, isList, isUnstructured bool) (*resourceMeta, error) { + if strings.HasSuffix(gvk.Kind, "List") && isList { + // if this was a list, treat it as a request for the item's resource + gvk.Kind = gvk.Kind[:len(gvk.Kind)-4] + } + + client, err := apiutil.RESTClientForGVK(gvk, isUnstructured, c.config, c.codecs) + if err != nil { + return nil, err + } + mapping, err := c.mapper.RESTMapping(gvk.GroupKind(), gvk.Version) + if err != nil { + return nil, err + } + return &resourceMeta{Interface: client, mapping: mapping, gvk: gvk}, nil +} + +// getResource returns the resource meta information for the given type of object. +// If the object is a list, the resource represents the item's type instead. +func (c *clientCache) getResource(obj runtime.Object) (*resourceMeta, error) { + gvk, err := apiutil.GVKForObject(obj, c.scheme) + if err != nil { + return nil, err + } + + _, isUnstructured := obj.(*unstructured.Unstructured) + _, isUnstructuredList := obj.(*unstructured.UnstructuredList) + isUnstructured = isUnstructured || isUnstructuredList + + // It's better to do creation work twice than to not let multiple + // people make requests at once + c.mu.RLock() + resourceByType := c.structuredResourceByType + if isUnstructured { + resourceByType = c.unstructuredResourceByType + } + r, known := resourceByType[gvk] + c.mu.RUnlock() + + if known { + return r, nil + } + + // Initialize a new Client + c.mu.Lock() + defer c.mu.Unlock() + r, err = c.newResource(gvk, meta.IsListType(obj), isUnstructured) + if err != nil { + return nil, err + } + resourceByType[gvk] = r + return r, err +} + +// getObjMeta returns objMeta containing both type and object metadata and state. +func (c *clientCache) getObjMeta(obj runtime.Object) (*objMeta, error) { + r, err := c.getResource(obj) + if err != nil { + return nil, err + } + m, err := meta.Accessor(obj) + if err != nil { + return nil, err + } + return &objMeta{resourceMeta: r, Object: m}, err +} + +// resourceMeta caches state for a Kubernetes type. +type resourceMeta struct { + // client is the rest client used to talk to the apiserver + rest.Interface + // gvk is the GroupVersionKind of the resourceMeta + gvk schema.GroupVersionKind + // mapping is the rest mapping + mapping *meta.RESTMapping +} + +// isNamespaced returns true if the type is namespaced. +func (r *resourceMeta) isNamespaced() bool { + return r.mapping.Scope.Name() != meta.RESTScopeNameRoot +} + +// resource returns the resource name of the type. +func (r *resourceMeta) resource() string { + return r.mapping.Resource.Resource +} + +// objMeta stores type and object information about a Kubernetes type. +type objMeta struct { + // resourceMeta contains type information for the object + *resourceMeta + + // Object contains meta data for the object instance + metav1.Object +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/client/codec.go b/vendor/sigs.k8s.io/controller-runtime/pkg/client/codec.go new file mode 100644 index 0000000000..9c2923106c --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/client/codec.go @@ -0,0 +1,40 @@ +/* +Copyright 2021 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package client + +import ( + "errors" + "net/url" + + "k8s.io/apimachinery/pkg/conversion/queryparams" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +var _ runtime.ParameterCodec = noConversionParamCodec{} + +// noConversionParamCodec is a no-conversion codec for serializing parameters into URL query strings. +// it's useful in scenarios with the unstructured client and arbitrary resources. +type noConversionParamCodec struct{} + +func (noConversionParamCodec) EncodeParameters(obj runtime.Object, to schema.GroupVersion) (url.Values, error) { + return queryparams.Convert(obj) +} + +func (noConversionParamCodec) DecodeParameters(parameters url.Values, from schema.GroupVersion, into runtime.Object) error { + return errors.New("DecodeParameters not implemented on noConversionParamCodec") +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/client/config/config.go b/vendor/sigs.k8s.io/controller-runtime/pkg/client/config/config.go new file mode 100644 index 0000000000..ff44a225fe --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/client/config/config.go @@ -0,0 +1,157 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package config + +import ( + "flag" + "fmt" + "os" + "os/user" + "path/filepath" + + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/clientcmd" + clientcmdapi "k8s.io/client-go/tools/clientcmd/api" + logf "sigs.k8s.io/controller-runtime/pkg/internal/log" +) + +var ( + kubeconfig string + log = logf.RuntimeLog.WithName("client").WithName("config") +) + +func init() { + // TODO: Fix this to allow double vendoring this library but still register flags on behalf of users + flag.StringVar(&kubeconfig, "kubeconfig", "", + "Paths to a kubeconfig. Only required if out-of-cluster.") +} + +// GetConfig creates a *rest.Config for talking to a Kubernetes API server. +// If --kubeconfig is set, will use the kubeconfig file at that location. Otherwise will assume running +// in cluster and use the cluster provided kubeconfig. +// +// It also applies saner defaults for QPS and burst based on the Kubernetes +// controller manager defaults (20 QPS, 30 burst) +// +// Config precedence: +// +// * --kubeconfig flag pointing at a file +// +// * KUBECONFIG environment variable pointing at a file +// +// * In-cluster config if running in cluster +// +// * $HOME/.kube/config if exists. +func GetConfig() (*rest.Config, error) { + return GetConfigWithContext("") +} + +// GetConfigWithContext creates a *rest.Config for talking to a Kubernetes API server with a specific context. +// If --kubeconfig is set, will use the kubeconfig file at that location. Otherwise will assume running +// in cluster and use the cluster provided kubeconfig. +// +// It also applies saner defaults for QPS and burst based on the Kubernetes +// controller manager defaults (20 QPS, 30 burst) +// +// Config precedence: +// +// * --kubeconfig flag pointing at a file +// +// * KUBECONFIG environment variable pointing at a file +// +// * In-cluster config if running in cluster +// +// * $HOME/.kube/config if exists. +func GetConfigWithContext(context string) (*rest.Config, error) { + cfg, err := loadConfig(context) + if err != nil { + return nil, err + } + + if cfg.QPS == 0.0 { + cfg.QPS = 20.0 + cfg.Burst = 30.0 + } + + return cfg, nil +} + +// loadInClusterConfig is a function used to load the in-cluster +// Kubernetes client config. This variable makes is possible to +// test the precedence of loading the config. +var loadInClusterConfig = rest.InClusterConfig + +// loadConfig loads a REST Config as per the rules specified in GetConfig. +func loadConfig(context string) (*rest.Config, error) { + // If a flag is specified with the config location, use that + if len(kubeconfig) > 0 { + return loadConfigWithContext("", &clientcmd.ClientConfigLoadingRules{ExplicitPath: kubeconfig}, context) + } + + // If the recommended kubeconfig env variable is not specified, + // try the in-cluster config. + kubeconfigPath := os.Getenv(clientcmd.RecommendedConfigPathEnvVar) + if len(kubeconfigPath) == 0 { + if c, err := loadInClusterConfig(); err == nil { + return c, nil + } + } + + // If the recommended kubeconfig env variable is set, or there + // is no in-cluster config, try the default recommended locations. + // + // NOTE: For default config file locations, upstream only checks + // $HOME for the user's home directory, but we can also try + // os/user.HomeDir when $HOME is unset. + // + // TODO(jlanford): could this be done upstream? + loadingRules := clientcmd.NewDefaultClientConfigLoadingRules() + if _, ok := os.LookupEnv("HOME"); !ok { + u, err := user.Current() + if err != nil { + return nil, fmt.Errorf("could not get current user: %w", err) + } + loadingRules.Precedence = append(loadingRules.Precedence, filepath.Join(u.HomeDir, clientcmd.RecommendedHomeDir, clientcmd.RecommendedFileName)) + } + + return loadConfigWithContext("", loadingRules, context) +} + +func loadConfigWithContext(apiServerURL string, loader clientcmd.ClientConfigLoader, context string) (*rest.Config, error) { + return clientcmd.NewNonInteractiveDeferredLoadingClientConfig( + loader, + &clientcmd.ConfigOverrides{ + ClusterInfo: clientcmdapi.Cluster{ + Server: apiServerURL, + }, + CurrentContext: context, + }).ClientConfig() +} + +// GetConfigOrDie creates a *rest.Config for talking to a Kubernetes apiserver. +// If --kubeconfig is set, will use the kubeconfig file at that location. Otherwise will assume running +// in cluster and use the cluster provided kubeconfig. +// +// Will log an error and exit if there is an error creating the rest.Config. +func GetConfigOrDie() *rest.Config { + config, err := GetConfig() + if err != nil { + log.Error(err, "unable to get kubeconfig") + os.Exit(1) + } + return config +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/client/config/doc.go b/vendor/sigs.k8s.io/controller-runtime/pkg/client/config/doc.go new file mode 100644 index 0000000000..796c9cf590 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/client/config/doc.go @@ -0,0 +1,18 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package config contains libraries for initializing REST configs for talking to the Kubernetes API +package config diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/client/doc.go b/vendor/sigs.k8s.io/controller-runtime/pkg/client/doc.go new file mode 100644 index 0000000000..e0e2885094 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/client/doc.go @@ -0,0 +1,50 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package client contains functionality for interacting with Kubernetes API +// servers. +// +// # Clients +// +// Clients are split into two interfaces -- Readers and Writers. Readers +// get and list, while writers create, update, and delete. +// +// The New function can be used to create a new client that talks directly +// to the API server. +// +// It is a common pattern in Kubernetes to read from a cache and write to the API +// server. This pattern is covered by the DelegatingClient type, which can +// be used to have a client whose Reader is different from the Writer. +// +// # Options +// +// Many client operations in Kubernetes support options. These options are +// represented as variadic arguments at the end of a given method call. +// For instance, to use a label selector on list, you can call +// +// err := someReader.List(context.Background(), &podList, client.MatchingLabels{"somelabel": "someval"}) +// +// # Indexing +// +// Indexes may be added to caches using a FieldIndexer. This allows you to easily +// and efficiently look up objects with certain properties. You can then make +// use of the index by specifying a field selector on calls to List on the Reader +// corresponding to the given Cache. +// +// For instance, a Secret controller might have an index on the +// `.spec.volumes.secret.secretName` field in Pod objects, so that it could +// easily look up all pods that reference a given secret. +package client diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/client/dryrun.go b/vendor/sigs.k8s.io/controller-runtime/pkg/client/dryrun.go new file mode 100644 index 0000000000..14606a5794 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/client/dryrun.go @@ -0,0 +1,106 @@ +/* +Copyright 2020 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package client + +import ( + "context" + + "k8s.io/apimachinery/pkg/api/meta" + "k8s.io/apimachinery/pkg/runtime" +) + +// NewDryRunClient wraps an existing client and enforces DryRun mode +// on all mutating api calls. +func NewDryRunClient(c Client) Client { + return &dryRunClient{client: c} +} + +var _ Client = &dryRunClient{} + +// dryRunClient is a Client that wraps another Client in order to enforce DryRun mode. +type dryRunClient struct { + client Client +} + +// Scheme returns the scheme this client is using. +func (c *dryRunClient) Scheme() *runtime.Scheme { + return c.client.Scheme() +} + +// RESTMapper returns the rest mapper this client is using. +func (c *dryRunClient) RESTMapper() meta.RESTMapper { + return c.client.RESTMapper() +} + +// Create implements client.Client. +func (c *dryRunClient) Create(ctx context.Context, obj Object, opts ...CreateOption) error { + return c.client.Create(ctx, obj, append(opts, DryRunAll)...) +} + +// Update implements client.Client. +func (c *dryRunClient) Update(ctx context.Context, obj Object, opts ...UpdateOption) error { + return c.client.Update(ctx, obj, append(opts, DryRunAll)...) +} + +// Delete implements client.Client. +func (c *dryRunClient) Delete(ctx context.Context, obj Object, opts ...DeleteOption) error { + return c.client.Delete(ctx, obj, append(opts, DryRunAll)...) +} + +// DeleteAllOf implements client.Client. +func (c *dryRunClient) DeleteAllOf(ctx context.Context, obj Object, opts ...DeleteAllOfOption) error { + return c.client.DeleteAllOf(ctx, obj, append(opts, DryRunAll)...) +} + +// Patch implements client.Client. +func (c *dryRunClient) Patch(ctx context.Context, obj Object, patch Patch, opts ...PatchOption) error { + return c.client.Patch(ctx, obj, patch, append(opts, DryRunAll)...) +} + +// Get implements client.Client. +func (c *dryRunClient) Get(ctx context.Context, key ObjectKey, obj Object, opts ...GetOption) error { + return c.client.Get(ctx, key, obj, opts...) +} + +// List implements client.Client. +func (c *dryRunClient) List(ctx context.Context, obj ObjectList, opts ...ListOption) error { + return c.client.List(ctx, obj, opts...) +} + +// Status implements client.StatusClient. +func (c *dryRunClient) Status() StatusWriter { + return &dryRunStatusWriter{client: c.client.Status()} +} + +// ensure dryRunStatusWriter implements client.StatusWriter. +var _ StatusWriter = &dryRunStatusWriter{} + +// dryRunStatusWriter is client.StatusWriter that writes status subresource with dryRun mode +// enforced. +type dryRunStatusWriter struct { + client StatusWriter +} + +// Update implements client.StatusWriter. +func (sw *dryRunStatusWriter) Update(ctx context.Context, obj Object, opts ...UpdateOption) error { + return sw.client.Update(ctx, obj, append(opts, DryRunAll)...) +} + +// Patch implements client.StatusWriter. +func (sw *dryRunStatusWriter) Patch(ctx context.Context, obj Object, patch Patch, opts ...PatchOption) error { + return sw.client.Patch(ctx, obj, patch, append(opts, DryRunAll)...) +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/client/interfaces.go b/vendor/sigs.k8s.io/controller-runtime/pkg/client/interfaces.go new file mode 100644 index 0000000000..7f8f8f31c6 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/client/interfaces.go @@ -0,0 +1,155 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package client + +import ( + "context" + + apierrors "k8s.io/apimachinery/pkg/api/errors" + + "k8s.io/apimachinery/pkg/api/meta" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/watch" +) + +// ObjectKey identifies a Kubernetes Object. +type ObjectKey = types.NamespacedName + +// ObjectKeyFromObject returns the ObjectKey given a runtime.Object. +func ObjectKeyFromObject(obj Object) ObjectKey { + return ObjectKey{Namespace: obj.GetNamespace(), Name: obj.GetName()} +} + +// Patch is a patch that can be applied to a Kubernetes object. +type Patch interface { + // Type is the PatchType of the patch. + Type() types.PatchType + // Data is the raw data representing the patch. + Data(obj Object) ([]byte, error) +} + +// TODO(directxman12): is there a sane way to deal with get/delete options? + +// Reader knows how to read and list Kubernetes objects. +type Reader interface { + // Get retrieves an obj for the given object key from the Kubernetes Cluster. + // obj must be a struct pointer so that obj can be updated with the response + // returned by the Server. + Get(ctx context.Context, key ObjectKey, obj Object, opts ...GetOption) error + + // List retrieves list of objects for a given namespace and list options. On a + // successful call, Items field in the list will be populated with the + // result returned from the server. + List(ctx context.Context, list ObjectList, opts ...ListOption) error +} + +// Writer knows how to create, delete, and update Kubernetes objects. +type Writer interface { + // Create saves the object obj in the Kubernetes cluster. + Create(ctx context.Context, obj Object, opts ...CreateOption) error + + // Delete deletes the given obj from Kubernetes cluster. + Delete(ctx context.Context, obj Object, opts ...DeleteOption) error + + // Update updates the given obj in the Kubernetes cluster. obj must be a + // struct pointer so that obj can be updated with the content returned by the Server. + Update(ctx context.Context, obj Object, opts ...UpdateOption) error + + // Patch patches the given obj in the Kubernetes cluster. obj must be a + // struct pointer so that obj can be updated with the content returned by the Server. + Patch(ctx context.Context, obj Object, patch Patch, opts ...PatchOption) error + + // DeleteAllOf deletes all objects of the given type matching the given options. + DeleteAllOf(ctx context.Context, obj Object, opts ...DeleteAllOfOption) error +} + +// StatusClient knows how to create a client which can update status subresource +// for kubernetes objects. +type StatusClient interface { + Status() StatusWriter +} + +// StatusWriter knows how to update status subresource of a Kubernetes object. +type StatusWriter interface { + // Update updates the fields corresponding to the status subresource for the + // given obj. obj must be a struct pointer so that obj can be updated + // with the content returned by the Server. + Update(ctx context.Context, obj Object, opts ...UpdateOption) error + + // Patch patches the given object's subresource. obj must be a struct + // pointer so that obj can be updated with the content returned by the + // Server. + Patch(ctx context.Context, obj Object, patch Patch, opts ...PatchOption) error +} + +// Client knows how to perform CRUD operations on Kubernetes objects. +type Client interface { + Reader + Writer + StatusClient + + // Scheme returns the scheme this client is using. + Scheme() *runtime.Scheme + // RESTMapper returns the rest this client is using. + RESTMapper() meta.RESTMapper +} + +// WithWatch supports Watch on top of the CRUD operations supported by +// the normal Client. Its intended use-case are CLI apps that need to wait for +// events. +type WithWatch interface { + Client + Watch(ctx context.Context, obj ObjectList, opts ...ListOption) (watch.Interface, error) +} + +// IndexerFunc knows how to take an object and turn it into a series +// of non-namespaced keys. Namespaced objects are automatically given +// namespaced and non-spaced variants, so keys do not need to include namespace. +type IndexerFunc func(Object) []string + +// FieldIndexer knows how to index over a particular "field" such that it +// can later be used by a field selector. +type FieldIndexer interface { + // IndexFields adds an index with the given field name on the given object type + // by using the given function to extract the value for that field. If you want + // compatibility with the Kubernetes API server, only return one key, and only use + // fields that the API server supports. Otherwise, you can return multiple keys, + // and "equality" in the field selector means that at least one key matches the value. + // The FieldIndexer will automatically take care of indexing over namespace + // and supporting efficient all-namespace queries. + IndexField(ctx context.Context, obj Object, field string, extractValue IndexerFunc) error +} + +// IgnoreNotFound returns nil on NotFound errors. +// All other values that are not NotFound errors or nil are returned unmodified. +func IgnoreNotFound(err error) error { + if apierrors.IsNotFound(err) { + return nil + } + return err +} + +// IgnoreAlreadyExists returns nil on AlreadyExists errors. +// All other values that are not AlreadyExists errors or nil are returned unmodified. +func IgnoreAlreadyExists(err error) error { + if apierrors.IsAlreadyExists(err) { + return nil + } + + return err +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/client/metadata_client.go b/vendor/sigs.k8s.io/controller-runtime/pkg/client/metadata_client.go new file mode 100644 index 0000000000..2854556f32 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/client/metadata_client.go @@ -0,0 +1,196 @@ +/* +Copyright 2020 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package client + +import ( + "context" + "fmt" + "strings" + + "k8s.io/apimachinery/pkg/api/meta" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/client-go/metadata" +) + +// TODO(directxman12): we could rewrite this on top of the low-level REST +// client to avoid the extra shallow copy at the end, but I'm not sure it's +// worth it -- the metadata client deals with falling back to loading the whole +// object on older API servers, etc, and we'd have to reproduce that. + +// metadataClient is a client that reads & writes metadata-only requests to/from the API server. +type metadataClient struct { + client metadata.Interface + restMapper meta.RESTMapper +} + +func (mc *metadataClient) getResourceInterface(gvk schema.GroupVersionKind, ns string) (metadata.ResourceInterface, error) { + mapping, err := mc.restMapper.RESTMapping(gvk.GroupKind(), gvk.Version) + if err != nil { + return nil, err + } + if mapping.Scope.Name() == meta.RESTScopeNameRoot { + return mc.client.Resource(mapping.Resource), nil + } + return mc.client.Resource(mapping.Resource).Namespace(ns), nil +} + +// Delete implements client.Client. +func (mc *metadataClient) Delete(ctx context.Context, obj Object, opts ...DeleteOption) error { + metadata, ok := obj.(*metav1.PartialObjectMetadata) + if !ok { + return fmt.Errorf("metadata client did not understand object: %T", obj) + } + + resInt, err := mc.getResourceInterface(metadata.GroupVersionKind(), metadata.Namespace) + if err != nil { + return err + } + + deleteOpts := DeleteOptions{} + deleteOpts.ApplyOptions(opts) + + return resInt.Delete(ctx, metadata.Name, *deleteOpts.AsDeleteOptions()) +} + +// DeleteAllOf implements client.Client. +func (mc *metadataClient) DeleteAllOf(ctx context.Context, obj Object, opts ...DeleteAllOfOption) error { + metadata, ok := obj.(*metav1.PartialObjectMetadata) + if !ok { + return fmt.Errorf("metadata client did not understand object: %T", obj) + } + + deleteAllOfOpts := DeleteAllOfOptions{} + deleteAllOfOpts.ApplyOptions(opts) + + resInt, err := mc.getResourceInterface(metadata.GroupVersionKind(), deleteAllOfOpts.ListOptions.Namespace) + if err != nil { + return err + } + + return resInt.DeleteCollection(ctx, *deleteAllOfOpts.AsDeleteOptions(), *deleteAllOfOpts.AsListOptions()) +} + +// Patch implements client.Client. +func (mc *metadataClient) Patch(ctx context.Context, obj Object, patch Patch, opts ...PatchOption) error { + metadata, ok := obj.(*metav1.PartialObjectMetadata) + if !ok { + return fmt.Errorf("metadata client did not understand object: %T", obj) + } + + gvk := metadata.GroupVersionKind() + resInt, err := mc.getResourceInterface(gvk, metadata.Namespace) + if err != nil { + return err + } + + data, err := patch.Data(obj) + if err != nil { + return err + } + + patchOpts := &PatchOptions{} + patchOpts.ApplyOptions(opts) + + res, err := resInt.Patch(ctx, metadata.Name, patch.Type(), data, *patchOpts.AsPatchOptions()) + if err != nil { + return err + } + *metadata = *res + metadata.SetGroupVersionKind(gvk) // restore the GVK, which isn't set on metadata + return nil +} + +// Get implements client.Client. +func (mc *metadataClient) Get(ctx context.Context, key ObjectKey, obj Object, opts ...GetOption) error { + metadata, ok := obj.(*metav1.PartialObjectMetadata) + if !ok { + return fmt.Errorf("metadata client did not understand object: %T", obj) + } + + gvk := metadata.GroupVersionKind() + + getOpts := GetOptions{} + getOpts.ApplyOptions(opts) + + resInt, err := mc.getResourceInterface(gvk, key.Namespace) + if err != nil { + return err + } + + res, err := resInt.Get(ctx, key.Name, *getOpts.AsGetOptions()) + if err != nil { + return err + } + *metadata = *res + metadata.SetGroupVersionKind(gvk) // restore the GVK, which isn't set on metadata + return nil +} + +// List implements client.Client. +func (mc *metadataClient) List(ctx context.Context, obj ObjectList, opts ...ListOption) error { + metadata, ok := obj.(*metav1.PartialObjectMetadataList) + if !ok { + return fmt.Errorf("metadata client did not understand object: %T", obj) + } + + gvk := metadata.GroupVersionKind() + gvk.Kind = strings.TrimSuffix(gvk.Kind, "List") + + listOpts := ListOptions{} + listOpts.ApplyOptions(opts) + + resInt, err := mc.getResourceInterface(gvk, listOpts.Namespace) + if err != nil { + return err + } + + res, err := resInt.List(ctx, *listOpts.AsListOptions()) + if err != nil { + return err + } + *metadata = *res + metadata.SetGroupVersionKind(gvk) // restore the GVK, which isn't set on metadata + return nil +} + +func (mc *metadataClient) PatchStatus(ctx context.Context, obj Object, patch Patch, opts ...PatchOption) error { + metadata, ok := obj.(*metav1.PartialObjectMetadata) + if !ok { + return fmt.Errorf("metadata client did not understand object: %T", obj) + } + + gvk := metadata.GroupVersionKind() + resInt, err := mc.getResourceInterface(gvk, metadata.Namespace) + if err != nil { + return err + } + + data, err := patch.Data(obj) + if err != nil { + return err + } + + patchOpts := &PatchOptions{} + res, err := resInt.Patch(ctx, metadata.Name, patch.Type(), data, *patchOpts.AsPatchOptions(), "status") + if err != nil { + return err + } + *metadata = *res + metadata.SetGroupVersionKind(gvk) // restore the GVK, which isn't set on metadata + return nil +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/client/namespaced_client.go b/vendor/sigs.k8s.io/controller-runtime/pkg/client/namespaced_client.go new file mode 100644 index 0000000000..674fe253d8 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/client/namespaced_client.go @@ -0,0 +1,213 @@ +/* +Copyright 2020 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package client + +import ( + "context" + "fmt" + + "k8s.io/apimachinery/pkg/api/meta" + "k8s.io/apimachinery/pkg/runtime" + "sigs.k8s.io/controller-runtime/pkg/internal/objectutil" +) + +// NewNamespacedClient wraps an existing client enforcing the namespace value. +// All functions using this client will have the same namespace declared here. +func NewNamespacedClient(c Client, ns string) Client { + return &namespacedClient{ + client: c, + namespace: ns, + } +} + +var _ Client = &namespacedClient{} + +// namespacedClient is a Client that wraps another Client in order to enforce the specified namespace value. +type namespacedClient struct { + namespace string + client Client +} + +// Scheme returns the scheme this client is using. +func (n *namespacedClient) Scheme() *runtime.Scheme { + return n.client.Scheme() +} + +// RESTMapper returns the scheme this client is using. +func (n *namespacedClient) RESTMapper() meta.RESTMapper { + return n.client.RESTMapper() +} + +// Create implements client.Client. +func (n *namespacedClient) Create(ctx context.Context, obj Object, opts ...CreateOption) error { + isNamespaceScoped, err := objectutil.IsAPINamespaced(obj, n.Scheme(), n.RESTMapper()) + if err != nil { + return fmt.Errorf("error finding the scope of the object: %w", err) + } + + objectNamespace := obj.GetNamespace() + if objectNamespace != n.namespace && objectNamespace != "" { + return fmt.Errorf("namespace %s of the object %s does not match the namespace %s on the client", objectNamespace, obj.GetName(), n.namespace) + } + + if isNamespaceScoped && objectNamespace == "" { + obj.SetNamespace(n.namespace) + } + return n.client.Create(ctx, obj, opts...) +} + +// Update implements client.Client. +func (n *namespacedClient) Update(ctx context.Context, obj Object, opts ...UpdateOption) error { + isNamespaceScoped, err := objectutil.IsAPINamespaced(obj, n.Scheme(), n.RESTMapper()) + if err != nil { + return fmt.Errorf("error finding the scope of the object: %w", err) + } + + objectNamespace := obj.GetNamespace() + if objectNamespace != n.namespace && objectNamespace != "" { + return fmt.Errorf("namespace %s of the object %s does not match the namespace %s on the client", objectNamespace, obj.GetName(), n.namespace) + } + + if isNamespaceScoped && objectNamespace == "" { + obj.SetNamespace(n.namespace) + } + return n.client.Update(ctx, obj, opts...) +} + +// Delete implements client.Client. +func (n *namespacedClient) Delete(ctx context.Context, obj Object, opts ...DeleteOption) error { + isNamespaceScoped, err := objectutil.IsAPINamespaced(obj, n.Scheme(), n.RESTMapper()) + if err != nil { + return fmt.Errorf("error finding the scope of the object: %w", err) + } + + objectNamespace := obj.GetNamespace() + if objectNamespace != n.namespace && objectNamespace != "" { + return fmt.Errorf("namespace %s of the object %s does not match the namespace %s on the client", objectNamespace, obj.GetName(), n.namespace) + } + + if isNamespaceScoped && objectNamespace == "" { + obj.SetNamespace(n.namespace) + } + return n.client.Delete(ctx, obj, opts...) +} + +// DeleteAllOf implements client.Client. +func (n *namespacedClient) DeleteAllOf(ctx context.Context, obj Object, opts ...DeleteAllOfOption) error { + isNamespaceScoped, err := objectutil.IsAPINamespaced(obj, n.Scheme(), n.RESTMapper()) + if err != nil { + return fmt.Errorf("error finding the scope of the object: %w", err) + } + + if isNamespaceScoped { + opts = append(opts, InNamespace(n.namespace)) + } + return n.client.DeleteAllOf(ctx, obj, opts...) +} + +// Patch implements client.Client. +func (n *namespacedClient) Patch(ctx context.Context, obj Object, patch Patch, opts ...PatchOption) error { + isNamespaceScoped, err := objectutil.IsAPINamespaced(obj, n.Scheme(), n.RESTMapper()) + if err != nil { + return fmt.Errorf("error finding the scope of the object: %w", err) + } + + objectNamespace := obj.GetNamespace() + if objectNamespace != n.namespace && objectNamespace != "" { + return fmt.Errorf("namespace %s of the object %s does not match the namespace %s on the client", objectNamespace, obj.GetName(), n.namespace) + } + + if isNamespaceScoped && objectNamespace == "" { + obj.SetNamespace(n.namespace) + } + return n.client.Patch(ctx, obj, patch, opts...) +} + +// Get implements client.Client. +func (n *namespacedClient) Get(ctx context.Context, key ObjectKey, obj Object, opts ...GetOption) error { + isNamespaceScoped, err := objectutil.IsAPINamespaced(obj, n.Scheme(), n.RESTMapper()) + if err != nil { + return fmt.Errorf("error finding the scope of the object: %w", err) + } + if isNamespaceScoped { + if key.Namespace != "" && key.Namespace != n.namespace { + return fmt.Errorf("namespace %s provided for the object %s does not match the namespace %s on the client", key.Namespace, obj.GetName(), n.namespace) + } + key.Namespace = n.namespace + } + return n.client.Get(ctx, key, obj, opts...) +} + +// List implements client.Client. +func (n *namespacedClient) List(ctx context.Context, obj ObjectList, opts ...ListOption) error { + if n.namespace != "" { + opts = append(opts, InNamespace(n.namespace)) + } + return n.client.List(ctx, obj, opts...) +} + +// Status implements client.StatusClient. +func (n *namespacedClient) Status() StatusWriter { + return &namespacedClientStatusWriter{StatusClient: n.client.Status(), namespace: n.namespace, namespacedclient: n} +} + +// ensure namespacedClientStatusWriter implements client.StatusWriter. +var _ StatusWriter = &namespacedClientStatusWriter{} + +type namespacedClientStatusWriter struct { + StatusClient StatusWriter + namespace string + namespacedclient Client +} + +// Update implements client.StatusWriter. +func (nsw *namespacedClientStatusWriter) Update(ctx context.Context, obj Object, opts ...UpdateOption) error { + isNamespaceScoped, err := objectutil.IsAPINamespaced(obj, nsw.namespacedclient.Scheme(), nsw.namespacedclient.RESTMapper()) + + if err != nil { + return fmt.Errorf("error finding the scope of the object: %w", err) + } + + objectNamespace := obj.GetNamespace() + if objectNamespace != nsw.namespace && objectNamespace != "" { + return fmt.Errorf("namespace %s of the object %s does not match the namespace %s on the client", objectNamespace, obj.GetName(), nsw.namespace) + } + + if isNamespaceScoped && objectNamespace == "" { + obj.SetNamespace(nsw.namespace) + } + return nsw.StatusClient.Update(ctx, obj, opts...) +} + +// Patch implements client.StatusWriter. +func (nsw *namespacedClientStatusWriter) Patch(ctx context.Context, obj Object, patch Patch, opts ...PatchOption) error { + isNamespaceScoped, err := objectutil.IsAPINamespaced(obj, nsw.namespacedclient.Scheme(), nsw.namespacedclient.RESTMapper()) + + if err != nil { + return fmt.Errorf("error finding the scope of the object: %w", err) + } + + objectNamespace := obj.GetNamespace() + if objectNamespace != nsw.namespace && objectNamespace != "" { + return fmt.Errorf("namespace %s of the object %s does not match the namespace %s on the client", objectNamespace, obj.GetName(), nsw.namespace) + } + + if isNamespaceScoped && objectNamespace == "" { + obj.SetNamespace(nsw.namespace) + } + return nsw.StatusClient.Patch(ctx, obj, patch, opts...) +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/client/object.go b/vendor/sigs.k8s.io/controller-runtime/pkg/client/object.go new file mode 100644 index 0000000000..31e334d6c2 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/client/object.go @@ -0,0 +1,77 @@ +/* +Copyright 2020 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package client + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" +) + +// Object is a Kubernetes object, allows functions to work indistinctly with +// any resource that implements both Object interfaces. +// +// Semantically, these are objects which are both serializable (runtime.Object) +// and identifiable (metav1.Object) -- think any object which you could write +// as YAML or JSON, and then `kubectl create`. +// +// Code-wise, this means that any object which embeds both ObjectMeta (which +// provides metav1.Object) and TypeMeta (which provides half of runtime.Object) +// and has a `DeepCopyObject` implementation (the other half of runtime.Object) +// will implement this by default. +// +// For example, nearly all the built-in types are Objects, as well as all +// KubeBuilder-generated CRDs (unless you do something real funky to them). +// +// By and large, most things that implement runtime.Object also implement +// Object -- it's very rare to have *just* a runtime.Object implementation (the +// cases tend to be funky built-in types like Webhook payloads that don't have +// a `metadata` field). +// +// Notice that XYZList types are distinct: they implement ObjectList instead. +type Object interface { + metav1.Object + runtime.Object +} + +// ObjectList is a Kubernetes object list, allows functions to work +// indistinctly with any resource that implements both runtime.Object and +// metav1.ListInterface interfaces. +// +// Semantically, this is any object which may be serialized (ObjectMeta), and +// is a kubernetes list wrapper (has items, pagination fields, etc) -- think +// the wrapper used in a response from a `kubectl list --output yaml` call. +// +// Code-wise, this means that any object which embedds both ListMeta (which +// provides metav1.ListInterface) and TypeMeta (which provides half of +// runtime.Object) and has a `DeepCopyObject` implementation (the other half of +// runtime.Object) will implement this by default. +// +// For example, nearly all the built-in XYZList types are ObjectLists, as well +// as the XYZList types for all KubeBuilder-generated CRDs (unless you do +// something real funky to them). +// +// By and large, most things that are XYZList and implement runtime.Object also +// implement ObjectList -- it's very rare to have *just* a runtime.Object +// implementation (the cases tend to be funky built-in types like Webhook +// payloads that don't have a `metadata` field). +// +// This is similar to Object, which is almost always implemented by the items +// in the list themselves. +type ObjectList interface { + metav1.ListInterface + runtime.Object +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/client/options.go b/vendor/sigs.k8s.io/controller-runtime/pkg/client/options.go new file mode 100644 index 0000000000..495b86944c --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/client/options.go @@ -0,0 +1,742 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package client + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/fields" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/selection" +) + +// {{{ "Functional" Option Interfaces + +// CreateOption is some configuration that modifies options for a create request. +type CreateOption interface { + // ApplyToCreate applies this configuration to the given create options. + ApplyToCreate(*CreateOptions) +} + +// DeleteOption is some configuration that modifies options for a delete request. +type DeleteOption interface { + // ApplyToDelete applies this configuration to the given delete options. + ApplyToDelete(*DeleteOptions) +} + +// GetOption is some configuration that modifies options for a get request. +type GetOption interface { + // ApplyToGet applies this configuration to the given get options. + ApplyToGet(*GetOptions) +} + +// ListOption is some configuration that modifies options for a list request. +type ListOption interface { + // ApplyToList applies this configuration to the given list options. + ApplyToList(*ListOptions) +} + +// UpdateOption is some configuration that modifies options for a update request. +type UpdateOption interface { + // ApplyToUpdate applies this configuration to the given update options. + ApplyToUpdate(*UpdateOptions) +} + +// PatchOption is some configuration that modifies options for a patch request. +type PatchOption interface { + // ApplyToPatch applies this configuration to the given patch options. + ApplyToPatch(*PatchOptions) +} + +// DeleteAllOfOption is some configuration that modifies options for a delete request. +type DeleteAllOfOption interface { + // ApplyToDeleteAllOf applies this configuration to the given deletecollection options. + ApplyToDeleteAllOf(*DeleteAllOfOptions) +} + +// }}} + +// {{{ Multi-Type Options + +// DryRunAll sets the "dry run" option to "all", executing all +// validation, etc without persisting the change to storage. +var DryRunAll = dryRunAll{} + +type dryRunAll struct{} + +// ApplyToCreate applies this configuration to the given create options. +func (dryRunAll) ApplyToCreate(opts *CreateOptions) { + opts.DryRun = []string{metav1.DryRunAll} +} + +// ApplyToUpdate applies this configuration to the given update options. +func (dryRunAll) ApplyToUpdate(opts *UpdateOptions) { + opts.DryRun = []string{metav1.DryRunAll} +} + +// ApplyToPatch applies this configuration to the given patch options. +func (dryRunAll) ApplyToPatch(opts *PatchOptions) { + opts.DryRun = []string{metav1.DryRunAll} +} + +// ApplyToPatch applies this configuration to the given delete options. +func (dryRunAll) ApplyToDelete(opts *DeleteOptions) { + opts.DryRun = []string{metav1.DryRunAll} +} +func (dryRunAll) ApplyToDeleteAllOf(opts *DeleteAllOfOptions) { + opts.DryRun = []string{metav1.DryRunAll} +} + +// FieldOwner set the field manager name for the given server-side apply patch. +type FieldOwner string + +// ApplyToPatch applies this configuration to the given patch options. +func (f FieldOwner) ApplyToPatch(opts *PatchOptions) { + opts.FieldManager = string(f) +} + +// ApplyToCreate applies this configuration to the given create options. +func (f FieldOwner) ApplyToCreate(opts *CreateOptions) { + opts.FieldManager = string(f) +} + +// ApplyToUpdate applies this configuration to the given update options. +func (f FieldOwner) ApplyToUpdate(opts *UpdateOptions) { + opts.FieldManager = string(f) +} + +// }}} + +// {{{ Create Options + +// CreateOptions contains options for create requests. It's generally a subset +// of metav1.CreateOptions. +type CreateOptions struct { + // When present, indicates that modifications should not be + // persisted. An invalid or unrecognized dryRun directive will + // result in an error response and no further processing of the + // request. Valid values are: + // - All: all dry run stages will be processed + DryRun []string + + // FieldManager is the name of the user or component submitting + // this request. It must be set with server-side apply. + FieldManager string + + // Raw represents raw CreateOptions, as passed to the API server. + Raw *metav1.CreateOptions +} + +// AsCreateOptions returns these options as a metav1.CreateOptions. +// This may mutate the Raw field. +func (o *CreateOptions) AsCreateOptions() *metav1.CreateOptions { + if o == nil { + return &metav1.CreateOptions{} + } + if o.Raw == nil { + o.Raw = &metav1.CreateOptions{} + } + + o.Raw.DryRun = o.DryRun + o.Raw.FieldManager = o.FieldManager + return o.Raw +} + +// ApplyOptions applies the given create options on these options, +// and then returns itself (for convenient chaining). +func (o *CreateOptions) ApplyOptions(opts []CreateOption) *CreateOptions { + for _, opt := range opts { + opt.ApplyToCreate(o) + } + return o +} + +// ApplyToCreate implements CreateOption. +func (o *CreateOptions) ApplyToCreate(co *CreateOptions) { + if o.DryRun != nil { + co.DryRun = o.DryRun + } + if o.FieldManager != "" { + co.FieldManager = o.FieldManager + } + if o.Raw != nil { + co.Raw = o.Raw + } +} + +var _ CreateOption = &CreateOptions{} + +// }}} + +// {{{ Delete Options + +// DeleteOptions contains options for delete requests. It's generally a subset +// of metav1.DeleteOptions. +type DeleteOptions struct { + // GracePeriodSeconds is the duration in seconds before the object should be + // deleted. Value must be non-negative integer. The value zero indicates + // delete immediately. If this value is nil, the default grace period for the + // specified type will be used. + GracePeriodSeconds *int64 + + // Preconditions must be fulfilled before a deletion is carried out. If not + // possible, a 409 Conflict status will be returned. + Preconditions *metav1.Preconditions + + // PropagationPolicy determined whether and how garbage collection will be + // performed. Either this field or OrphanDependents may be set, but not both. + // The default policy is decided by the existing finalizer set in the + // metadata.finalizers and the resource-specific default policy. + // Acceptable values are: 'Orphan' - orphan the dependents; 'Background' - + // allow the garbage collector to delete the dependents in the background; + // 'Foreground' - a cascading policy that deletes all dependents in the + // foreground. + PropagationPolicy *metav1.DeletionPropagation + + // Raw represents raw DeleteOptions, as passed to the API server. + Raw *metav1.DeleteOptions + + // When present, indicates that modifications should not be + // persisted. An invalid or unrecognized dryRun directive will + // result in an error response and no further processing of the + // request. Valid values are: + // - All: all dry run stages will be processed + DryRun []string +} + +// AsDeleteOptions returns these options as a metav1.DeleteOptions. +// This may mutate the Raw field. +func (o *DeleteOptions) AsDeleteOptions() *metav1.DeleteOptions { + if o == nil { + return &metav1.DeleteOptions{} + } + if o.Raw == nil { + o.Raw = &metav1.DeleteOptions{} + } + + o.Raw.GracePeriodSeconds = o.GracePeriodSeconds + o.Raw.Preconditions = o.Preconditions + o.Raw.PropagationPolicy = o.PropagationPolicy + o.Raw.DryRun = o.DryRun + return o.Raw +} + +// ApplyOptions applies the given delete options on these options, +// and then returns itself (for convenient chaining). +func (o *DeleteOptions) ApplyOptions(opts []DeleteOption) *DeleteOptions { + for _, opt := range opts { + opt.ApplyToDelete(o) + } + return o +} + +var _ DeleteOption = &DeleteOptions{} + +// ApplyToDelete implements DeleteOption. +func (o *DeleteOptions) ApplyToDelete(do *DeleteOptions) { + if o.GracePeriodSeconds != nil { + do.GracePeriodSeconds = o.GracePeriodSeconds + } + if o.Preconditions != nil { + do.Preconditions = o.Preconditions + } + if o.PropagationPolicy != nil { + do.PropagationPolicy = o.PropagationPolicy + } + if o.Raw != nil { + do.Raw = o.Raw + } + if o.DryRun != nil { + do.DryRun = o.DryRun + } +} + +// GracePeriodSeconds sets the grace period for the deletion +// to the given number of seconds. +type GracePeriodSeconds int64 + +// ApplyToDelete applies this configuration to the given delete options. +func (s GracePeriodSeconds) ApplyToDelete(opts *DeleteOptions) { + secs := int64(s) + opts.GracePeriodSeconds = &secs +} + +// ApplyToDeleteAllOf applies this configuration to the given an List options. +func (s GracePeriodSeconds) ApplyToDeleteAllOf(opts *DeleteAllOfOptions) { + s.ApplyToDelete(&opts.DeleteOptions) +} + +// Preconditions must be fulfilled before an operation (update, delete, etc.) is carried out. +type Preconditions metav1.Preconditions + +// ApplyToDelete applies this configuration to the given delete options. +func (p Preconditions) ApplyToDelete(opts *DeleteOptions) { + preconds := metav1.Preconditions(p) + opts.Preconditions = &preconds +} + +// ApplyToDeleteAllOf applies this configuration to the given an List options. +func (p Preconditions) ApplyToDeleteAllOf(opts *DeleteAllOfOptions) { + p.ApplyToDelete(&opts.DeleteOptions) +} + +// PropagationPolicy determined whether and how garbage collection will be +// performed. Either this field or OrphanDependents may be set, but not both. +// The default policy is decided by the existing finalizer set in the +// metadata.finalizers and the resource-specific default policy. +// Acceptable values are: 'Orphan' - orphan the dependents; 'Background' - +// allow the garbage collector to delete the dependents in the background; +// 'Foreground' - a cascading policy that deletes all dependents in the +// foreground. +type PropagationPolicy metav1.DeletionPropagation + +// ApplyToDelete applies the given delete options on these options. +// It will propagate to the dependents of the object to let the garbage collector handle it. +func (p PropagationPolicy) ApplyToDelete(opts *DeleteOptions) { + policy := metav1.DeletionPropagation(p) + opts.PropagationPolicy = &policy +} + +// ApplyToDeleteAllOf applies this configuration to the given an List options. +func (p PropagationPolicy) ApplyToDeleteAllOf(opts *DeleteAllOfOptions) { + p.ApplyToDelete(&opts.DeleteOptions) +} + +// }}} + +// {{{ Get Options + +// GetOptions contains options for get operation. +// Now it only has a Raw field, with support for specific resourceVersion. +type GetOptions struct { + // Raw represents raw GetOptions, as passed to the API server. Note + // that these may not be respected by all implementations of interface. + Raw *metav1.GetOptions +} + +var _ GetOption = &GetOptions{} + +// ApplyToGet implements GetOption for GetOptions. +func (o *GetOptions) ApplyToGet(lo *GetOptions) { + if o.Raw != nil { + lo.Raw = o.Raw + } +} + +// AsGetOptions returns these options as a flattened metav1.GetOptions. +// This may mutate the Raw field. +func (o *GetOptions) AsGetOptions() *metav1.GetOptions { + if o == nil || o.Raw == nil { + return &metav1.GetOptions{} + } + return o.Raw +} + +// ApplyOptions applies the given get options on these options, +// and then returns itself (for convenient chaining). +func (o *GetOptions) ApplyOptions(opts []GetOption) *GetOptions { + for _, opt := range opts { + opt.ApplyToGet(o) + } + return o +} + +// }}} + +// {{{ List Options + +// ListOptions contains options for limiting or filtering results. +// It's generally a subset of metav1.ListOptions, with support for +// pre-parsed selectors (since generally, selectors will be executed +// against the cache). +type ListOptions struct { + // LabelSelector filters results by label. Use labels.Parse() to + // set from raw string form. + LabelSelector labels.Selector + // FieldSelector filters results by a particular field. In order + // to use this with cache-based implementations, restrict usage to + // a single field-value pair that's been added to the indexers. + FieldSelector fields.Selector + + // Namespace represents the namespace to list for, or empty for + // non-namespaced objects, or to list across all namespaces. + Namespace string + + // Limit specifies the maximum number of results to return from the server. The server may + // not support this field on all resource types, but if it does and more results remain it + // will set the continue field on the returned list object. This field is not supported if watch + // is true in the Raw ListOptions. + Limit int64 + // Continue is a token returned by the server that lets a client retrieve chunks of results + // from the server by specifying limit. The server may reject requests for continuation tokens + // it does not recognize and will return a 410 error if the token can no longer be used because + // it has expired. This field is not supported if watch is true in the Raw ListOptions. + Continue string + + // Raw represents raw ListOptions, as passed to the API server. Note + // that these may not be respected by all implementations of interface, + // and the LabelSelector, FieldSelector, Limit and Continue fields are ignored. + Raw *metav1.ListOptions +} + +var _ ListOption = &ListOptions{} + +// ApplyToList implements ListOption for ListOptions. +func (o *ListOptions) ApplyToList(lo *ListOptions) { + if o.LabelSelector != nil { + lo.LabelSelector = o.LabelSelector + } + if o.FieldSelector != nil { + lo.FieldSelector = o.FieldSelector + } + if o.Namespace != "" { + lo.Namespace = o.Namespace + } + if o.Raw != nil { + lo.Raw = o.Raw + } + if o.Limit > 0 { + lo.Limit = o.Limit + } + if o.Continue != "" { + lo.Continue = o.Continue + } +} + +// AsListOptions returns these options as a flattened metav1.ListOptions. +// This may mutate the Raw field. +func (o *ListOptions) AsListOptions() *metav1.ListOptions { + if o == nil { + return &metav1.ListOptions{} + } + if o.Raw == nil { + o.Raw = &metav1.ListOptions{} + } + if o.LabelSelector != nil { + o.Raw.LabelSelector = o.LabelSelector.String() + } + if o.FieldSelector != nil { + o.Raw.FieldSelector = o.FieldSelector.String() + } + if !o.Raw.Watch { + o.Raw.Limit = o.Limit + o.Raw.Continue = o.Continue + } + return o.Raw +} + +// ApplyOptions applies the given list options on these options, +// and then returns itself (for convenient chaining). +func (o *ListOptions) ApplyOptions(opts []ListOption) *ListOptions { + for _, opt := range opts { + opt.ApplyToList(o) + } + return o +} + +// MatchingLabels filters the list/delete operation on the given set of labels. +type MatchingLabels map[string]string + +// ApplyToList applies this configuration to the given list options. +func (m MatchingLabels) ApplyToList(opts *ListOptions) { + // TODO(directxman12): can we avoid reserializing this over and over? + sel := labels.SelectorFromValidatedSet(map[string]string(m)) + opts.LabelSelector = sel +} + +// ApplyToDeleteAllOf applies this configuration to the given an List options. +func (m MatchingLabels) ApplyToDeleteAllOf(opts *DeleteAllOfOptions) { + m.ApplyToList(&opts.ListOptions) +} + +// HasLabels filters the list/delete operation checking if the set of labels exists +// without checking their values. +type HasLabels []string + +// ApplyToList applies this configuration to the given list options. +func (m HasLabels) ApplyToList(opts *ListOptions) { + sel := labels.NewSelector() + for _, label := range m { + r, err := labels.NewRequirement(label, selection.Exists, nil) + if err == nil { + sel = sel.Add(*r) + } + } + opts.LabelSelector = sel +} + +// ApplyToDeleteAllOf applies this configuration to the given an List options. +func (m HasLabels) ApplyToDeleteAllOf(opts *DeleteAllOfOptions) { + m.ApplyToList(&opts.ListOptions) +} + +// MatchingLabelsSelector filters the list/delete operation on the given label +// selector (or index in the case of cached lists). A struct is used because +// labels.Selector is an interface, which cannot be aliased. +type MatchingLabelsSelector struct { + labels.Selector +} + +// ApplyToList applies this configuration to the given list options. +func (m MatchingLabelsSelector) ApplyToList(opts *ListOptions) { + opts.LabelSelector = m +} + +// ApplyToDeleteAllOf applies this configuration to the given an List options. +func (m MatchingLabelsSelector) ApplyToDeleteAllOf(opts *DeleteAllOfOptions) { + m.ApplyToList(&opts.ListOptions) +} + +// MatchingFields filters the list/delete operation on the given field Set +// (or index in the case of cached lists). +type MatchingFields fields.Set + +// ApplyToList applies this configuration to the given list options. +func (m MatchingFields) ApplyToList(opts *ListOptions) { + // TODO(directxman12): can we avoid re-serializing this? + sel := fields.Set(m).AsSelector() + opts.FieldSelector = sel +} + +// ApplyToDeleteAllOf applies this configuration to the given an List options. +func (m MatchingFields) ApplyToDeleteAllOf(opts *DeleteAllOfOptions) { + m.ApplyToList(&opts.ListOptions) +} + +// MatchingFieldsSelector filters the list/delete operation on the given field +// selector (or index in the case of cached lists). A struct is used because +// fields.Selector is an interface, which cannot be aliased. +type MatchingFieldsSelector struct { + fields.Selector +} + +// ApplyToList applies this configuration to the given list options. +func (m MatchingFieldsSelector) ApplyToList(opts *ListOptions) { + opts.FieldSelector = m +} + +// ApplyToDeleteAllOf applies this configuration to the given an List options. +func (m MatchingFieldsSelector) ApplyToDeleteAllOf(opts *DeleteAllOfOptions) { + m.ApplyToList(&opts.ListOptions) +} + +// InNamespace restricts the list/delete operation to the given namespace. +type InNamespace string + +// ApplyToList applies this configuration to the given list options. +func (n InNamespace) ApplyToList(opts *ListOptions) { + opts.Namespace = string(n) +} + +// ApplyToDeleteAllOf applies this configuration to the given an List options. +func (n InNamespace) ApplyToDeleteAllOf(opts *DeleteAllOfOptions) { + n.ApplyToList(&opts.ListOptions) +} + +// Limit specifies the maximum number of results to return from the server. +// Limit does not implement DeleteAllOfOption interface because the server +// does not support setting it for deletecollection operations. +type Limit int64 + +// ApplyToList applies this configuration to the given an list options. +func (l Limit) ApplyToList(opts *ListOptions) { + opts.Limit = int64(l) +} + +// Continue sets a continuation token to retrieve chunks of results when using limit. +// Continue does not implement DeleteAllOfOption interface because the server +// does not support setting it for deletecollection operations. +type Continue string + +// ApplyToList applies this configuration to the given an List options. +func (c Continue) ApplyToList(opts *ListOptions) { + opts.Continue = string(c) +} + +// }}} + +// {{{ Update Options + +// UpdateOptions contains options for create requests. It's generally a subset +// of metav1.UpdateOptions. +type UpdateOptions struct { + // When present, indicates that modifications should not be + // persisted. An invalid or unrecognized dryRun directive will + // result in an error response and no further processing of the + // request. Valid values are: + // - All: all dry run stages will be processed + DryRun []string + + // FieldManager is the name of the user or component submitting + // this request. It must be set with server-side apply. + FieldManager string + + // Raw represents raw UpdateOptions, as passed to the API server. + Raw *metav1.UpdateOptions +} + +// AsUpdateOptions returns these options as a metav1.UpdateOptions. +// This may mutate the Raw field. +func (o *UpdateOptions) AsUpdateOptions() *metav1.UpdateOptions { + if o == nil { + return &metav1.UpdateOptions{} + } + if o.Raw == nil { + o.Raw = &metav1.UpdateOptions{} + } + + o.Raw.DryRun = o.DryRun + o.Raw.FieldManager = o.FieldManager + return o.Raw +} + +// ApplyOptions applies the given update options on these options, +// and then returns itself (for convenient chaining). +func (o *UpdateOptions) ApplyOptions(opts []UpdateOption) *UpdateOptions { + for _, opt := range opts { + opt.ApplyToUpdate(o) + } + return o +} + +var _ UpdateOption = &UpdateOptions{} + +// ApplyToUpdate implements UpdateOption. +func (o *UpdateOptions) ApplyToUpdate(uo *UpdateOptions) { + if o.DryRun != nil { + uo.DryRun = o.DryRun + } + if o.FieldManager != "" { + uo.FieldManager = o.FieldManager + } + if o.Raw != nil { + uo.Raw = o.Raw + } +} + +// }}} + +// {{{ Patch Options + +// PatchOptions contains options for patch requests. +type PatchOptions struct { + // When present, indicates that modifications should not be + // persisted. An invalid or unrecognized dryRun directive will + // result in an error response and no further processing of the + // request. Valid values are: + // - All: all dry run stages will be processed + DryRun []string + + // Force is going to "force" Apply requests. It means user will + // re-acquire conflicting fields owned by other people. Force + // flag must be unset for non-apply patch requests. + // +optional + Force *bool + + // FieldManager is the name of the user or component submitting + // this request. It must be set with server-side apply. + FieldManager string + + // Raw represents raw PatchOptions, as passed to the API server. + Raw *metav1.PatchOptions +} + +// ApplyOptions applies the given patch options on these options, +// and then returns itself (for convenient chaining). +func (o *PatchOptions) ApplyOptions(opts []PatchOption) *PatchOptions { + for _, opt := range opts { + opt.ApplyToPatch(o) + } + return o +} + +// AsPatchOptions returns these options as a metav1.PatchOptions. +// This may mutate the Raw field. +func (o *PatchOptions) AsPatchOptions() *metav1.PatchOptions { + if o == nil { + return &metav1.PatchOptions{} + } + if o.Raw == nil { + o.Raw = &metav1.PatchOptions{} + } + + o.Raw.DryRun = o.DryRun + o.Raw.Force = o.Force + o.Raw.FieldManager = o.FieldManager + return o.Raw +} + +var _ PatchOption = &PatchOptions{} + +// ApplyToPatch implements PatchOptions. +func (o *PatchOptions) ApplyToPatch(po *PatchOptions) { + if o.DryRun != nil { + po.DryRun = o.DryRun + } + if o.Force != nil { + po.Force = o.Force + } + if o.FieldManager != "" { + po.FieldManager = o.FieldManager + } + if o.Raw != nil { + po.Raw = o.Raw + } +} + +// ForceOwnership indicates that in case of conflicts with server-side apply, +// the client should acquire ownership of the conflicting field. Most +// controllers should use this. +var ForceOwnership = forceOwnership{} + +type forceOwnership struct{} + +func (forceOwnership) ApplyToPatch(opts *PatchOptions) { + definitelyTrue := true + opts.Force = &definitelyTrue +} + +// }}} + +// {{{ DeleteAllOf Options + +// these are all just delete options and list options + +// DeleteAllOfOptions contains options for deletecollection (deleteallof) requests. +// It's just list and delete options smooshed together. +type DeleteAllOfOptions struct { + ListOptions + DeleteOptions +} + +// ApplyOptions applies the given deleteallof options on these options, +// and then returns itself (for convenient chaining). +func (o *DeleteAllOfOptions) ApplyOptions(opts []DeleteAllOfOption) *DeleteAllOfOptions { + for _, opt := range opts { + opt.ApplyToDeleteAllOf(o) + } + return o +} + +var _ DeleteAllOfOption = &DeleteAllOfOptions{} + +// ApplyToDeleteAllOf implements DeleteAllOfOption. +func (o *DeleteAllOfOptions) ApplyToDeleteAllOf(do *DeleteAllOfOptions) { + o.ApplyToList(&do.ListOptions) + o.ApplyToDelete(&do.DeleteOptions) +} + +// }}} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/client/patch.go b/vendor/sigs.k8s.io/controller-runtime/pkg/client/patch.go new file mode 100644 index 0000000000..11d6083885 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/client/patch.go @@ -0,0 +1,213 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package client + +import ( + "fmt" + + jsonpatch "github.com/evanphx/json-patch/v5" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/json" + "k8s.io/apimachinery/pkg/util/strategicpatch" +) + +var ( + // Apply uses server-side apply to patch the given object. + Apply Patch = applyPatch{} + + // Merge uses the raw object as a merge patch, without modifications. + // Use MergeFrom if you wish to compute a diff instead. + Merge Patch = mergePatch{} +) + +type patch struct { + patchType types.PatchType + data []byte +} + +// Type implements Patch. +func (s *patch) Type() types.PatchType { + return s.patchType +} + +// Data implements Patch. +func (s *patch) Data(obj Object) ([]byte, error) { + return s.data, nil +} + +// RawPatch constructs a new Patch with the given PatchType and data. +func RawPatch(patchType types.PatchType, data []byte) Patch { + return &patch{patchType, data} +} + +// MergeFromWithOptimisticLock can be used if clients want to make sure a patch +// is being applied to the latest resource version of an object. +// +// The behavior is similar to what an Update would do, without the need to send the +// whole object. Usually this method is useful if you might have multiple clients +// acting on the same object and the same API version, but with different versions of the Go structs. +// +// For example, an "older" copy of a Widget that has fields A and B, and a "newer" copy with A, B, and C. +// Sending an update using the older struct definition results in C being dropped, whereas using a patch does not. +type MergeFromWithOptimisticLock struct{} + +// ApplyToMergeFrom applies this configuration to the given patch options. +func (m MergeFromWithOptimisticLock) ApplyToMergeFrom(in *MergeFromOptions) { + in.OptimisticLock = true +} + +// MergeFromOption is some configuration that modifies options for a merge-from patch data. +type MergeFromOption interface { + // ApplyToMergeFrom applies this configuration to the given patch options. + ApplyToMergeFrom(*MergeFromOptions) +} + +// MergeFromOptions contains options to generate a merge-from patch data. +type MergeFromOptions struct { + // OptimisticLock, when true, includes `metadata.resourceVersion` into the final + // patch data. If the `resourceVersion` field doesn't match what's stored, + // the operation results in a conflict and clients will need to try again. + OptimisticLock bool +} + +type mergeFromPatch struct { + patchType types.PatchType + createPatch func(originalJSON, modifiedJSON []byte, dataStruct interface{}) ([]byte, error) + from Object + opts MergeFromOptions +} + +// Type implements Patch. +func (s *mergeFromPatch) Type() types.PatchType { + return s.patchType +} + +// Data implements Patch. +func (s *mergeFromPatch) Data(obj Object) ([]byte, error) { + original := s.from + modified := obj + + if s.opts.OptimisticLock { + version := original.GetResourceVersion() + if len(version) == 0 { + return nil, fmt.Errorf("cannot use OptimisticLock, object %q does not have any resource version we can use", original) + } + + original = original.DeepCopyObject().(Object) + original.SetResourceVersion("") + + modified = modified.DeepCopyObject().(Object) + modified.SetResourceVersion(version) + } + + originalJSON, err := json.Marshal(original) + if err != nil { + return nil, err + } + + modifiedJSON, err := json.Marshal(modified) + if err != nil { + return nil, err + } + + data, err := s.createPatch(originalJSON, modifiedJSON, obj) + if err != nil { + return nil, err + } + + return data, nil +} + +func createMergePatch(originalJSON, modifiedJSON []byte, _ interface{}) ([]byte, error) { + return jsonpatch.CreateMergePatch(originalJSON, modifiedJSON) +} + +func createStrategicMergePatch(originalJSON, modifiedJSON []byte, dataStruct interface{}) ([]byte, error) { + return strategicpatch.CreateTwoWayMergePatch(originalJSON, modifiedJSON, dataStruct) +} + +// MergeFrom creates a Patch that patches using the merge-patch strategy with the given object as base. +// The difference between MergeFrom and StrategicMergeFrom lays in the handling of modified list fields. +// When using MergeFrom, existing lists will be completely replaced by new lists. +// When using StrategicMergeFrom, the list field's `patchStrategy` is respected if specified in the API type, +// e.g. the existing list is not replaced completely but rather merged with the new one using the list's `patchMergeKey`. +// See https://kubernetes.io/docs/tasks/manage-kubernetes-objects/update-api-object-kubectl-patch/ for more details on +// the difference between merge-patch and strategic-merge-patch. +func MergeFrom(obj Object) Patch { + return &mergeFromPatch{patchType: types.MergePatchType, createPatch: createMergePatch, from: obj} +} + +// MergeFromWithOptions creates a Patch that patches using the merge-patch strategy with the given object as base. +// See MergeFrom for more details. +func MergeFromWithOptions(obj Object, opts ...MergeFromOption) Patch { + options := &MergeFromOptions{} + for _, opt := range opts { + opt.ApplyToMergeFrom(options) + } + return &mergeFromPatch{patchType: types.MergePatchType, createPatch: createMergePatch, from: obj, opts: *options} +} + +// StrategicMergeFrom creates a Patch that patches using the strategic-merge-patch strategy with the given object as base. +// The difference between MergeFrom and StrategicMergeFrom lays in the handling of modified list fields. +// When using MergeFrom, existing lists will be completely replaced by new lists. +// When using StrategicMergeFrom, the list field's `patchStrategy` is respected if specified in the API type, +// e.g. the existing list is not replaced completely but rather merged with the new one using the list's `patchMergeKey`. +// See https://kubernetes.io/docs/tasks/manage-kubernetes-objects/update-api-object-kubectl-patch/ for more details on +// the difference between merge-patch and strategic-merge-patch. +// Please note, that CRDs don't support strategic-merge-patch, see +// https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/#advanced-features-and-flexibility +func StrategicMergeFrom(obj Object, opts ...MergeFromOption) Patch { + options := &MergeFromOptions{} + for _, opt := range opts { + opt.ApplyToMergeFrom(options) + } + return &mergeFromPatch{patchType: types.StrategicMergePatchType, createPatch: createStrategicMergePatch, from: obj, opts: *options} +} + +// mergePatch uses a raw merge strategy to patch the object. +type mergePatch struct{} + +// Type implements Patch. +func (p mergePatch) Type() types.PatchType { + return types.MergePatchType +} + +// Data implements Patch. +func (p mergePatch) Data(obj Object) ([]byte, error) { + // NB(directxman12): we might technically want to be using an actual encoder + // here (in case some more performant encoder is introduced) but this is + // correct and sufficient for our uses (it's what the JSON serializer in + // client-go does, more-or-less). + return json.Marshal(obj) +} + +// applyPatch uses server-side apply to patch the object. +type applyPatch struct{} + +// Type implements Patch. +func (p applyPatch) Type() types.PatchType { + return types.ApplyPatchType +} + +// Data implements Patch. +func (p applyPatch) Data(obj Object) ([]byte, error) { + // NB(directxman12): we might technically want to be using an actual encoder + // here (in case some more performant encoder is introduced) but this is + // correct and sufficient for our uses (it's what the JSON serializer in + // client-go does, more-or-less). + return json.Marshal(obj) +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/client/split.go b/vendor/sigs.k8s.io/controller-runtime/pkg/client/split.go new file mode 100644 index 0000000000..8717345349 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/client/split.go @@ -0,0 +1,141 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package client + +import ( + "context" + "strings" + + "k8s.io/apimachinery/pkg/api/meta" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + + "sigs.k8s.io/controller-runtime/pkg/client/apiutil" +) + +// NewDelegatingClientInput encapsulates the input parameters to create a new delegating client. +type NewDelegatingClientInput struct { + CacheReader Reader + Client Client + UncachedObjects []Object + CacheUnstructured bool +} + +// NewDelegatingClient creates a new delegating client. +// +// A delegating client forms a Client by composing separate reader, writer and +// statusclient interfaces. This way, you can have an Client that reads from a +// cache and writes to the API server. +func NewDelegatingClient(in NewDelegatingClientInput) (Client, error) { + uncachedGVKs := map[schema.GroupVersionKind]struct{}{} + for _, obj := range in.UncachedObjects { + gvk, err := apiutil.GVKForObject(obj, in.Client.Scheme()) + if err != nil { + return nil, err + } + uncachedGVKs[gvk] = struct{}{} + } + + return &delegatingClient{ + scheme: in.Client.Scheme(), + mapper: in.Client.RESTMapper(), + Reader: &delegatingReader{ + CacheReader: in.CacheReader, + ClientReader: in.Client, + scheme: in.Client.Scheme(), + uncachedGVKs: uncachedGVKs, + cacheUnstructured: in.CacheUnstructured, + }, + Writer: in.Client, + StatusClient: in.Client, + }, nil +} + +type delegatingClient struct { + Reader + Writer + StatusClient + + scheme *runtime.Scheme + mapper meta.RESTMapper +} + +// Scheme returns the scheme this client is using. +func (d *delegatingClient) Scheme() *runtime.Scheme { + return d.scheme +} + +// RESTMapper returns the rest mapper this client is using. +func (d *delegatingClient) RESTMapper() meta.RESTMapper { + return d.mapper +} + +// delegatingReader forms a Reader that will cause Get and List requests for +// unstructured types to use the ClientReader while requests for any other type +// of object with use the CacheReader. This avoids accidentally caching the +// entire cluster in the common case of loading arbitrary unstructured objects +// (e.g. from OwnerReferences). +type delegatingReader struct { + CacheReader Reader + ClientReader Reader + + uncachedGVKs map[schema.GroupVersionKind]struct{} + scheme *runtime.Scheme + cacheUnstructured bool +} + +func (d *delegatingReader) shouldBypassCache(obj runtime.Object) (bool, error) { + gvk, err := apiutil.GVKForObject(obj, d.scheme) + if err != nil { + return false, err + } + // TODO: this is producing unsafe guesses that don't actually work, + // but it matches ~99% of the cases out there. + if meta.IsListType(obj) { + gvk.Kind = strings.TrimSuffix(gvk.Kind, "List") + } + if _, isUncached := d.uncachedGVKs[gvk]; isUncached { + return true, nil + } + if !d.cacheUnstructured { + _, isUnstructured := obj.(*unstructured.Unstructured) + _, isUnstructuredList := obj.(*unstructured.UnstructuredList) + return isUnstructured || isUnstructuredList, nil + } + return false, nil +} + +// Get retrieves an obj for a given object key from the Kubernetes Cluster. +func (d *delegatingReader) Get(ctx context.Context, key ObjectKey, obj Object, opts ...GetOption) error { + if isUncached, err := d.shouldBypassCache(obj); err != nil { + return err + } else if isUncached { + return d.ClientReader.Get(ctx, key, obj, opts...) + } + return d.CacheReader.Get(ctx, key, obj, opts...) +} + +// List retrieves list of objects for a given namespace and list options. +func (d *delegatingReader) List(ctx context.Context, list ObjectList, opts ...ListOption) error { + if isUncached, err := d.shouldBypassCache(list); err != nil { + return err + } else if isUncached { + return d.ClientReader.List(ctx, list, opts...) + } + return d.CacheReader.List(ctx, list, opts...) +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/client/typed_client.go b/vendor/sigs.k8s.io/controller-runtime/pkg/client/typed_client.go new file mode 100644 index 0000000000..c4e56d9be6 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/client/typed_client.go @@ -0,0 +1,208 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package client + +import ( + "context" + + "k8s.io/apimachinery/pkg/runtime" +) + +var _ Reader = &typedClient{} +var _ Writer = &typedClient{} +var _ StatusWriter = &typedClient{} + +// client is a client.Client that reads and writes directly from/to an API server. It lazily initializes +// new clients at the time they are used, and caches the client. +type typedClient struct { + cache *clientCache + paramCodec runtime.ParameterCodec +} + +// Create implements client.Client. +func (c *typedClient) Create(ctx context.Context, obj Object, opts ...CreateOption) error { + o, err := c.cache.getObjMeta(obj) + if err != nil { + return err + } + + createOpts := &CreateOptions{} + createOpts.ApplyOptions(opts) + return o.Post(). + NamespaceIfScoped(o.GetNamespace(), o.isNamespaced()). + Resource(o.resource()). + Body(obj). + VersionedParams(createOpts.AsCreateOptions(), c.paramCodec). + Do(ctx). + Into(obj) +} + +// Update implements client.Client. +func (c *typedClient) Update(ctx context.Context, obj Object, opts ...UpdateOption) error { + o, err := c.cache.getObjMeta(obj) + if err != nil { + return err + } + + updateOpts := &UpdateOptions{} + updateOpts.ApplyOptions(opts) + return o.Put(). + NamespaceIfScoped(o.GetNamespace(), o.isNamespaced()). + Resource(o.resource()). + Name(o.GetName()). + Body(obj). + VersionedParams(updateOpts.AsUpdateOptions(), c.paramCodec). + Do(ctx). + Into(obj) +} + +// Delete implements client.Client. +func (c *typedClient) Delete(ctx context.Context, obj Object, opts ...DeleteOption) error { + o, err := c.cache.getObjMeta(obj) + if err != nil { + return err + } + + deleteOpts := DeleteOptions{} + deleteOpts.ApplyOptions(opts) + + return o.Delete(). + NamespaceIfScoped(o.GetNamespace(), o.isNamespaced()). + Resource(o.resource()). + Name(o.GetName()). + Body(deleteOpts.AsDeleteOptions()). + Do(ctx). + Error() +} + +// DeleteAllOf implements client.Client. +func (c *typedClient) DeleteAllOf(ctx context.Context, obj Object, opts ...DeleteAllOfOption) error { + o, err := c.cache.getObjMeta(obj) + if err != nil { + return err + } + + deleteAllOfOpts := DeleteAllOfOptions{} + deleteAllOfOpts.ApplyOptions(opts) + + return o.Delete(). + NamespaceIfScoped(deleteAllOfOpts.ListOptions.Namespace, o.isNamespaced()). + Resource(o.resource()). + VersionedParams(deleteAllOfOpts.AsListOptions(), c.paramCodec). + Body(deleteAllOfOpts.AsDeleteOptions()). + Do(ctx). + Error() +} + +// Patch implements client.Client. +func (c *typedClient) Patch(ctx context.Context, obj Object, patch Patch, opts ...PatchOption) error { + o, err := c.cache.getObjMeta(obj) + if err != nil { + return err + } + + data, err := patch.Data(obj) + if err != nil { + return err + } + + patchOpts := &PatchOptions{} + return o.Patch(patch.Type()). + NamespaceIfScoped(o.GetNamespace(), o.isNamespaced()). + Resource(o.resource()). + Name(o.GetName()). + VersionedParams(patchOpts.ApplyOptions(opts).AsPatchOptions(), c.paramCodec). + Body(data). + Do(ctx). + Into(obj) +} + +// Get implements client.Client. +func (c *typedClient) Get(ctx context.Context, key ObjectKey, obj Object, opts ...GetOption) error { + r, err := c.cache.getResource(obj) + if err != nil { + return err + } + getOpts := GetOptions{} + getOpts.ApplyOptions(opts) + return r.Get(). + NamespaceIfScoped(key.Namespace, r.isNamespaced()). + Resource(r.resource()). + VersionedParams(getOpts.AsGetOptions(), c.paramCodec). + Name(key.Name).Do(ctx).Into(obj) +} + +// List implements client.Client. +func (c *typedClient) List(ctx context.Context, obj ObjectList, opts ...ListOption) error { + r, err := c.cache.getResource(obj) + if err != nil { + return err + } + listOpts := ListOptions{} + listOpts.ApplyOptions(opts) + return r.Get(). + NamespaceIfScoped(listOpts.Namespace, r.isNamespaced()). + Resource(r.resource()). + VersionedParams(listOpts.AsListOptions(), c.paramCodec). + Do(ctx). + Into(obj) +} + +// UpdateStatus used by StatusWriter to write status. +func (c *typedClient) UpdateStatus(ctx context.Context, obj Object, opts ...UpdateOption) error { + o, err := c.cache.getObjMeta(obj) + if err != nil { + return err + } + // TODO(droot): examine the returned error and check if it error needs to be + // wrapped to improve the UX ? + // It will be nice to receive an error saying the object doesn't implement + // status subresource and check CRD definition + return o.Put(). + NamespaceIfScoped(o.GetNamespace(), o.isNamespaced()). + Resource(o.resource()). + Name(o.GetName()). + SubResource("status"). + Body(obj). + VersionedParams((&UpdateOptions{}).ApplyOptions(opts).AsUpdateOptions(), c.paramCodec). + Do(ctx). + Into(obj) +} + +// PatchStatus used by StatusWriter to write status. +func (c *typedClient) PatchStatus(ctx context.Context, obj Object, patch Patch, opts ...PatchOption) error { + o, err := c.cache.getObjMeta(obj) + if err != nil { + return err + } + + data, err := patch.Data(obj) + if err != nil { + return err + } + + patchOpts := &PatchOptions{} + return o.Patch(patch.Type()). + NamespaceIfScoped(o.GetNamespace(), o.isNamespaced()). + Resource(o.resource()). + Name(o.GetName()). + SubResource("status"). + Body(data). + VersionedParams(patchOpts.ApplyOptions(opts).AsPatchOptions(), c.paramCodec). + Do(ctx). + Into(obj) +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/client/unstructured_client.go b/vendor/sigs.k8s.io/controller-runtime/pkg/client/unstructured_client.go new file mode 100644 index 0000000000..3d3dbe7b28 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/client/unstructured_client.go @@ -0,0 +1,275 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package client + +import ( + "context" + "fmt" + "strings" + + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" +) + +var _ Reader = &unstructuredClient{} +var _ Writer = &unstructuredClient{} +var _ StatusWriter = &unstructuredClient{} + +// client is a client.Client that reads and writes directly from/to an API server. It lazily initializes +// new clients at the time they are used, and caches the client. +type unstructuredClient struct { + cache *clientCache + paramCodec runtime.ParameterCodec +} + +// Create implements client.Client. +func (uc *unstructuredClient) Create(ctx context.Context, obj Object, opts ...CreateOption) error { + u, ok := obj.(*unstructured.Unstructured) + if !ok { + return fmt.Errorf("unstructured client did not understand object: %T", obj) + } + + gvk := u.GroupVersionKind() + + o, err := uc.cache.getObjMeta(obj) + if err != nil { + return err + } + + createOpts := &CreateOptions{} + createOpts.ApplyOptions(opts) + result := o.Post(). + NamespaceIfScoped(o.GetNamespace(), o.isNamespaced()). + Resource(o.resource()). + Body(obj). + VersionedParams(createOpts.AsCreateOptions(), uc.paramCodec). + Do(ctx). + Into(obj) + + u.SetGroupVersionKind(gvk) + return result +} + +// Update implements client.Client. +func (uc *unstructuredClient) Update(ctx context.Context, obj Object, opts ...UpdateOption) error { + u, ok := obj.(*unstructured.Unstructured) + if !ok { + return fmt.Errorf("unstructured client did not understand object: %T", obj) + } + + gvk := u.GroupVersionKind() + + o, err := uc.cache.getObjMeta(obj) + if err != nil { + return err + } + + updateOpts := UpdateOptions{} + updateOpts.ApplyOptions(opts) + result := o.Put(). + NamespaceIfScoped(o.GetNamespace(), o.isNamespaced()). + Resource(o.resource()). + Name(o.GetName()). + Body(obj). + VersionedParams(updateOpts.AsUpdateOptions(), uc.paramCodec). + Do(ctx). + Into(obj) + + u.SetGroupVersionKind(gvk) + return result +} + +// Delete implements client.Client. +func (uc *unstructuredClient) Delete(ctx context.Context, obj Object, opts ...DeleteOption) error { + if _, ok := obj.(*unstructured.Unstructured); !ok { + return fmt.Errorf("unstructured client did not understand object: %T", obj) + } + + o, err := uc.cache.getObjMeta(obj) + if err != nil { + return err + } + + deleteOpts := DeleteOptions{} + deleteOpts.ApplyOptions(opts) + return o.Delete(). + NamespaceIfScoped(o.GetNamespace(), o.isNamespaced()). + Resource(o.resource()). + Name(o.GetName()). + Body(deleteOpts.AsDeleteOptions()). + Do(ctx). + Error() +} + +// DeleteAllOf implements client.Client. +func (uc *unstructuredClient) DeleteAllOf(ctx context.Context, obj Object, opts ...DeleteAllOfOption) error { + if _, ok := obj.(*unstructured.Unstructured); !ok { + return fmt.Errorf("unstructured client did not understand object: %T", obj) + } + + o, err := uc.cache.getObjMeta(obj) + if err != nil { + return err + } + + deleteAllOfOpts := DeleteAllOfOptions{} + deleteAllOfOpts.ApplyOptions(opts) + return o.Delete(). + NamespaceIfScoped(deleteAllOfOpts.ListOptions.Namespace, o.isNamespaced()). + Resource(o.resource()). + VersionedParams(deleteAllOfOpts.AsListOptions(), uc.paramCodec). + Body(deleteAllOfOpts.AsDeleteOptions()). + Do(ctx). + Error() +} + +// Patch implements client.Client. +func (uc *unstructuredClient) Patch(ctx context.Context, obj Object, patch Patch, opts ...PatchOption) error { + if _, ok := obj.(*unstructured.Unstructured); !ok { + return fmt.Errorf("unstructured client did not understand object: %T", obj) + } + + o, err := uc.cache.getObjMeta(obj) + if err != nil { + return err + } + + data, err := patch.Data(obj) + if err != nil { + return err + } + + patchOpts := &PatchOptions{} + return o.Patch(patch.Type()). + NamespaceIfScoped(o.GetNamespace(), o.isNamespaced()). + Resource(o.resource()). + Name(o.GetName()). + VersionedParams(patchOpts.ApplyOptions(opts).AsPatchOptions(), uc.paramCodec). + Body(data). + Do(ctx). + Into(obj) +} + +// Get implements client.Client. +func (uc *unstructuredClient) Get(ctx context.Context, key ObjectKey, obj Object, opts ...GetOption) error { + u, ok := obj.(*unstructured.Unstructured) + if !ok { + return fmt.Errorf("unstructured client did not understand object: %T", obj) + } + + gvk := u.GroupVersionKind() + + getOpts := GetOptions{} + getOpts.ApplyOptions(opts) + + r, err := uc.cache.getResource(obj) + if err != nil { + return err + } + + result := r.Get(). + NamespaceIfScoped(key.Namespace, r.isNamespaced()). + Resource(r.resource()). + VersionedParams(getOpts.AsGetOptions(), uc.paramCodec). + Name(key.Name). + Do(ctx). + Into(obj) + + u.SetGroupVersionKind(gvk) + + return result +} + +// List implements client.Client. +func (uc *unstructuredClient) List(ctx context.Context, obj ObjectList, opts ...ListOption) error { + u, ok := obj.(*unstructured.UnstructuredList) + if !ok { + return fmt.Errorf("unstructured client did not understand object: %T", obj) + } + + gvk := u.GroupVersionKind() + gvk.Kind = strings.TrimSuffix(gvk.Kind, "List") + + listOpts := ListOptions{} + listOpts.ApplyOptions(opts) + + r, err := uc.cache.getResource(obj) + if err != nil { + return err + } + + return r.Get(). + NamespaceIfScoped(listOpts.Namespace, r.isNamespaced()). + Resource(r.resource()). + VersionedParams(listOpts.AsListOptions(), uc.paramCodec). + Do(ctx). + Into(obj) +} + +func (uc *unstructuredClient) UpdateStatus(ctx context.Context, obj Object, opts ...UpdateOption) error { + if _, ok := obj.(*unstructured.Unstructured); !ok { + return fmt.Errorf("unstructured client did not understand object: %T", obj) + } + + o, err := uc.cache.getObjMeta(obj) + if err != nil { + return err + } + + return o.Put(). + NamespaceIfScoped(o.GetNamespace(), o.isNamespaced()). + Resource(o.resource()). + Name(o.GetName()). + SubResource("status"). + Body(obj). + VersionedParams((&UpdateOptions{}).ApplyOptions(opts).AsUpdateOptions(), uc.paramCodec). + Do(ctx). + Into(obj) +} + +func (uc *unstructuredClient) PatchStatus(ctx context.Context, obj Object, patch Patch, opts ...PatchOption) error { + u, ok := obj.(*unstructured.Unstructured) + if !ok { + return fmt.Errorf("unstructured client did not understand object: %T", obj) + } + + gvk := u.GroupVersionKind() + + o, err := uc.cache.getObjMeta(obj) + if err != nil { + return err + } + + data, err := patch.Data(obj) + if err != nil { + return err + } + + patchOpts := &PatchOptions{} + result := o.Patch(patch.Type()). + NamespaceIfScoped(o.GetNamespace(), o.isNamespaced()). + Resource(o.resource()). + Name(o.GetName()). + SubResource("status"). + Body(data). + VersionedParams(patchOpts.ApplyOptions(opts).AsPatchOptions(), uc.paramCodec). + Do(ctx). + Into(u) + + u.SetGroupVersionKind(gvk) + return result +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/client/watch.go b/vendor/sigs.k8s.io/controller-runtime/pkg/client/watch.go new file mode 100644 index 0000000000..70490664bd --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/client/watch.go @@ -0,0 +1,114 @@ +/* +Copyright 2020 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package client + +import ( + "context" + "strings" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/watch" + "k8s.io/client-go/dynamic" + "k8s.io/client-go/rest" +) + +// NewWithWatch returns a new WithWatch. +func NewWithWatch(config *rest.Config, options Options) (WithWatch, error) { + client, err := newClient(config, options) + if err != nil { + return nil, err + } + dynamicClient, err := dynamic.NewForConfig(config) + if err != nil { + return nil, err + } + return &watchingClient{client: client, dynamic: dynamicClient}, nil +} + +type watchingClient struct { + *client + dynamic dynamic.Interface +} + +func (w *watchingClient) Watch(ctx context.Context, list ObjectList, opts ...ListOption) (watch.Interface, error) { + switch l := list.(type) { + case *unstructured.UnstructuredList: + return w.unstructuredWatch(ctx, l, opts...) + case *metav1.PartialObjectMetadataList: + return w.metadataWatch(ctx, l, opts...) + default: + return w.typedWatch(ctx, l, opts...) + } +} + +func (w *watchingClient) listOpts(opts ...ListOption) ListOptions { + listOpts := ListOptions{} + listOpts.ApplyOptions(opts) + if listOpts.Raw == nil { + listOpts.Raw = &metav1.ListOptions{} + } + listOpts.Raw.Watch = true + + return listOpts +} + +func (w *watchingClient) metadataWatch(ctx context.Context, obj *metav1.PartialObjectMetadataList, opts ...ListOption) (watch.Interface, error) { + gvk := obj.GroupVersionKind() + gvk.Kind = strings.TrimSuffix(gvk.Kind, "List") + + listOpts := w.listOpts(opts...) + + resInt, err := w.client.metadataClient.getResourceInterface(gvk, listOpts.Namespace) + if err != nil { + return nil, err + } + + return resInt.Watch(ctx, *listOpts.AsListOptions()) +} + +func (w *watchingClient) unstructuredWatch(ctx context.Context, obj *unstructured.UnstructuredList, opts ...ListOption) (watch.Interface, error) { + gvk := obj.GroupVersionKind() + gvk.Kind = strings.TrimSuffix(gvk.Kind, "List") + + r, err := w.client.unstructuredClient.cache.getResource(obj) + if err != nil { + return nil, err + } + + listOpts := w.listOpts(opts...) + + if listOpts.Namespace != "" && r.isNamespaced() { + return w.dynamic.Resource(r.mapping.Resource).Namespace(listOpts.Namespace).Watch(ctx, *listOpts.AsListOptions()) + } + return w.dynamic.Resource(r.mapping.Resource).Watch(ctx, *listOpts.AsListOptions()) +} + +func (w *watchingClient) typedWatch(ctx context.Context, obj ObjectList, opts ...ListOption) (watch.Interface, error) { + r, err := w.client.typedClient.cache.getResource(obj) + if err != nil { + return nil, err + } + + listOpts := w.listOpts(opts...) + + return r.Get(). + NamespaceIfScoped(listOpts.Namespace, r.isNamespaced()). + Resource(r.resource()). + VersionedParams(listOpts.AsListOptions(), w.client.typedClient.paramCodec). + Watch(ctx) +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/cluster/cluster.go b/vendor/sigs.k8s.io/controller-runtime/pkg/cluster/cluster.go new file mode 100644 index 0000000000..4b8ee8e7c5 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/cluster/cluster.go @@ -0,0 +1,270 @@ +/* +Copyright 2020 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package cluster + +import ( + "context" + "errors" + "time" + + "github.com/go-logr/logr" + "k8s.io/apimachinery/pkg/api/meta" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/kubernetes/scheme" + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/record" + "sigs.k8s.io/controller-runtime/pkg/client/apiutil" + logf "sigs.k8s.io/controller-runtime/pkg/internal/log" + + "sigs.k8s.io/controller-runtime/pkg/cache" + "sigs.k8s.io/controller-runtime/pkg/client" + intrec "sigs.k8s.io/controller-runtime/pkg/internal/recorder" +) + +// Cluster provides various methods to interact with a cluster. +type Cluster interface { + // SetFields will set any dependencies on an object for which the object has implemented the inject + // interface - e.g. inject.Client. + // Deprecated: use the equivalent Options field to set a field. This method will be removed in v0.10. + SetFields(interface{}) error + + // GetConfig returns an initialized Config + GetConfig() *rest.Config + + // GetScheme returns an initialized Scheme + GetScheme() *runtime.Scheme + + // GetClient returns a client configured with the Config. This client may + // not be a fully "direct" client -- it may read from a cache, for + // instance. See Options.NewClient for more information on how the default + // implementation works. + GetClient() client.Client + + // GetFieldIndexer returns a client.FieldIndexer configured with the client + GetFieldIndexer() client.FieldIndexer + + // GetCache returns a cache.Cache + GetCache() cache.Cache + + // GetEventRecorderFor returns a new EventRecorder for the provided name + GetEventRecorderFor(name string) record.EventRecorder + + // GetRESTMapper returns a RESTMapper + GetRESTMapper() meta.RESTMapper + + // GetAPIReader returns a reader that will be configured to use the API server. + // This should be used sparingly and only when the client does not fit your + // use case. + GetAPIReader() client.Reader + + // Start starts the cluster + Start(ctx context.Context) error +} + +// Options are the possible options that can be configured for a Cluster. +type Options struct { + // Scheme is the scheme used to resolve runtime.Objects to GroupVersionKinds / Resources + // Defaults to the kubernetes/client-go scheme.Scheme, but it's almost always better + // idea to pass your own scheme in. See the documentation in pkg/scheme for more information. + Scheme *runtime.Scheme + + // MapperProvider provides the rest mapper used to map go types to Kubernetes APIs + MapperProvider func(c *rest.Config) (meta.RESTMapper, error) + + // Logger is the logger that should be used by this Cluster. + // If none is set, it defaults to log.Log global logger. + Logger logr.Logger + + // SyncPeriod determines the minimum frequency at which watched resources are + // reconciled. A lower period will correct entropy more quickly, but reduce + // responsiveness to change if there are many watched resources. Change this + // value only if you know what you are doing. Defaults to 10 hours if unset. + // there will a 10 percent jitter between the SyncPeriod of all controllers + // so that all controllers will not send list requests simultaneously. + SyncPeriod *time.Duration + + // Namespace if specified restricts the manager's cache to watch objects in + // the desired namespace Defaults to all namespaces + // + // Note: If a namespace is specified, controllers can still Watch for a + // cluster-scoped resource (e.g Node). For namespaced resources the cache + // will only hold objects from the desired namespace. + Namespace string + + // NewCache is the function that will create the cache to be used + // by the manager. If not set this will use the default new cache function. + NewCache cache.NewCacheFunc + + // NewClient is the func that creates the client to be used by the manager. + // If not set this will create the default DelegatingClient that will + // use the cache for reads and the client for writes. + NewClient NewClientFunc + + // ClientDisableCacheFor tells the client that, if any cache is used, to bypass it + // for the given objects. + ClientDisableCacheFor []client.Object + + // DryRunClient specifies whether the client should be configured to enforce + // dryRun mode. + DryRunClient bool + + // EventBroadcaster records Events emitted by the manager and sends them to the Kubernetes API + // Use this to customize the event correlator and spam filter + // + // Deprecated: using this may cause goroutine leaks if the lifetime of your manager or controllers + // is shorter than the lifetime of your process. + EventBroadcaster record.EventBroadcaster + + // makeBroadcaster allows deferring the creation of the broadcaster to + // avoid leaking goroutines if we never call Start on this manager. It also + // returns whether or not this is a "owned" broadcaster, and as such should be + // stopped with the manager. + makeBroadcaster intrec.EventBroadcasterProducer + + // Dependency injection for testing + newRecorderProvider func(config *rest.Config, scheme *runtime.Scheme, logger logr.Logger, makeBroadcaster intrec.EventBroadcasterProducer) (*intrec.Provider, error) +} + +// Option can be used to manipulate Options. +type Option func(*Options) + +// New constructs a brand new cluster. +func New(config *rest.Config, opts ...Option) (Cluster, error) { + if config == nil { + return nil, errors.New("must specify Config") + } + + options := Options{} + for _, opt := range opts { + opt(&options) + } + options = setOptionsDefaults(options) + + // Create the mapper provider + mapper, err := options.MapperProvider(config) + if err != nil { + options.Logger.Error(err, "Failed to get API Group-Resources") + return nil, err + } + + // Create the cache for the cached read client and registering informers + cache, err := options.NewCache(config, cache.Options{Scheme: options.Scheme, Mapper: mapper, Resync: options.SyncPeriod, Namespace: options.Namespace}) + if err != nil { + return nil, err + } + + clientOptions := client.Options{Scheme: options.Scheme, Mapper: mapper} + + apiReader, err := client.New(config, clientOptions) + if err != nil { + return nil, err + } + + writeObj, err := options.NewClient(cache, config, clientOptions, options.ClientDisableCacheFor...) + if err != nil { + return nil, err + } + + if options.DryRunClient { + writeObj = client.NewDryRunClient(writeObj) + } + + // Create the recorder provider to inject event recorders for the components. + // TODO(directxman12): the log for the event provider should have a context (name, tags, etc) specific + // to the particular controller that it's being injected into, rather than a generic one like is here. + recorderProvider, err := options.newRecorderProvider(config, options.Scheme, options.Logger.WithName("events"), options.makeBroadcaster) + if err != nil { + return nil, err + } + + return &cluster{ + config: config, + scheme: options.Scheme, + cache: cache, + fieldIndexes: cache, + client: writeObj, + apiReader: apiReader, + recorderProvider: recorderProvider, + mapper: mapper, + logger: options.Logger, + }, nil +} + +// setOptionsDefaults set default values for Options fields. +func setOptionsDefaults(options Options) Options { + // Use the Kubernetes client-go scheme if none is specified + if options.Scheme == nil { + options.Scheme = scheme.Scheme + } + + if options.MapperProvider == nil { + options.MapperProvider = func(c *rest.Config) (meta.RESTMapper, error) { + return apiutil.NewDynamicRESTMapper(c) + } + } + + // Allow users to define how to create a new client + if options.NewClient == nil { + options.NewClient = DefaultNewClient + } + + // Allow newCache to be mocked + if options.NewCache == nil { + options.NewCache = cache.New + } + + // Allow newRecorderProvider to be mocked + if options.newRecorderProvider == nil { + options.newRecorderProvider = intrec.NewProvider + } + + // This is duplicated with pkg/manager, we need it here to provide + // the user with an EventBroadcaster and there for the Leader election + if options.EventBroadcaster == nil { + // defer initialization to avoid leaking by default + options.makeBroadcaster = func() (record.EventBroadcaster, bool) { + return record.NewBroadcaster(), true + } + } else { + options.makeBroadcaster = func() (record.EventBroadcaster, bool) { + return options.EventBroadcaster, false + } + } + + if options.Logger.GetSink() == nil { + options.Logger = logf.RuntimeLog.WithName("cluster") + } + + return options +} + +// NewClientFunc allows a user to define how to create a client. +type NewClientFunc func(cache cache.Cache, config *rest.Config, options client.Options, uncachedObjects ...client.Object) (client.Client, error) + +// DefaultNewClient creates the default caching client. +func DefaultNewClient(cache cache.Cache, config *rest.Config, options client.Options, uncachedObjects ...client.Object) (client.Client, error) { + c, err := client.New(config, options) + if err != nil { + return nil, err + } + + return client.NewDelegatingClient(client.NewDelegatingClientInput{ + CacheReader: cache, + Client: c, + UncachedObjects: uncachedObjects, + }) +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/cluster/internal.go b/vendor/sigs.k8s.io/controller-runtime/pkg/cluster/internal.go new file mode 100644 index 0000000000..125e1d144e --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/cluster/internal.go @@ -0,0 +1,128 @@ +/* +Copyright 2020 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package cluster + +import ( + "context" + + "github.com/go-logr/logr" + "k8s.io/apimachinery/pkg/api/meta" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/record" + + "sigs.k8s.io/controller-runtime/pkg/cache" + "sigs.k8s.io/controller-runtime/pkg/client" + intrec "sigs.k8s.io/controller-runtime/pkg/internal/recorder" + "sigs.k8s.io/controller-runtime/pkg/runtime/inject" +) + +type cluster struct { + // config is the rest.config used to talk to the apiserver. Required. + config *rest.Config + + // scheme is the scheme injected into Controllers, EventHandlers, Sources and Predicates. Defaults + // to scheme.scheme. + scheme *runtime.Scheme + + cache cache.Cache + + // TODO(directxman12): Provide an escape hatch to get individual indexers + // client is the client injected into Controllers (and EventHandlers, Sources and Predicates). + client client.Client + + // apiReader is the reader that will make requests to the api server and not the cache. + apiReader client.Reader + + // fieldIndexes knows how to add field indexes over the Cache used by this controller, + // which can later be consumed via field selectors from the injected client. + fieldIndexes client.FieldIndexer + + // recorderProvider is used to generate event recorders that will be injected into Controllers + // (and EventHandlers, Sources and Predicates). + recorderProvider *intrec.Provider + + // mapper is used to map resources to kind, and map kind and version. + mapper meta.RESTMapper + + // Logger is the logger that should be used by this manager. + // If none is set, it defaults to log.Log global logger. + logger logr.Logger +} + +func (c *cluster) SetFields(i interface{}) error { + if _, err := inject.ConfigInto(c.config, i); err != nil { + return err + } + if _, err := inject.ClientInto(c.client, i); err != nil { + return err + } + if _, err := inject.APIReaderInto(c.apiReader, i); err != nil { + return err + } + if _, err := inject.SchemeInto(c.scheme, i); err != nil { + return err + } + if _, err := inject.CacheInto(c.cache, i); err != nil { + return err + } + if _, err := inject.MapperInto(c.mapper, i); err != nil { + return err + } + return nil +} + +func (c *cluster) GetConfig() *rest.Config { + return c.config +} + +func (c *cluster) GetClient() client.Client { + return c.client +} + +func (c *cluster) GetScheme() *runtime.Scheme { + return c.scheme +} + +func (c *cluster) GetFieldIndexer() client.FieldIndexer { + return c.fieldIndexes +} + +func (c *cluster) GetCache() cache.Cache { + return c.cache +} + +func (c *cluster) GetEventRecorderFor(name string) record.EventRecorder { + return c.recorderProvider.GetEventRecorderFor(name) +} + +func (c *cluster) GetRESTMapper() meta.RESTMapper { + return c.mapper +} + +func (c *cluster) GetAPIReader() client.Reader { + return c.apiReader +} + +func (c *cluster) GetLogger() logr.Logger { + return c.logger +} + +func (c *cluster) Start(ctx context.Context) error { + defer c.recorderProvider.Stop(ctx) + return c.cache.Start(ctx) +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/config/config.go b/vendor/sigs.k8s.io/controller-runtime/pkg/config/config.go new file mode 100644 index 0000000000..8e853d6a0f --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/config/config.go @@ -0,0 +1,112 @@ +/* +Copyright 2020 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package config + +import ( + "fmt" + "os" + "sync" + + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/serializer" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + "sigs.k8s.io/controller-runtime/pkg/config/v1alpha1" +) + +// ControllerManagerConfiguration defines the functions necessary to parse a config file +// and to configure the Options struct for the ctrl.Manager. +type ControllerManagerConfiguration interface { + runtime.Object + + // Complete returns the versioned configuration + Complete() (v1alpha1.ControllerManagerConfigurationSpec, error) +} + +// DeferredFileLoader is used to configure the decoder for loading controller +// runtime component config types. +type DeferredFileLoader struct { + ControllerManagerConfiguration + path string + scheme *runtime.Scheme + once sync.Once + err error +} + +// File will set up the deferred file loader for the configuration +// this will also configure the defaults for the loader if nothing is +// +// Defaults: +// * Path: "./config.yaml" +// * Kind: GenericControllerManagerConfiguration +func File() *DeferredFileLoader { + scheme := runtime.NewScheme() + utilruntime.Must(v1alpha1.AddToScheme(scheme)) + return &DeferredFileLoader{ + path: "./config.yaml", + ControllerManagerConfiguration: &v1alpha1.ControllerManagerConfiguration{}, + scheme: scheme, + } +} + +// Complete will use sync.Once to set the scheme. +func (d *DeferredFileLoader) Complete() (v1alpha1.ControllerManagerConfigurationSpec, error) { + d.once.Do(d.loadFile) + if d.err != nil { + return v1alpha1.ControllerManagerConfigurationSpec{}, d.err + } + return d.ControllerManagerConfiguration.Complete() +} + +// AtPath will set the path to load the file for the decoder. +func (d *DeferredFileLoader) AtPath(path string) *DeferredFileLoader { + d.path = path + return d +} + +// OfKind will set the type to be used for decoding the file into. +func (d *DeferredFileLoader) OfKind(obj ControllerManagerConfiguration) *DeferredFileLoader { + d.ControllerManagerConfiguration = obj + return d +} + +// InjectScheme will configure the scheme to be used for decoding the file. +func (d *DeferredFileLoader) InjectScheme(scheme *runtime.Scheme) error { + d.scheme = scheme + return nil +} + +// loadFile is used from the mutex.Once to load the file. +func (d *DeferredFileLoader) loadFile() { + if d.scheme == nil { + d.err = fmt.Errorf("scheme not supplied to controller configuration loader") + return + } + + content, err := os.ReadFile(d.path) + if err != nil { + d.err = fmt.Errorf("could not read file at %s", d.path) + return + } + + codecs := serializer.NewCodecFactory(d.scheme) + + // Regardless of if the bytes are of any external version, + // it will be read successfully and converted into the internal version + if err = runtime.DecodeInto(codecs.UniversalDecoder(), content, d.ControllerManagerConfiguration); err != nil { + d.err = fmt.Errorf("could not decode file into runtime.Object") + } +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/config/doc.go b/vendor/sigs.k8s.io/controller-runtime/pkg/config/doc.go new file mode 100644 index 0000000000..a169ec5597 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/config/doc.go @@ -0,0 +1,25 @@ +/* +Copyright 2020 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package config contains functionality for interacting with ComponentConfig +// files +// +// # DeferredFileLoader +// +// This uses a deferred file decoding allowing you to chain your configuration +// setup. You can pass this into manager.Options#File and it will load your +// config. +package config diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/config/v1alpha1/doc.go b/vendor/sigs.k8s.io/controller-runtime/pkg/config/v1alpha1/doc.go new file mode 100644 index 0000000000..1e3adbafb8 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/config/v1alpha1/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 2020 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package v1alpha1 provides the ControllerManagerConfiguration used for +// configuring ctrl.Manager +// +kubebuilder:object:generate=true +package v1alpha1 diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/config/v1alpha1/register.go b/vendor/sigs.k8s.io/controller-runtime/pkg/config/v1alpha1/register.go new file mode 100644 index 0000000000..9efdbc0668 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/config/v1alpha1/register.go @@ -0,0 +1,37 @@ +/* +Copyright 2020 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + "k8s.io/apimachinery/pkg/runtime/schema" + "sigs.k8s.io/controller-runtime/pkg/scheme" +) + +var ( + // GroupVersion is group version used to register these objects. + GroupVersion = schema.GroupVersion{Group: "controller-runtime.sigs.k8s.io", Version: "v1alpha1"} + + // SchemeBuilder is used to add go types to the GroupVersionKind scheme. + SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} + + // AddToScheme adds the types in this group-version to the given scheme. + AddToScheme = SchemeBuilder.AddToScheme +) + +func init() { + SchemeBuilder.Register(&ControllerManagerConfiguration{}) +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/config/v1alpha1/types.go b/vendor/sigs.k8s.io/controller-runtime/pkg/config/v1alpha1/types.go new file mode 100644 index 0000000000..e67b62e514 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/config/v1alpha1/types.go @@ -0,0 +1,157 @@ +/* +Copyright 2020 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + configv1alpha1 "k8s.io/component-base/config/v1alpha1" +) + +// ControllerManagerConfigurationSpec defines the desired state of GenericControllerManagerConfiguration. +type ControllerManagerConfigurationSpec struct { + // SyncPeriod determines the minimum frequency at which watched resources are + // reconciled. A lower period will correct entropy more quickly, but reduce + // responsiveness to change if there are many watched resources. Change this + // value only if you know what you are doing. Defaults to 10 hours if unset. + // there will a 10 percent jitter between the SyncPeriod of all controllers + // so that all controllers will not send list requests simultaneously. + // +optional + SyncPeriod *metav1.Duration `json:"syncPeriod,omitempty"` + + // LeaderElection is the LeaderElection config to be used when configuring + // the manager.Manager leader election + // +optional + LeaderElection *configv1alpha1.LeaderElectionConfiguration `json:"leaderElection,omitempty"` + + // CacheNamespace if specified restricts the manager's cache to watch objects in + // the desired namespace Defaults to all namespaces + // + // Note: If a namespace is specified, controllers can still Watch for a + // cluster-scoped resource (e.g Node). For namespaced resources the cache + // will only hold objects from the desired namespace. + // +optional + CacheNamespace string `json:"cacheNamespace,omitempty"` + + // GracefulShutdownTimeout is the duration given to runnable to stop before the manager actually returns on stop. + // To disable graceful shutdown, set to time.Duration(0) + // To use graceful shutdown without timeout, set to a negative duration, e.G. time.Duration(-1) + // The graceful shutdown is skipped for safety reasons in case the leader election lease is lost. + GracefulShutdownTimeout *metav1.Duration `json:"gracefulShutDown,omitempty"` + + // Controller contains global configuration options for controllers + // registered within this manager. + // +optional + Controller *ControllerConfigurationSpec `json:"controller,omitempty"` + + // Metrics contains thw controller metrics configuration + // +optional + Metrics ControllerMetrics `json:"metrics,omitempty"` + + // Health contains the controller health configuration + // +optional + Health ControllerHealth `json:"health,omitempty"` + + // Webhook contains the controllers webhook configuration + // +optional + Webhook ControllerWebhook `json:"webhook,omitempty"` +} + +// ControllerConfigurationSpec defines the global configuration for +// controllers registered with the manager. +type ControllerConfigurationSpec struct { + // GroupKindConcurrency is a map from a Kind to the number of concurrent reconciliation + // allowed for that controller. + // + // When a controller is registered within this manager using the builder utilities, + // users have to specify the type the controller reconciles in the For(...) call. + // If the object's kind passed matches one of the keys in this map, the concurrency + // for that controller is set to the number specified. + // + // The key is expected to be consistent in form with GroupKind.String(), + // e.g. ReplicaSet in apps group (regardless of version) would be `ReplicaSet.apps`. + // + // +optional + GroupKindConcurrency map[string]int `json:"groupKindConcurrency,omitempty"` + + // CacheSyncTimeout refers to the time limit set to wait for syncing caches. + // Defaults to 2 minutes if not set. + // +optional + CacheSyncTimeout *time.Duration `json:"cacheSyncTimeout,omitempty"` +} + +// ControllerMetrics defines the metrics configs. +type ControllerMetrics struct { + // BindAddress is the TCP address that the controller should bind to + // for serving prometheus metrics. + // It can be set to "0" to disable the metrics serving. + // +optional + BindAddress string `json:"bindAddress,omitempty"` +} + +// ControllerHealth defines the health configs. +type ControllerHealth struct { + // HealthProbeBindAddress is the TCP address that the controller should bind to + // for serving health probes + // +optional + HealthProbeBindAddress string `json:"healthProbeBindAddress,omitempty"` + + // ReadinessEndpointName, defaults to "readyz" + // +optional + ReadinessEndpointName string `json:"readinessEndpointName,omitempty"` + + // LivenessEndpointName, defaults to "healthz" + // +optional + LivenessEndpointName string `json:"livenessEndpointName,omitempty"` +} + +// ControllerWebhook defines the webhook server for the controller. +type ControllerWebhook struct { + // Port is the port that the webhook server serves at. + // It is used to set webhook.Server.Port. + // +optional + Port *int `json:"port,omitempty"` + + // Host is the hostname that the webhook server binds to. + // It is used to set webhook.Server.Host. + // +optional + Host string `json:"host,omitempty"` + + // CertDir is the directory that contains the server key and certificate. + // if not set, webhook server would look up the server key and certificate in + // {TempDir}/k8s-webhook-server/serving-certs. The server key and certificate + // must be named tls.key and tls.crt, respectively. + // +optional + CertDir string `json:"certDir,omitempty"` +} + +// +kubebuilder:object:root=true + +// ControllerManagerConfiguration is the Schema for the GenericControllerManagerConfigurations API. +type ControllerManagerConfiguration struct { + metav1.TypeMeta `json:",inline"` + + // ControllerManagerConfiguration returns the contfigurations for controllers + ControllerManagerConfigurationSpec `json:",inline"` +} + +// Complete returns the configuration for controller-runtime. +func (c *ControllerManagerConfigurationSpec) Complete() (ControllerManagerConfigurationSpec, error) { + return *c, nil +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/config/v1alpha1/zz_generated.deepcopy.go b/vendor/sigs.k8s.io/controller-runtime/pkg/config/v1alpha1/zz_generated.deepcopy.go new file mode 100644 index 0000000000..5329bef667 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/config/v1alpha1/zz_generated.deepcopy.go @@ -0,0 +1,153 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +// Code generated by controller-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + configv1alpha1 "k8s.io/component-base/config/v1alpha1" + timex "time" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ControllerConfigurationSpec) DeepCopyInto(out *ControllerConfigurationSpec) { + *out = *in + if in.GroupKindConcurrency != nil { + in, out := &in.GroupKindConcurrency, &out.GroupKindConcurrency + *out = make(map[string]int, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.CacheSyncTimeout != nil { + in, out := &in.CacheSyncTimeout, &out.CacheSyncTimeout + *out = new(timex.Duration) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ControllerConfigurationSpec. +func (in *ControllerConfigurationSpec) DeepCopy() *ControllerConfigurationSpec { + if in == nil { + return nil + } + out := new(ControllerConfigurationSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ControllerHealth) DeepCopyInto(out *ControllerHealth) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ControllerHealth. +func (in *ControllerHealth) DeepCopy() *ControllerHealth { + if in == nil { + return nil + } + out := new(ControllerHealth) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ControllerManagerConfiguration) DeepCopyInto(out *ControllerManagerConfiguration) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ControllerManagerConfigurationSpec.DeepCopyInto(&out.ControllerManagerConfigurationSpec) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ControllerManagerConfiguration. +func (in *ControllerManagerConfiguration) DeepCopy() *ControllerManagerConfiguration { + if in == nil { + return nil + } + out := new(ControllerManagerConfiguration) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ControllerManagerConfiguration) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ControllerManagerConfigurationSpec) DeepCopyInto(out *ControllerManagerConfigurationSpec) { + *out = *in + if in.SyncPeriod != nil { + in, out := &in.SyncPeriod, &out.SyncPeriod + *out = new(v1.Duration) + **out = **in + } + if in.LeaderElection != nil { + in, out := &in.LeaderElection, &out.LeaderElection + *out = new(configv1alpha1.LeaderElectionConfiguration) + (*in).DeepCopyInto(*out) + } + if in.GracefulShutdownTimeout != nil { + in, out := &in.GracefulShutdownTimeout, &out.GracefulShutdownTimeout + *out = new(v1.Duration) + **out = **in + } + if in.Controller != nil { + in, out := &in.Controller, &out.Controller + *out = new(ControllerConfigurationSpec) + (*in).DeepCopyInto(*out) + } + out.Metrics = in.Metrics + out.Health = in.Health + in.Webhook.DeepCopyInto(&out.Webhook) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ControllerManagerConfigurationSpec. +func (in *ControllerManagerConfigurationSpec) DeepCopy() *ControllerManagerConfigurationSpec { + if in == nil { + return nil + } + out := new(ControllerManagerConfigurationSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ControllerMetrics) DeepCopyInto(out *ControllerMetrics) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ControllerMetrics. +func (in *ControllerMetrics) DeepCopy() *ControllerMetrics { + if in == nil { + return nil + } + out := new(ControllerMetrics) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ControllerWebhook) DeepCopyInto(out *ControllerWebhook) { + *out = *in + if in.Port != nil { + in, out := &in.Port, &out.Port + *out = new(int) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ControllerWebhook. +func (in *ControllerWebhook) DeepCopy() *ControllerWebhook { + if in == nil { + return nil + } + out := new(ControllerWebhook) + in.DeepCopyInto(out) + return out +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/controller/controller.go b/vendor/sigs.k8s.io/controller-runtime/pkg/controller/controller.go new file mode 100644 index 0000000000..8e3d8591d6 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/controller/controller.go @@ -0,0 +1,155 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package controller + +import ( + "context" + "fmt" + "time" + + "github.com/go-logr/logr" + "k8s.io/client-go/util/workqueue" + "k8s.io/klog/v2" + + "sigs.k8s.io/controller-runtime/pkg/handler" + "sigs.k8s.io/controller-runtime/pkg/internal/controller" + "sigs.k8s.io/controller-runtime/pkg/manager" + "sigs.k8s.io/controller-runtime/pkg/predicate" + "sigs.k8s.io/controller-runtime/pkg/ratelimiter" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + "sigs.k8s.io/controller-runtime/pkg/source" +) + +// Options are the arguments for creating a new Controller. +type Options struct { + // MaxConcurrentReconciles is the maximum number of concurrent Reconciles which can be run. Defaults to 1. + MaxConcurrentReconciles int + + // Reconciler reconciles an object + Reconciler reconcile.Reconciler + + // RateLimiter is used to limit how frequently requests may be queued. + // Defaults to MaxOfRateLimiter which has both overall and per-item rate limiting. + // The overall is a token bucket and the per-item is exponential. + RateLimiter ratelimiter.RateLimiter + + // LogConstructor is used to construct a logger used for this controller and passed + // to each reconciliation via the context field. + LogConstructor func(request *reconcile.Request) logr.Logger + + // CacheSyncTimeout refers to the time limit set to wait for syncing caches. + // Defaults to 2 minutes if not set. + CacheSyncTimeout time.Duration + + // RecoverPanic indicates whether the panic caused by reconcile should be recovered. + RecoverPanic bool +} + +// Controller implements a Kubernetes API. A Controller manages a work queue fed reconcile.Requests +// from source.Sources. Work is performed through the reconcile.Reconciler for each enqueued item. +// Work typically is reads and writes Kubernetes objects to make the system state match the state specified +// in the object Spec. +type Controller interface { + // Reconciler is called to reconcile an object by Namespace/Name + reconcile.Reconciler + + // Watch takes events provided by a Source and uses the EventHandler to + // enqueue reconcile.Requests in response to the events. + // + // Watch may be provided one or more Predicates to filter events before + // they are given to the EventHandler. Events will be passed to the + // EventHandler if all provided Predicates evaluate to true. + Watch(src source.Source, eventhandler handler.EventHandler, predicates ...predicate.Predicate) error + + // Start starts the controller. Start blocks until the context is closed or a + // controller has an error starting. + Start(ctx context.Context) error + + // GetLogger returns this controller logger prefilled with basic information. + GetLogger() logr.Logger +} + +// New returns a new Controller registered with the Manager. The Manager will ensure that shared Caches have +// been synced before the Controller is Started. +func New(name string, mgr manager.Manager, options Options) (Controller, error) { + c, err := NewUnmanaged(name, mgr, options) + if err != nil { + return nil, err + } + + // Add the controller as a Manager components + return c, mgr.Add(c) +} + +// NewUnmanaged returns a new controller without adding it to the manager. The +// caller is responsible for starting the returned controller. +func NewUnmanaged(name string, mgr manager.Manager, options Options) (Controller, error) { + if options.Reconciler == nil { + return nil, fmt.Errorf("must specify Reconciler") + } + + if len(name) == 0 { + return nil, fmt.Errorf("must specify Name for Controller") + } + + if options.LogConstructor == nil { + log := mgr.GetLogger().WithValues( + "controller", name, + ) + options.LogConstructor = func(req *reconcile.Request) logr.Logger { + log := log + if req != nil { + log = log.WithValues( + "object", klog.KRef(req.Namespace, req.Name), + "namespace", req.Namespace, "name", req.Name, + ) + } + return log + } + } + + if options.MaxConcurrentReconciles <= 0 { + options.MaxConcurrentReconciles = 1 + } + + if options.CacheSyncTimeout == 0 { + options.CacheSyncTimeout = 2 * time.Minute + } + + if options.RateLimiter == nil { + options.RateLimiter = workqueue.DefaultControllerRateLimiter() + } + + // Inject dependencies into Reconciler + if err := mgr.SetFields(options.Reconciler); err != nil { + return nil, err + } + + // Create controller with dependencies set + return &controller.Controller{ + Do: options.Reconciler, + MakeQueue: func() workqueue.RateLimitingInterface { + return workqueue.NewNamedRateLimitingQueue(options.RateLimiter, name) + }, + MaxConcurrentReconciles: options.MaxConcurrentReconciles, + CacheSyncTimeout: options.CacheSyncTimeout, + SetFields: mgr.SetFields, + Name: name, + LogConstructor: options.LogConstructor, + RecoverPanic: options.RecoverPanic, + }, nil +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/controller/controllerutil/controllerutil.go b/vendor/sigs.k8s.io/controller-runtime/pkg/controller/controllerutil/controllerutil.go new file mode 100644 index 0000000000..aa53a77d41 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/controller/controllerutil/controllerutil.go @@ -0,0 +1,394 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package controllerutil + +import ( + "context" + "fmt" + "reflect" + + "k8s.io/apimachinery/pkg/api/equality" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/utils/pointer" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/apiutil" +) + +// AlreadyOwnedError is an error returned if the object you are trying to assign +// a controller reference is already owned by another controller Object is the +// subject and Owner is the reference for the current owner. +type AlreadyOwnedError struct { + Object metav1.Object + Owner metav1.OwnerReference +} + +func (e *AlreadyOwnedError) Error() string { + return fmt.Sprintf("Object %s/%s is already owned by another %s controller %s", e.Object.GetNamespace(), e.Object.GetName(), e.Owner.Kind, e.Owner.Name) +} + +func newAlreadyOwnedError(obj metav1.Object, owner metav1.OwnerReference) *AlreadyOwnedError { + return &AlreadyOwnedError{ + Object: obj, + Owner: owner, + } +} + +// SetControllerReference sets owner as a Controller OwnerReference on controlled. +// This is used for garbage collection of the controlled object and for +// reconciling the owner object on changes to controlled (with a Watch + EnqueueRequestForOwner). +// Since only one OwnerReference can be a controller, it returns an error if +// there is another OwnerReference with Controller flag set. +func SetControllerReference(owner, controlled metav1.Object, scheme *runtime.Scheme) error { + // Validate the owner. + ro, ok := owner.(runtime.Object) + if !ok { + return fmt.Errorf("%T is not a runtime.Object, cannot call SetControllerReference", owner) + } + if err := validateOwner(owner, controlled); err != nil { + return err + } + + // Create a new controller ref. + gvk, err := apiutil.GVKForObject(ro, scheme) + if err != nil { + return err + } + ref := metav1.OwnerReference{ + APIVersion: gvk.GroupVersion().String(), + Kind: gvk.Kind, + Name: owner.GetName(), + UID: owner.GetUID(), + BlockOwnerDeletion: pointer.BoolPtr(true), + Controller: pointer.BoolPtr(true), + } + + // Return early with an error if the object is already controlled. + if existing := metav1.GetControllerOf(controlled); existing != nil && !referSameObject(*existing, ref) { + return newAlreadyOwnedError(controlled, *existing) + } + + // Update owner references and return. + upsertOwnerRef(ref, controlled) + return nil +} + +// SetOwnerReference is a helper method to make sure the given object contains an object reference to the object provided. +// This allows you to declare that owner has a dependency on the object without specifying it as a controller. +// If a reference to the same object already exists, it'll be overwritten with the newly provided version. +func SetOwnerReference(owner, object metav1.Object, scheme *runtime.Scheme) error { + // Validate the owner. + ro, ok := owner.(runtime.Object) + if !ok { + return fmt.Errorf("%T is not a runtime.Object, cannot call SetOwnerReference", owner) + } + if err := validateOwner(owner, object); err != nil { + return err + } + + // Create a new owner ref. + gvk, err := apiutil.GVKForObject(ro, scheme) + if err != nil { + return err + } + ref := metav1.OwnerReference{ + APIVersion: gvk.GroupVersion().String(), + Kind: gvk.Kind, + UID: owner.GetUID(), + Name: owner.GetName(), + } + + // Update owner references and return. + upsertOwnerRef(ref, object) + return nil +} + +func upsertOwnerRef(ref metav1.OwnerReference, object metav1.Object) { + owners := object.GetOwnerReferences() + if idx := indexOwnerRef(owners, ref); idx == -1 { + owners = append(owners, ref) + } else { + owners[idx] = ref + } + object.SetOwnerReferences(owners) +} + +// indexOwnerRef returns the index of the owner reference in the slice if found, or -1. +func indexOwnerRef(ownerReferences []metav1.OwnerReference, ref metav1.OwnerReference) int { + for index, r := range ownerReferences { + if referSameObject(r, ref) { + return index + } + } + return -1 +} + +func validateOwner(owner, object metav1.Object) error { + ownerNs := owner.GetNamespace() + if ownerNs != "" { + objNs := object.GetNamespace() + if objNs == "" { + return fmt.Errorf("cluster-scoped resource must not have a namespace-scoped owner, owner's namespace %s", ownerNs) + } + if ownerNs != objNs { + return fmt.Errorf("cross-namespace owner references are disallowed, owner's namespace %s, obj's namespace %s", owner.GetNamespace(), object.GetNamespace()) + } + } + return nil +} + +// Returns true if a and b point to the same object. +func referSameObject(a, b metav1.OwnerReference) bool { + aGV, err := schema.ParseGroupVersion(a.APIVersion) + if err != nil { + return false + } + + bGV, err := schema.ParseGroupVersion(b.APIVersion) + if err != nil { + return false + } + + return aGV.Group == bGV.Group && a.Kind == b.Kind && a.Name == b.Name +} + +// OperationResult is the action result of a CreateOrUpdate call. +type OperationResult string + +const ( // They should complete the sentence "Deployment default/foo has been ..." + // OperationResultNone means that the resource has not been changed. + OperationResultNone OperationResult = "unchanged" + // OperationResultCreated means that a new resource is created. + OperationResultCreated OperationResult = "created" + // OperationResultUpdated means that an existing resource is updated. + OperationResultUpdated OperationResult = "updated" + // OperationResultUpdatedStatus means that an existing resource and its status is updated. + OperationResultUpdatedStatus OperationResult = "updatedStatus" + // OperationResultUpdatedStatusOnly means that only an existing status is updated. + OperationResultUpdatedStatusOnly OperationResult = "updatedStatusOnly" +) + +// CreateOrUpdate creates or updates the given object in the Kubernetes +// cluster. The object's desired state must be reconciled with the existing +// state inside the passed in callback MutateFn. +// +// The MutateFn is called regardless of creating or updating an object. +// +// It returns the executed operation and an error. +func CreateOrUpdate(ctx context.Context, c client.Client, obj client.Object, f MutateFn) (OperationResult, error) { + key := client.ObjectKeyFromObject(obj) + if err := c.Get(ctx, key, obj); err != nil { + if !apierrors.IsNotFound(err) { + return OperationResultNone, err + } + if err := mutate(f, key, obj); err != nil { + return OperationResultNone, err + } + if err := c.Create(ctx, obj); err != nil { + return OperationResultNone, err + } + return OperationResultCreated, nil + } + + existing := obj.DeepCopyObject() //nolint + if err := mutate(f, key, obj); err != nil { + return OperationResultNone, err + } + + if equality.Semantic.DeepEqual(existing, obj) { + return OperationResultNone, nil + } + + if err := c.Update(ctx, obj); err != nil { + return OperationResultNone, err + } + return OperationResultUpdated, nil +} + +// CreateOrPatch creates or patches the given object in the Kubernetes +// cluster. The object's desired state must be reconciled with the before +// state inside the passed in callback MutateFn. +// +// The MutateFn is called regardless of creating or updating an object. +// +// It returns the executed operation and an error. +func CreateOrPatch(ctx context.Context, c client.Client, obj client.Object, f MutateFn) (OperationResult, error) { + key := client.ObjectKeyFromObject(obj) + if err := c.Get(ctx, key, obj); err != nil { + if !apierrors.IsNotFound(err) { + return OperationResultNone, err + } + if f != nil { + if err := mutate(f, key, obj); err != nil { + return OperationResultNone, err + } + } + if err := c.Create(ctx, obj); err != nil { + return OperationResultNone, err + } + return OperationResultCreated, nil + } + + // Create patches for the object and its possible status. + objPatch := client.MergeFrom(obj.DeepCopyObject().(client.Object)) + statusPatch := client.MergeFrom(obj.DeepCopyObject().(client.Object)) + + // Create a copy of the original object as well as converting that copy to + // unstructured data. + before, err := runtime.DefaultUnstructuredConverter.ToUnstructured(obj.DeepCopyObject()) + if err != nil { + return OperationResultNone, err + } + + // Attempt to extract the status from the resource for easier comparison later + beforeStatus, hasBeforeStatus, err := unstructured.NestedFieldCopy(before, "status") + if err != nil { + return OperationResultNone, err + } + + // If the resource contains a status then remove it from the unstructured + // copy to avoid unnecessary patching later. + if hasBeforeStatus { + unstructured.RemoveNestedField(before, "status") + } + + // Mutate the original object. + if f != nil { + if err := mutate(f, key, obj); err != nil { + return OperationResultNone, err + } + } + + // Convert the resource to unstructured to compare against our before copy. + after, err := runtime.DefaultUnstructuredConverter.ToUnstructured(obj) + if err != nil { + return OperationResultNone, err + } + + // Attempt to extract the status from the resource for easier comparison later + afterStatus, hasAfterStatus, err := unstructured.NestedFieldCopy(after, "status") + if err != nil { + return OperationResultNone, err + } + + // If the resource contains a status then remove it from the unstructured + // copy to avoid unnecessary patching later. + if hasAfterStatus { + unstructured.RemoveNestedField(after, "status") + } + + result := OperationResultNone + + if !reflect.DeepEqual(before, after) { + // Only issue a Patch if the before and after resources (minus status) differ + if err := c.Patch(ctx, obj, objPatch); err != nil { + return result, err + } + result = OperationResultUpdated + } + + if (hasBeforeStatus || hasAfterStatus) && !reflect.DeepEqual(beforeStatus, afterStatus) { + // Only issue a Status Patch if the resource has a status and the beforeStatus + // and afterStatus copies differ + if result == OperationResultUpdated { + // If Status was replaced by Patch before, set it to afterStatus + objectAfterPatch, err := runtime.DefaultUnstructuredConverter.ToUnstructured(obj) + if err != nil { + return result, err + } + if err = unstructured.SetNestedField(objectAfterPatch, afterStatus, "status"); err != nil { + return result, err + } + // If Status was replaced by Patch before, restore patched structure to the obj + if err = runtime.DefaultUnstructuredConverter.FromUnstructured(objectAfterPatch, obj); err != nil { + return result, err + } + } + if err := c.Status().Patch(ctx, obj, statusPatch); err != nil { + return result, err + } + if result == OperationResultUpdated { + result = OperationResultUpdatedStatus + } else { + result = OperationResultUpdatedStatusOnly + } + } + + return result, nil +} + +// mutate wraps a MutateFn and applies validation to its result. +func mutate(f MutateFn, key client.ObjectKey, obj client.Object) error { + if err := f(); err != nil { + return err + } + if newKey := client.ObjectKeyFromObject(obj); key != newKey { + return fmt.Errorf("MutateFn cannot mutate object name and/or object namespace") + } + return nil +} + +// MutateFn is a function which mutates the existing object into its desired state. +type MutateFn func() error + +// AddFinalizer accepts an Object and adds the provided finalizer if not present. +// It returns an indication of whether it updated the object's list of finalizers. +func AddFinalizer(o client.Object, finalizer string) (finalizersUpdated bool) { + f := o.GetFinalizers() + for _, e := range f { + if e == finalizer { + return false + } + } + o.SetFinalizers(append(f, finalizer)) + return true +} + +// RemoveFinalizer accepts an Object and removes the provided finalizer if present. +// It returns an indication of whether it updated the object's list of finalizers. +func RemoveFinalizer(o client.Object, finalizer string) (finalizersUpdated bool) { + f := o.GetFinalizers() + for i := 0; i < len(f); i++ { + if f[i] == finalizer { + f = append(f[:i], f[i+1:]...) + i-- + finalizersUpdated = true + } + } + o.SetFinalizers(f) + return +} + +// ContainsFinalizer checks an Object that the provided finalizer is present. +func ContainsFinalizer(o client.Object, finalizer string) bool { + f := o.GetFinalizers() + for _, e := range f { + if e == finalizer { + return true + } + } + return false +} + +// Object allows functions to work indistinctly with any resource that +// implements both Object interfaces. +// +// Deprecated: Use client.Object instead. +type Object = client.Object diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/controller/controllerutil/doc.go b/vendor/sigs.k8s.io/controller-runtime/pkg/controller/controllerutil/doc.go new file mode 100644 index 0000000000..ab386b29cd --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/controller/controllerutil/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* +Package controllerutil contains utility functions for working with and implementing Controllers. +*/ +package controllerutil diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/controller/doc.go b/vendor/sigs.k8s.io/controller-runtime/pkg/controller/doc.go new file mode 100644 index 0000000000..228335e929 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/controller/doc.go @@ -0,0 +1,25 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* +Package controller provides types and functions for building Controllers. Controllers implement Kubernetes APIs. + +# Creation + +To create a new Controller, first create a manager.Manager and pass it to the controller.New function. +The Controller MUST be started by calling Manager.Start. +*/ +package controller diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/conversion/conversion.go b/vendor/sigs.k8s.io/controller-runtime/pkg/conversion/conversion.go new file mode 100644 index 0000000000..da32ab48e4 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/conversion/conversion.go @@ -0,0 +1,40 @@ +/* +Copyright 2019 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* +Package conversion provides interface definitions that an API Type needs to +implement for it to be supported by the generic conversion webhook handler +defined under pkg/webhook/conversion. +*/ +package conversion + +import "k8s.io/apimachinery/pkg/runtime" + +// Convertible defines capability of a type to convertible i.e. it can be converted to/from a hub type. +type Convertible interface { + runtime.Object + ConvertTo(dst Hub) error + ConvertFrom(src Hub) error +} + +// Hub marks that a given type is the hub type for conversion. This means that +// all conversions will first convert to the hub type, then convert from the hub +// type to the destination type. All types besides the hub type should implement +// Convertible. +type Hub interface { + runtime.Object + Hub() +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/event/doc.go b/vendor/sigs.k8s.io/controller-runtime/pkg/event/doc.go new file mode 100644 index 0000000000..adba3bbc16 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/event/doc.go @@ -0,0 +1,28 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* +Package event contains the definitions for the Event types produced by source.Sources and transformed into +reconcile.Requests by handler.EventHandler. + +You should rarely need to work with these directly -- instead, use Controller.Watch with +source.Sources and handler.EventHandlers. + +Events generally contain both a full runtime.Object that caused the event, as well +as a direct handle to that object's metadata. This saves a lot of typecasting in +code that works with Events. +*/ +package event diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/event/event.go b/vendor/sigs.k8s.io/controller-runtime/pkg/event/event.go new file mode 100644 index 0000000000..271b3c00fb --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/event/event.go @@ -0,0 +1,55 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package event + +import "sigs.k8s.io/controller-runtime/pkg/client" + +// CreateEvent is an event where a Kubernetes object was created. CreateEvent should be generated +// by a source.Source and transformed into a reconcile.Request by an handler.EventHandler. +type CreateEvent struct { + // Object is the object from the event + Object client.Object +} + +// UpdateEvent is an event where a Kubernetes object was updated. UpdateEvent should be generated +// by a source.Source and transformed into a reconcile.Request by an handler.EventHandler. +type UpdateEvent struct { + // ObjectOld is the object from the event + ObjectOld client.Object + + // ObjectNew is the object from the event + ObjectNew client.Object +} + +// DeleteEvent is an event where a Kubernetes object was deleted. DeleteEvent should be generated +// by a source.Source and transformed into a reconcile.Request by an handler.EventHandler. +type DeleteEvent struct { + // Object is the object from the event + Object client.Object + + // DeleteStateUnknown is true if the Delete event was missed but we identified the object + // as having been deleted. + DeleteStateUnknown bool +} + +// GenericEvent is an event where the operation type is unknown (e.g. polling or event originating outside the cluster). +// GenericEvent should be generated by a source.Source and transformed into a reconcile.Request by an +// handler.EventHandler. +type GenericEvent struct { + // Object is the object from the event + Object client.Object +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/handler/doc.go b/vendor/sigs.k8s.io/controller-runtime/pkg/handler/doc.go new file mode 100644 index 0000000000..e5fd177aff --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/handler/doc.go @@ -0,0 +1,38 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* +Package handler defines EventHandlers that enqueue reconcile.Requests in response to Create, Update, Deletion Events +observed from Watching Kubernetes APIs. Users should provide a source.Source and handler.EventHandler to +Controller.Watch in order to generate and enqueue reconcile.Request work items. + +Generally, following premade event handlers should be sufficient for most use cases: + +EventHandlers: + +EnqueueRequestForObject - Enqueues a reconcile.Request containing the Name and Namespace of the object in the Event. This will +cause the object that was the source of the Event (e.g. the created / deleted / updated object) to be +reconciled. + +EnqueueRequestForOwner - Enqueues a reconcile.Request containing the Name and Namespace of the Owner of the object in the Event. +This will cause owner of the object that was the source of the Event (e.g. the owner object that created the object) +to be reconciled. + +EnqueueRequestsFromMapFunc - Enqueues reconcile.Requests resulting from a user provided transformation function run against the +object in the Event. This will cause an arbitrary collection of objects (defined from a transformation of the +source object) to be reconciled. +*/ +package handler diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/handler/enqueue.go b/vendor/sigs.k8s.io/controller-runtime/pkg/handler/enqueue.go new file mode 100644 index 0000000000..e6d3a4eaab --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/handler/enqueue.go @@ -0,0 +1,90 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package handler + +import ( + "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/util/workqueue" + "sigs.k8s.io/controller-runtime/pkg/event" + logf "sigs.k8s.io/controller-runtime/pkg/internal/log" + "sigs.k8s.io/controller-runtime/pkg/reconcile" +) + +var enqueueLog = logf.RuntimeLog.WithName("eventhandler").WithName("EnqueueRequestForObject") + +type empty struct{} + +var _ EventHandler = &EnqueueRequestForObject{} + +// EnqueueRequestForObject enqueues a Request containing the Name and Namespace of the object that is the source of the Event. +// (e.g. the created / deleted / updated objects Name and Namespace). handler.EnqueueRequestForObject is used by almost all +// Controllers that have associated Resources (e.g. CRDs) to reconcile the associated Resource. +type EnqueueRequestForObject struct{} + +// Create implements EventHandler. +func (e *EnqueueRequestForObject) Create(evt event.CreateEvent, q workqueue.RateLimitingInterface) { + if evt.Object == nil { + enqueueLog.Error(nil, "CreateEvent received with no metadata", "event", evt) + return + } + q.Add(reconcile.Request{NamespacedName: types.NamespacedName{ + Name: evt.Object.GetName(), + Namespace: evt.Object.GetNamespace(), + }}) +} + +// Update implements EventHandler. +func (e *EnqueueRequestForObject) Update(evt event.UpdateEvent, q workqueue.RateLimitingInterface) { + switch { + case evt.ObjectNew != nil: + q.Add(reconcile.Request{NamespacedName: types.NamespacedName{ + Name: evt.ObjectNew.GetName(), + Namespace: evt.ObjectNew.GetNamespace(), + }}) + case evt.ObjectOld != nil: + q.Add(reconcile.Request{NamespacedName: types.NamespacedName{ + Name: evt.ObjectOld.GetName(), + Namespace: evt.ObjectOld.GetNamespace(), + }}) + default: + enqueueLog.Error(nil, "UpdateEvent received with no metadata", "event", evt) + } +} + +// Delete implements EventHandler. +func (e *EnqueueRequestForObject) Delete(evt event.DeleteEvent, q workqueue.RateLimitingInterface) { + if evt.Object == nil { + enqueueLog.Error(nil, "DeleteEvent received with no metadata", "event", evt) + return + } + q.Add(reconcile.Request{NamespacedName: types.NamespacedName{ + Name: evt.Object.GetName(), + Namespace: evt.Object.GetNamespace(), + }}) +} + +// Generic implements EventHandler. +func (e *EnqueueRequestForObject) Generic(evt event.GenericEvent, q workqueue.RateLimitingInterface) { + if evt.Object == nil { + enqueueLog.Error(nil, "GenericEvent received with no metadata", "event", evt) + return + } + q.Add(reconcile.Request{NamespacedName: types.NamespacedName{ + Name: evt.Object.GetName(), + Namespace: evt.Object.GetNamespace(), + }}) +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/handler/enqueue_mapped.go b/vendor/sigs.k8s.io/controller-runtime/pkg/handler/enqueue_mapped.go new file mode 100644 index 0000000000..17401b1fdb --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/handler/enqueue_mapped.go @@ -0,0 +1,97 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package handler + +import ( + "k8s.io/client-go/util/workqueue" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/event" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + "sigs.k8s.io/controller-runtime/pkg/runtime/inject" +) + +// MapFunc is the signature required for enqueueing requests from a generic function. +// This type is usually used with EnqueueRequestsFromMapFunc when registering an event handler. +type MapFunc func(client.Object) []reconcile.Request + +// EnqueueRequestsFromMapFunc enqueues Requests by running a transformation function that outputs a collection +// of reconcile.Requests on each Event. The reconcile.Requests may be for an arbitrary set of objects +// defined by some user specified transformation of the source Event. (e.g. trigger Reconciler for a set of objects +// in response to a cluster resize event caused by adding or deleting a Node) +// +// EnqueueRequestsFromMapFunc is frequently used to fan-out updates from one object to one or more other +// objects of a differing type. +// +// For UpdateEvents which contain both a new and old object, the transformation function is run on both +// objects and both sets of Requests are enqueue. +func EnqueueRequestsFromMapFunc(fn MapFunc) EventHandler { + return &enqueueRequestsFromMapFunc{ + toRequests: fn, + } +} + +var _ EventHandler = &enqueueRequestsFromMapFunc{} + +type enqueueRequestsFromMapFunc struct { + // Mapper transforms the argument into a slice of keys to be reconciled + toRequests MapFunc +} + +// Create implements EventHandler. +func (e *enqueueRequestsFromMapFunc) Create(evt event.CreateEvent, q workqueue.RateLimitingInterface) { + reqs := map[reconcile.Request]empty{} + e.mapAndEnqueue(q, evt.Object, reqs) +} + +// Update implements EventHandler. +func (e *enqueueRequestsFromMapFunc) Update(evt event.UpdateEvent, q workqueue.RateLimitingInterface) { + reqs := map[reconcile.Request]empty{} + e.mapAndEnqueue(q, evt.ObjectOld, reqs) + e.mapAndEnqueue(q, evt.ObjectNew, reqs) +} + +// Delete implements EventHandler. +func (e *enqueueRequestsFromMapFunc) Delete(evt event.DeleteEvent, q workqueue.RateLimitingInterface) { + reqs := map[reconcile.Request]empty{} + e.mapAndEnqueue(q, evt.Object, reqs) +} + +// Generic implements EventHandler. +func (e *enqueueRequestsFromMapFunc) Generic(evt event.GenericEvent, q workqueue.RateLimitingInterface) { + reqs := map[reconcile.Request]empty{} + e.mapAndEnqueue(q, evt.Object, reqs) +} + +func (e *enqueueRequestsFromMapFunc) mapAndEnqueue(q workqueue.RateLimitingInterface, object client.Object, reqs map[reconcile.Request]empty) { + for _, req := range e.toRequests(object) { + _, ok := reqs[req] + if !ok { + q.Add(req) + reqs[req] = empty{} + } + } +} + +// EnqueueRequestsFromMapFunc can inject fields into the mapper. + +// InjectFunc implements inject.Injector. +func (e *enqueueRequestsFromMapFunc) InjectFunc(f inject.Func) error { + if f == nil { + return nil + } + return f(e.toRequests) +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/handler/enqueue_owner.go b/vendor/sigs.k8s.io/controller-runtime/pkg/handler/enqueue_owner.go new file mode 100644 index 0000000000..63699893fc --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/handler/enqueue_owner.go @@ -0,0 +1,189 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package handler + +import ( + "fmt" + + "k8s.io/apimachinery/pkg/api/meta" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/util/workqueue" + "sigs.k8s.io/controller-runtime/pkg/event" + logf "sigs.k8s.io/controller-runtime/pkg/internal/log" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + "sigs.k8s.io/controller-runtime/pkg/runtime/inject" +) + +var _ EventHandler = &EnqueueRequestForOwner{} + +var log = logf.RuntimeLog.WithName("eventhandler").WithName("EnqueueRequestForOwner") + +// EnqueueRequestForOwner enqueues Requests for the Owners of an object. E.g. the object that created +// the object that was the source of the Event. +// +// If a ReplicaSet creates Pods, users may reconcile the ReplicaSet in response to Pod Events using: +// +// - a source.Kind Source with Type of Pod. +// +// - a handler.EnqueueRequestForOwner EventHandler with an OwnerType of ReplicaSet and IsController set to true. +type EnqueueRequestForOwner struct { + // OwnerType is the type of the Owner object to look for in OwnerReferences. Only Group and Kind are compared. + OwnerType runtime.Object + + // IsController if set will only look at the first OwnerReference with Controller: true. + IsController bool + + // groupKind is the cached Group and Kind from OwnerType + groupKind schema.GroupKind + + // mapper maps GroupVersionKinds to Resources + mapper meta.RESTMapper +} + +// Create implements EventHandler. +func (e *EnqueueRequestForOwner) Create(evt event.CreateEvent, q workqueue.RateLimitingInterface) { + reqs := map[reconcile.Request]empty{} + e.getOwnerReconcileRequest(evt.Object, reqs) + for req := range reqs { + q.Add(req) + } +} + +// Update implements EventHandler. +func (e *EnqueueRequestForOwner) Update(evt event.UpdateEvent, q workqueue.RateLimitingInterface) { + reqs := map[reconcile.Request]empty{} + e.getOwnerReconcileRequest(evt.ObjectOld, reqs) + e.getOwnerReconcileRequest(evt.ObjectNew, reqs) + for req := range reqs { + q.Add(req) + } +} + +// Delete implements EventHandler. +func (e *EnqueueRequestForOwner) Delete(evt event.DeleteEvent, q workqueue.RateLimitingInterface) { + reqs := map[reconcile.Request]empty{} + e.getOwnerReconcileRequest(evt.Object, reqs) + for req := range reqs { + q.Add(req) + } +} + +// Generic implements EventHandler. +func (e *EnqueueRequestForOwner) Generic(evt event.GenericEvent, q workqueue.RateLimitingInterface) { + reqs := map[reconcile.Request]empty{} + e.getOwnerReconcileRequest(evt.Object, reqs) + for req := range reqs { + q.Add(req) + } +} + +// parseOwnerTypeGroupKind parses the OwnerType into a Group and Kind and caches the result. Returns false +// if the OwnerType could not be parsed using the scheme. +func (e *EnqueueRequestForOwner) parseOwnerTypeGroupKind(scheme *runtime.Scheme) error { + // Get the kinds of the type + kinds, _, err := scheme.ObjectKinds(e.OwnerType) + if err != nil { + log.Error(err, "Could not get ObjectKinds for OwnerType", "owner type", fmt.Sprintf("%T", e.OwnerType)) + return err + } + // Expect only 1 kind. If there is more than one kind this is probably an edge case such as ListOptions. + if len(kinds) != 1 { + err := fmt.Errorf("expected exactly 1 kind for OwnerType %T, but found %s kinds", e.OwnerType, kinds) + log.Error(nil, "expected exactly 1 kind for OwnerType", "owner type", fmt.Sprintf("%T", e.OwnerType), "kinds", kinds) + return err + } + // Cache the Group and Kind for the OwnerType + e.groupKind = schema.GroupKind{Group: kinds[0].Group, Kind: kinds[0].Kind} + return nil +} + +// getOwnerReconcileRequest looks at object and builds a map of reconcile.Request to reconcile +// owners of object that match e.OwnerType. +func (e *EnqueueRequestForOwner) getOwnerReconcileRequest(object metav1.Object, result map[reconcile.Request]empty) { + // Iterate through the OwnerReferences looking for a match on Group and Kind against what was requested + // by the user + for _, ref := range e.getOwnersReferences(object) { + // Parse the Group out of the OwnerReference to compare it to what was parsed out of the requested OwnerType + refGV, err := schema.ParseGroupVersion(ref.APIVersion) + if err != nil { + log.Error(err, "Could not parse OwnerReference APIVersion", + "api version", ref.APIVersion) + return + } + + // Compare the OwnerReference Group and Kind against the OwnerType Group and Kind specified by the user. + // If the two match, create a Request for the objected referred to by + // the OwnerReference. Use the Name from the OwnerReference and the Namespace from the + // object in the event. + if ref.Kind == e.groupKind.Kind && refGV.Group == e.groupKind.Group { + // Match found - add a Request for the object referred to in the OwnerReference + request := reconcile.Request{NamespacedName: types.NamespacedName{ + Name: ref.Name, + }} + + // if owner is not namespaced then we should set the namespace to the empty + mapping, err := e.mapper.RESTMapping(e.groupKind, refGV.Version) + if err != nil { + log.Error(err, "Could not retrieve rest mapping", "kind", e.groupKind) + return + } + if mapping.Scope.Name() != meta.RESTScopeNameRoot { + request.Namespace = object.GetNamespace() + } + + result[request] = empty{} + } + } +} + +// getOwnersReferences returns the OwnerReferences for an object as specified by the EnqueueRequestForOwner +// - if IsController is true: only take the Controller OwnerReference (if found) +// - if IsController is false: take all OwnerReferences. +func (e *EnqueueRequestForOwner) getOwnersReferences(object metav1.Object) []metav1.OwnerReference { + if object == nil { + return nil + } + + // If not filtered as Controller only, then use all the OwnerReferences + if !e.IsController { + return object.GetOwnerReferences() + } + // If filtered to a Controller, only take the Controller OwnerReference + if ownerRef := metav1.GetControllerOf(object); ownerRef != nil { + return []metav1.OwnerReference{*ownerRef} + } + // No Controller OwnerReference found + return nil +} + +var _ inject.Scheme = &EnqueueRequestForOwner{} + +// InjectScheme is called by the Controller to provide a singleton scheme to the EnqueueRequestForOwner. +func (e *EnqueueRequestForOwner) InjectScheme(s *runtime.Scheme) error { + return e.parseOwnerTypeGroupKind(s) +} + +var _ inject.Mapper = &EnqueueRequestForOwner{} + +// InjectMapper is called by the Controller to provide the rest mapper used by the manager. +func (e *EnqueueRequestForOwner) InjectMapper(m meta.RESTMapper) error { + e.mapper = m + return nil +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/handler/eventhandler.go b/vendor/sigs.k8s.io/controller-runtime/pkg/handler/eventhandler.go new file mode 100644 index 0000000000..8652d22d72 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/handler/eventhandler.go @@ -0,0 +1,104 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package handler + +import ( + "k8s.io/client-go/util/workqueue" + "sigs.k8s.io/controller-runtime/pkg/event" +) + +// EventHandler enqueues reconcile.Requests in response to events (e.g. Pod Create). EventHandlers map an Event +// for one object to trigger Reconciles for either the same object or different objects - e.g. if there is an +// Event for object with type Foo (using source.KindSource) then reconcile one or more object(s) with type Bar. +// +// Identical reconcile.Requests will be batched together through the queuing mechanism before reconcile is called. +// +// * Use EnqueueRequestForObject to reconcile the object the event is for +// - do this for events for the type the Controller Reconciles. (e.g. Deployment for a Deployment Controller) +// +// * Use EnqueueRequestForOwner to reconcile the owner of the object the event is for +// - do this for events for the types the Controller creates. (e.g. ReplicaSets created by a Deployment Controller) +// +// * Use EnqueueRequestsFromMapFunc to transform an event for an object to a reconcile of an object +// of a different type - do this for events for types the Controller may be interested in, but doesn't create. +// (e.g. If Foo responds to cluster size events, map Node events to Foo objects.) +// +// Unless you are implementing your own EventHandler, you can ignore the functions on the EventHandler interface. +// Most users shouldn't need to implement their own EventHandler. +type EventHandler interface { + // Create is called in response to an create event - e.g. Pod Creation. + Create(event.CreateEvent, workqueue.RateLimitingInterface) + + // Update is called in response to an update event - e.g. Pod Updated. + Update(event.UpdateEvent, workqueue.RateLimitingInterface) + + // Delete is called in response to a delete event - e.g. Pod Deleted. + Delete(event.DeleteEvent, workqueue.RateLimitingInterface) + + // Generic is called in response to an event of an unknown type or a synthetic event triggered as a cron or + // external trigger request - e.g. reconcile Autoscaling, or a Webhook. + Generic(event.GenericEvent, workqueue.RateLimitingInterface) +} + +var _ EventHandler = Funcs{} + +// Funcs implements EventHandler. +type Funcs struct { + // Create is called in response to an add event. Defaults to no-op. + // RateLimitingInterface is used to enqueue reconcile.Requests. + CreateFunc func(event.CreateEvent, workqueue.RateLimitingInterface) + + // Update is called in response to an update event. Defaults to no-op. + // RateLimitingInterface is used to enqueue reconcile.Requests. + UpdateFunc func(event.UpdateEvent, workqueue.RateLimitingInterface) + + // Delete is called in response to a delete event. Defaults to no-op. + // RateLimitingInterface is used to enqueue reconcile.Requests. + DeleteFunc func(event.DeleteEvent, workqueue.RateLimitingInterface) + + // GenericFunc is called in response to a generic event. Defaults to no-op. + // RateLimitingInterface is used to enqueue reconcile.Requests. + GenericFunc func(event.GenericEvent, workqueue.RateLimitingInterface) +} + +// Create implements EventHandler. +func (h Funcs) Create(e event.CreateEvent, q workqueue.RateLimitingInterface) { + if h.CreateFunc != nil { + h.CreateFunc(e, q) + } +} + +// Delete implements EventHandler. +func (h Funcs) Delete(e event.DeleteEvent, q workqueue.RateLimitingInterface) { + if h.DeleteFunc != nil { + h.DeleteFunc(e, q) + } +} + +// Update implements EventHandler. +func (h Funcs) Update(e event.UpdateEvent, q workqueue.RateLimitingInterface) { + if h.UpdateFunc != nil { + h.UpdateFunc(e, q) + } +} + +// Generic implements EventHandler. +func (h Funcs) Generic(e event.GenericEvent, q workqueue.RateLimitingInterface) { + if h.GenericFunc != nil { + h.GenericFunc(e, q) + } +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/healthz/doc.go b/vendor/sigs.k8s.io/controller-runtime/pkg/healthz/doc.go new file mode 100644 index 0000000000..9827eeafed --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/healthz/doc.go @@ -0,0 +1,32 @@ +/* +Copyright 2014 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package healthz contains helpers from supporting liveness and readiness endpoints. +// (often referred to as healthz and readyz, respectively). +// +// This package draws heavily from the apiserver's healthz package +// ( https://github.com/kubernetes/apiserver/tree/master/pkg/server/healthz ) +// but has some changes to bring it in line with controller-runtime's style. +// +// The main entrypoint is the Handler -- this serves both aggregated health status +// and individual health check endpoints. +package healthz + +import ( + logf "sigs.k8s.io/controller-runtime/pkg/internal/log" +) + +var log = logf.RuntimeLog.WithName("healthz") diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/healthz/healthz.go b/vendor/sigs.k8s.io/controller-runtime/pkg/healthz/healthz.go new file mode 100644 index 0000000000..bd1cc151af --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/healthz/healthz.go @@ -0,0 +1,206 @@ +/* +Copyright 2014 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package healthz + +import ( + "fmt" + "net/http" + "path" + "sort" + "strings" + + "k8s.io/apimachinery/pkg/util/sets" +) + +// Handler is an http.Handler that aggregates the results of the given +// checkers to the root path, and supports calling individual checkers on +// subpaths of the name of the checker. +// +// Adding checks on the fly is *not* threadsafe -- use a wrapper. +type Handler struct { + Checks map[string]Checker +} + +// checkStatus holds the output of a particular check. +type checkStatus struct { + name string + healthy bool + excluded bool +} + +func (h *Handler) serveAggregated(resp http.ResponseWriter, req *http.Request) { + failed := false + excluded := getExcludedChecks(req) + + parts := make([]checkStatus, 0, len(h.Checks)) + + // calculate the results... + for checkName, check := range h.Checks { + // no-op the check if we've specified we want to exclude the check + if excluded.Has(checkName) { + excluded.Delete(checkName) + parts = append(parts, checkStatus{name: checkName, healthy: true, excluded: true}) + continue + } + if err := check(req); err != nil { + log.V(1).Info("healthz check failed", "checker", checkName, "error", err) + parts = append(parts, checkStatus{name: checkName, healthy: false}) + failed = true + } else { + parts = append(parts, checkStatus{name: checkName, healthy: true}) + } + } + + // ...default a check if none is present... + if len(h.Checks) == 0 { + parts = append(parts, checkStatus{name: "ping", healthy: true}) + } + + for _, c := range excluded.List() { + log.V(1).Info("cannot exclude health check, no matches for it", "checker", c) + } + + // ...sort to be consistent... + sort.Slice(parts, func(i, j int) bool { return parts[i].name < parts[j].name }) + + // ...and write out the result + // TODO(directxman12): this should also accept a request for JSON content (via a accept header) + _, forceVerbose := req.URL.Query()["verbose"] + writeStatusesAsText(resp, parts, excluded, failed, forceVerbose) +} + +// writeStatusAsText writes out the given check statuses in some semi-arbitrary +// bespoke text format that we copied from Kubernetes. unknownExcludes lists +// any checks that the user requested to have excluded, but weren't actually +// known checks. writeStatusAsText is always verbose on failure, and can be +// forced to be verbose on success using the given argument. +func writeStatusesAsText(resp http.ResponseWriter, parts []checkStatus, unknownExcludes sets.String, failed, forceVerbose bool) { + resp.Header().Set("Content-Type", "text/plain; charset=utf-8") + resp.Header().Set("X-Content-Type-Options", "nosniff") + + // always write status code first + if failed { + resp.WriteHeader(http.StatusInternalServerError) + } else { + resp.WriteHeader(http.StatusOK) + } + + // shortcut for easy non-verbose success + if !failed && !forceVerbose { + fmt.Fprint(resp, "ok") + return + } + + // we're always verbose on failure, so from this point on we're guaranteed to be verbose + + for _, checkOut := range parts { + switch { + case checkOut.excluded: + fmt.Fprintf(resp, "[+]%s excluded: ok\n", checkOut.name) + case checkOut.healthy: + fmt.Fprintf(resp, "[+]%s ok\n", checkOut.name) + default: + // don't include the error since this endpoint is public. If someone wants more detail + // they should have explicit permission to the detailed checks. + fmt.Fprintf(resp, "[-]%s failed: reason withheld\n", checkOut.name) + } + } + + if unknownExcludes.Len() > 0 { + fmt.Fprintf(resp, "warn: some health checks cannot be excluded: no matches for %s\n", formatQuoted(unknownExcludes.List()...)) + } + + if failed { + log.Info("healthz check failed", "statuses", parts) + fmt.Fprintf(resp, "healthz check failed\n") + } else { + fmt.Fprint(resp, "healthz check passed\n") + } +} + +func (h *Handler) ServeHTTP(resp http.ResponseWriter, req *http.Request) { + // clean up the request (duplicating the internal logic of http.ServeMux a bit) + // clean up the path a bit + reqPath := req.URL.Path + if reqPath == "" || reqPath[0] != '/' { + reqPath = "/" + reqPath + } + // path.Clean removes the trailing slash except for root for us + // (which is fine, since we're only serving one layer of sub-paths) + reqPath = path.Clean(reqPath) + + // either serve the root endpoint... + if reqPath == "/" { + h.serveAggregated(resp, req) + return + } + + // ...the default check (if nothing else is present)... + if len(h.Checks) == 0 && reqPath[1:] == "ping" { + CheckHandler{Checker: Ping}.ServeHTTP(resp, req) + return + } + + // ...or an individual checker + checkName := reqPath[1:] // ignore the leading slash + checker, known := h.Checks[checkName] + if !known { + http.NotFoundHandler().ServeHTTP(resp, req) + return + } + + CheckHandler{Checker: checker}.ServeHTTP(resp, req) +} + +// CheckHandler is an http.Handler that serves a health check endpoint at the root path, +// based on its checker. +type CheckHandler struct { + Checker +} + +func (h CheckHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) { + if err := h.Checker(req); err != nil { + http.Error(resp, fmt.Sprintf("internal server error: %v", err), http.StatusInternalServerError) + } else { + fmt.Fprint(resp, "ok") + } +} + +// Checker knows how to perform a health check. +type Checker func(req *http.Request) error + +// Ping returns true automatically when checked. +var Ping Checker = func(_ *http.Request) error { return nil } + +// getExcludedChecks extracts the health check names to be excluded from the query param. +func getExcludedChecks(r *http.Request) sets.String { + checks, found := r.URL.Query()["exclude"] + if found { + return sets.NewString(checks...) + } + return sets.NewString() +} + +// formatQuoted returns a formatted string of the health check names, +// preserving the order passed in. +func formatQuoted(names ...string) string { + quoted := make([]string, 0, len(names)) + for _, name := range names { + quoted = append(quoted, fmt.Sprintf("%q", name)) + } + return strings.Join(quoted, ",") +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/internal/controller/controller.go b/vendor/sigs.k8s.io/controller-runtime/pkg/internal/controller/controller.go new file mode 100644 index 0000000000..3732eea16e --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/internal/controller/controller.go @@ -0,0 +1,360 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package controller + +import ( + "context" + "errors" + "fmt" + "sync" + "time" + + "github.com/go-logr/logr" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + "k8s.io/apimachinery/pkg/util/uuid" + "k8s.io/client-go/util/workqueue" + "sigs.k8s.io/controller-runtime/pkg/handler" + ctrlmetrics "sigs.k8s.io/controller-runtime/pkg/internal/controller/metrics" + logf "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/predicate" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + "sigs.k8s.io/controller-runtime/pkg/runtime/inject" + "sigs.k8s.io/controller-runtime/pkg/source" +) + +var _ inject.Injector = &Controller{} + +// Controller implements controller.Controller. +type Controller struct { + // Name is used to uniquely identify a Controller in tracing, logging and monitoring. Name is required. + Name string + + // MaxConcurrentReconciles is the maximum number of concurrent Reconciles which can be run. Defaults to 1. + MaxConcurrentReconciles int + + // Reconciler is a function that can be called at any time with the Name / Namespace of an object and + // ensures that the state of the system matches the state specified in the object. + // Defaults to the DefaultReconcileFunc. + Do reconcile.Reconciler + + // MakeQueue constructs the queue for this controller once the controller is ready to start. + // This exists because the standard Kubernetes workqueues start themselves immediately, which + // leads to goroutine leaks if something calls controller.New repeatedly. + MakeQueue func() workqueue.RateLimitingInterface + + // Queue is an listeningQueue that listens for events from Informers and adds object keys to + // the Queue for processing + Queue workqueue.RateLimitingInterface + + // SetFields is used to inject dependencies into other objects such as Sources, EventHandlers and Predicates + // Deprecated: the caller should handle injected fields itself. + SetFields func(i interface{}) error + + // mu is used to synchronize Controller setup + mu sync.Mutex + + // Started is true if the Controller has been Started + Started bool + + // ctx is the context that was passed to Start() and used when starting watches. + // + // According to the docs, contexts should not be stored in a struct: https://golang.org/pkg/context, + // while we usually always strive to follow best practices, we consider this a legacy case and it should + // undergo a major refactoring and redesign to allow for context to not be stored in a struct. + ctx context.Context + + // CacheSyncTimeout refers to the time limit set on waiting for cache to sync + // Defaults to 2 minutes if not set. + CacheSyncTimeout time.Duration + + // startWatches maintains a list of sources, handlers, and predicates to start when the controller is started. + startWatches []watchDescription + + // LogConstructor is used to construct a logger to then log messages to users during reconciliation, + // or for example when a watch is started. + // Note: LogConstructor has to be able to handle nil requests as we are also using it + // outside the context of a reconciliation. + LogConstructor func(request *reconcile.Request) logr.Logger + + // RecoverPanic indicates whether the panic caused by reconcile should be recovered. + RecoverPanic bool +} + +// watchDescription contains all the information necessary to start a watch. +type watchDescription struct { + src source.Source + handler handler.EventHandler + predicates []predicate.Predicate +} + +// Reconcile implements reconcile.Reconciler. +func (c *Controller) Reconcile(ctx context.Context, req reconcile.Request) (_ reconcile.Result, err error) { + defer func() { + if r := recover(); r != nil { + if c.RecoverPanic { + for _, fn := range utilruntime.PanicHandlers { + fn(r) + } + err = fmt.Errorf("panic: %v [recovered]", r) + return + } + + log := logf.FromContext(ctx) + log.Info(fmt.Sprintf("Observed a panic in reconciler: %v", r)) + panic(r) + } + }() + return c.Do.Reconcile(ctx, req) +} + +// Watch implements controller.Controller. +func (c *Controller) Watch(src source.Source, evthdler handler.EventHandler, prct ...predicate.Predicate) error { + c.mu.Lock() + defer c.mu.Unlock() + + // Inject Cache into arguments + if err := c.SetFields(src); err != nil { + return err + } + if err := c.SetFields(evthdler); err != nil { + return err + } + for _, pr := range prct { + if err := c.SetFields(pr); err != nil { + return err + } + } + + // Controller hasn't started yet, store the watches locally and return. + // + // These watches are going to be held on the controller struct until the manager or user calls Start(...). + if !c.Started { + c.startWatches = append(c.startWatches, watchDescription{src: src, handler: evthdler, predicates: prct}) + return nil + } + + c.LogConstructor(nil).Info("Starting EventSource", "source", src) + return src.Start(c.ctx, evthdler, c.Queue, prct...) +} + +// Start implements controller.Controller. +func (c *Controller) Start(ctx context.Context) error { + // use an IIFE to get proper lock handling + // but lock outside to get proper handling of the queue shutdown + c.mu.Lock() + if c.Started { + return errors.New("controller was started more than once. This is likely to be caused by being added to a manager multiple times") + } + + c.initMetrics() + + // Set the internal context. + c.ctx = ctx + + c.Queue = c.MakeQueue() + go func() { + <-ctx.Done() + c.Queue.ShutDown() + }() + + wg := &sync.WaitGroup{} + err := func() error { + defer c.mu.Unlock() + + // TODO(pwittrock): Reconsider HandleCrash + defer utilruntime.HandleCrash() + + // NB(directxman12): launch the sources *before* trying to wait for the + // caches to sync so that they have a chance to register their intendeded + // caches. + for _, watch := range c.startWatches { + c.LogConstructor(nil).Info("Starting EventSource", "source", fmt.Sprintf("%s", watch.src)) + + if err := watch.src.Start(ctx, watch.handler, c.Queue, watch.predicates...); err != nil { + return err + } + } + + // Start the SharedIndexInformer factories to begin populating the SharedIndexInformer caches + c.LogConstructor(nil).Info("Starting Controller") + + for _, watch := range c.startWatches { + syncingSource, ok := watch.src.(source.SyncingSource) + if !ok { + continue + } + + if err := func() error { + // use a context with timeout for launching sources and syncing caches. + sourceStartCtx, cancel := context.WithTimeout(ctx, c.CacheSyncTimeout) + defer cancel() + + // WaitForSync waits for a definitive timeout, and returns if there + // is an error or a timeout + if err := syncingSource.WaitForSync(sourceStartCtx); err != nil { + err := fmt.Errorf("failed to wait for %s caches to sync: %w", c.Name, err) + c.LogConstructor(nil).Error(err, "Could not wait for Cache to sync") + return err + } + + return nil + }(); err != nil { + return err + } + } + + // All the watches have been started, we can reset the local slice. + // + // We should never hold watches more than necessary, each watch source can hold a backing cache, + // which won't be garbage collected if we hold a reference to it. + c.startWatches = nil + + // Launch workers to process resources + c.LogConstructor(nil).Info("Starting workers", "worker count", c.MaxConcurrentReconciles) + wg.Add(c.MaxConcurrentReconciles) + for i := 0; i < c.MaxConcurrentReconciles; i++ { + go func() { + defer wg.Done() + // Run a worker thread that just dequeues items, processes them, and marks them done. + // It enforces that the reconcileHandler is never invoked concurrently with the same object. + for c.processNextWorkItem(ctx) { + } + }() + } + + c.Started = true + return nil + }() + if err != nil { + return err + } + + <-ctx.Done() + c.LogConstructor(nil).Info("Shutdown signal received, waiting for all workers to finish") + wg.Wait() + c.LogConstructor(nil).Info("All workers finished") + return nil +} + +// processNextWorkItem will read a single work item off the workqueue and +// attempt to process it, by calling the reconcileHandler. +func (c *Controller) processNextWorkItem(ctx context.Context) bool { + obj, shutdown := c.Queue.Get() + if shutdown { + // Stop working + return false + } + + // We call Done here so the workqueue knows we have finished + // processing this item. We also must remember to call Forget if we + // do not want this work item being re-queued. For example, we do + // not call Forget if a transient error occurs, instead the item is + // put back on the workqueue and attempted again after a back-off + // period. + defer c.Queue.Done(obj) + + ctrlmetrics.ActiveWorkers.WithLabelValues(c.Name).Add(1) + defer ctrlmetrics.ActiveWorkers.WithLabelValues(c.Name).Add(-1) + + c.reconcileHandler(ctx, obj) + return true +} + +const ( + labelError = "error" + labelRequeueAfter = "requeue_after" + labelRequeue = "requeue" + labelSuccess = "success" +) + +func (c *Controller) initMetrics() { + ctrlmetrics.ActiveWorkers.WithLabelValues(c.Name).Set(0) + ctrlmetrics.ReconcileErrors.WithLabelValues(c.Name).Add(0) + ctrlmetrics.ReconcileTotal.WithLabelValues(c.Name, labelError).Add(0) + ctrlmetrics.ReconcileTotal.WithLabelValues(c.Name, labelRequeueAfter).Add(0) + ctrlmetrics.ReconcileTotal.WithLabelValues(c.Name, labelRequeue).Add(0) + ctrlmetrics.ReconcileTotal.WithLabelValues(c.Name, labelSuccess).Add(0) + ctrlmetrics.WorkerCount.WithLabelValues(c.Name).Set(float64(c.MaxConcurrentReconciles)) +} + +func (c *Controller) reconcileHandler(ctx context.Context, obj interface{}) { + // Update metrics after processing each item + reconcileStartTS := time.Now() + defer func() { + c.updateMetrics(time.Since(reconcileStartTS)) + }() + + // Make sure that the object is a valid request. + req, ok := obj.(reconcile.Request) + if !ok { + // As the item in the workqueue is actually invalid, we call + // Forget here else we'd go into a loop of attempting to + // process a work item that is invalid. + c.Queue.Forget(obj) + c.LogConstructor(nil).Error(nil, "Queue item was not a Request", "type", fmt.Sprintf("%T", obj), "value", obj) + // Return true, don't take a break + return + } + + log := c.LogConstructor(&req) + + log = log.WithValues("reconcileID", uuid.NewUUID()) + ctx = logf.IntoContext(ctx, log) + + // RunInformersAndControllers the syncHandler, passing it the Namespace/Name string of the + // resource to be synced. + result, err := c.Reconcile(ctx, req) + switch { + case err != nil: + c.Queue.AddRateLimited(req) + ctrlmetrics.ReconcileErrors.WithLabelValues(c.Name).Inc() + ctrlmetrics.ReconcileTotal.WithLabelValues(c.Name, labelError).Inc() + log.Error(err, "Reconciler error") + case result.RequeueAfter > 0: + // The result.RequeueAfter request will be lost, if it is returned + // along with a non-nil error. But this is intended as + // We need to drive to stable reconcile loops before queuing due + // to result.RequestAfter + c.Queue.Forget(obj) + c.Queue.AddAfter(req, result.RequeueAfter) + ctrlmetrics.ReconcileTotal.WithLabelValues(c.Name, labelRequeueAfter).Inc() + case result.Requeue: + c.Queue.AddRateLimited(req) + ctrlmetrics.ReconcileTotal.WithLabelValues(c.Name, labelRequeue).Inc() + default: + // Finally, if no error occurs we Forget this item so it does not + // get queued again until another change happens. + c.Queue.Forget(obj) + ctrlmetrics.ReconcileTotal.WithLabelValues(c.Name, labelSuccess).Inc() + } +} + +// GetLogger returns this controller's logger. +func (c *Controller) GetLogger() logr.Logger { + return c.LogConstructor(nil) +} + +// InjectFunc implement SetFields.Injector. +func (c *Controller) InjectFunc(f inject.Func) error { + c.SetFields = f + return nil +} + +// updateMetrics updates prometheus metrics within the controller. +func (c *Controller) updateMetrics(reconcileTime time.Duration) { + ctrlmetrics.ReconcileTime.WithLabelValues(c.Name).Observe(reconcileTime.Seconds()) +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/internal/controller/metrics/metrics.go b/vendor/sigs.k8s.io/controller-runtime/pkg/internal/controller/metrics/metrics.go new file mode 100644 index 0000000000..baec669277 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/internal/controller/metrics/metrics.go @@ -0,0 +1,78 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package metrics + +import ( + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/collectors" + "sigs.k8s.io/controller-runtime/pkg/metrics" +) + +var ( + // ReconcileTotal is a prometheus counter metrics which holds the total + // number of reconciliations per controller. It has two labels. controller label refers + // to the controller name and result label refers to the reconcile result i.e + // success, error, requeue, requeue_after. + ReconcileTotal = prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: "controller_runtime_reconcile_total", + Help: "Total number of reconciliations per controller", + }, []string{"controller", "result"}) + + // ReconcileErrors is a prometheus counter metrics which holds the total + // number of errors from the Reconciler. + ReconcileErrors = prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: "controller_runtime_reconcile_errors_total", + Help: "Total number of reconciliation errors per controller", + }, []string{"controller"}) + + // ReconcileTime is a prometheus metric which keeps track of the duration + // of reconciliations. + ReconcileTime = prometheus.NewHistogramVec(prometheus.HistogramOpts{ + Name: "controller_runtime_reconcile_time_seconds", + Help: "Length of time per reconciliation per controller", + Buckets: []float64{0.005, 0.01, 0.025, 0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, + 1.25, 1.5, 1.75, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5, 6, 7, 8, 9, 10, 15, 20, 25, 30, 40, 50, 60}, + }, []string{"controller"}) + + // WorkerCount is a prometheus metric which holds the number of + // concurrent reconciles per controller. + WorkerCount = prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Name: "controller_runtime_max_concurrent_reconciles", + Help: "Maximum number of concurrent reconciles per controller", + }, []string{"controller"}) + + // ActiveWorkers is a prometheus metric which holds the number + // of active workers per controller. + ActiveWorkers = prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Name: "controller_runtime_active_workers", + Help: "Number of currently used workers per controller", + }, []string{"controller"}) +) + +func init() { + metrics.Registry.MustRegister( + ReconcileTotal, + ReconcileErrors, + ReconcileTime, + WorkerCount, + ActiveWorkers, + // expose process metrics like CPU, Memory, file descriptor usage etc. + collectors.NewProcessCollector(collectors.ProcessCollectorOpts{}), + // expose Go runtime metrics like GC stats, memory stats etc. + collectors.NewGoCollector(), + ) +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/internal/httpserver/server.go b/vendor/sigs.k8s.io/controller-runtime/pkg/internal/httpserver/server.go new file mode 100644 index 0000000000..b5f91f18e0 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/internal/httpserver/server.go @@ -0,0 +1,16 @@ +package httpserver + +import ( + "net/http" + "time" +) + +// New returns a new server with sane defaults. +func New(handler http.Handler) *http.Server { + return &http.Server{ + Handler: handler, + MaxHeaderBytes: 1 << 20, + IdleTimeout: 90 * time.Second, // matches http.DefaultTransport keep-alive timeout + ReadHeaderTimeout: 32 * time.Second, + } +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/internal/log/log.go b/vendor/sigs.k8s.io/controller-runtime/pkg/internal/log/log.go new file mode 100644 index 0000000000..d91a0ca50c --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/internal/log/log.go @@ -0,0 +1,32 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package log + +import ( + "github.com/go-logr/logr" + + "sigs.k8s.io/controller-runtime/pkg/log" +) + +var ( + // RuntimeLog is a base parent logger for use inside controller-runtime. + RuntimeLog logr.Logger +) + +func init() { + RuntimeLog = log.Log.WithName("controller-runtime") +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/internal/objectutil/objectutil.go b/vendor/sigs.k8s.io/controller-runtime/pkg/internal/objectutil/objectutil.go new file mode 100644 index 0000000000..7057f3dbe4 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/internal/objectutil/objectutil.go @@ -0,0 +1,78 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package objectutil + +import ( + "errors" + "fmt" + + apimeta "k8s.io/apimachinery/pkg/api/meta" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "sigs.k8s.io/controller-runtime/pkg/client/apiutil" +) + +// FilterWithLabels returns a copy of the items in objs matching labelSel. +func FilterWithLabels(objs []runtime.Object, labelSel labels.Selector) ([]runtime.Object, error) { + outItems := make([]runtime.Object, 0, len(objs)) + for _, obj := range objs { + meta, err := apimeta.Accessor(obj) + if err != nil { + return nil, err + } + if labelSel != nil { + lbls := labels.Set(meta.GetLabels()) + if !labelSel.Matches(lbls) { + continue + } + } + outItems = append(outItems, obj.DeepCopyObject()) + } + return outItems, nil +} + +// IsAPINamespaced returns true if the object is namespace scoped. +// For unstructured objects the gvk is found from the object itself. +func IsAPINamespaced(obj runtime.Object, scheme *runtime.Scheme, restmapper apimeta.RESTMapper) (bool, error) { + gvk, err := apiutil.GVKForObject(obj, scheme) + if err != nil { + return false, err + } + + return IsAPINamespacedWithGVK(gvk, scheme, restmapper) +} + +// IsAPINamespacedWithGVK returns true if the object having the provided +// GVK is namespace scoped. +func IsAPINamespacedWithGVK(gk schema.GroupVersionKind, scheme *runtime.Scheme, restmapper apimeta.RESTMapper) (bool, error) { + restmapping, err := restmapper.RESTMapping(schema.GroupKind{Group: gk.Group, Kind: gk.Kind}) + if err != nil { + return false, fmt.Errorf("failed to get restmapping: %w", err) + } + + scope := restmapping.Scope.Name() + + if scope == "" { + return false, errors.New("scope cannot be identified, empty scope returned") + } + + if scope != apimeta.RESTScopeNameRoot { + return true, nil + } + return false, nil +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/internal/recorder/recorder.go b/vendor/sigs.k8s.io/controller-runtime/pkg/internal/recorder/recorder.go new file mode 100644 index 0000000000..9d8b2f0740 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/internal/recorder/recorder.go @@ -0,0 +1,176 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package recorder + +import ( + "context" + "fmt" + "sync" + + "github.com/go-logr/logr" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/runtime" + corev1client "k8s.io/client-go/kubernetes/typed/core/v1" + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/record" +) + +// EventBroadcasterProducer makes an event broadcaster, returning +// whether or not the broadcaster should be stopped with the Provider, +// or not (e.g. if it's shared, it shouldn't be stopped with the Provider). +type EventBroadcasterProducer func() (caster record.EventBroadcaster, stopWithProvider bool) + +// Provider is a recorder.Provider that records events to the k8s API server +// and to a logr Logger. +type Provider struct { + lock sync.RWMutex + stopped bool + + // scheme to specify when creating a recorder + scheme *runtime.Scheme + // logger is the logger to use when logging diagnostic event info + logger logr.Logger + evtClient corev1client.EventInterface + makeBroadcaster EventBroadcasterProducer + + broadcasterOnce sync.Once + broadcaster record.EventBroadcaster + stopBroadcaster bool +} + +// NB(directxman12): this manually implements Stop instead of Being a runnable because we need to +// stop it *after* everything else shuts down, otherwise we'll cause panics as the leader election +// code finishes up and tries to continue emitting events. + +// Stop attempts to stop this provider, stopping the underlying broadcaster +// if the broadcaster asked to be stopped. It kinda tries to honor the given +// context, but the underlying broadcaster has an indefinite wait that doesn't +// return until all queued events are flushed, so this may end up just returning +// before the underlying wait has finished instead of cancelling the wait. +// This is Very Frustrating™. +func (p *Provider) Stop(shutdownCtx context.Context) { + doneCh := make(chan struct{}) + + go func() { + // technically, this could start the broadcaster, but practically, it's + // almost certainly already been started (e.g. by leader election). We + // need to invoke this to ensure that we don't inadvertently race with + // an invocation of getBroadcaster. + broadcaster := p.getBroadcaster() + if p.stopBroadcaster { + p.lock.Lock() + broadcaster.Shutdown() + p.stopped = true + p.lock.Unlock() + } + close(doneCh) + }() + + select { + case <-shutdownCtx.Done(): + case <-doneCh: + } +} + +// getBroadcaster ensures that a broadcaster is started for this +// provider, and returns it. It's threadsafe. +func (p *Provider) getBroadcaster() record.EventBroadcaster { + // NB(directxman12): this can technically still leak if something calls + // "getBroadcaster" (i.e. Emits an Event) but never calls Start, but if we + // create the broadcaster in start, we could race with other things that + // are started at the same time & want to emit events. The alternative is + // silently swallowing events and more locking, but that seems suboptimal. + + p.broadcasterOnce.Do(func() { + broadcaster, stop := p.makeBroadcaster() + broadcaster.StartRecordingToSink(&corev1client.EventSinkImpl{Interface: p.evtClient}) + broadcaster.StartEventWatcher( + func(e *corev1.Event) { + p.logger.V(1).Info(e.Message, "type", e.Type, "object", e.InvolvedObject, "reason", e.Reason) + }) + p.broadcaster = broadcaster + p.stopBroadcaster = stop + }) + + return p.broadcaster +} + +// NewProvider create a new Provider instance. +func NewProvider(config *rest.Config, scheme *runtime.Scheme, logger logr.Logger, makeBroadcaster EventBroadcasterProducer) (*Provider, error) { + corev1Client, err := corev1client.NewForConfig(config) + if err != nil { + return nil, fmt.Errorf("failed to init client: %w", err) + } + + p := &Provider{scheme: scheme, logger: logger, makeBroadcaster: makeBroadcaster, evtClient: corev1Client.Events("")} + return p, nil +} + +// GetEventRecorderFor returns an event recorder that broadcasts to this provider's +// broadcaster. All events will be associated with a component of the given name. +func (p *Provider) GetEventRecorderFor(name string) record.EventRecorder { + return &lazyRecorder{ + prov: p, + name: name, + } +} + +// lazyRecorder is a recorder that doesn't actually instantiate any underlying +// recorder until the first event is emitted. +type lazyRecorder struct { + prov *Provider + name string + + recOnce sync.Once + rec record.EventRecorder +} + +// ensureRecording ensures that a concrete recorder is populated for this recorder. +func (l *lazyRecorder) ensureRecording() { + l.recOnce.Do(func() { + broadcaster := l.prov.getBroadcaster() + l.rec = broadcaster.NewRecorder(l.prov.scheme, corev1.EventSource{Component: l.name}) + }) +} + +func (l *lazyRecorder) Event(object runtime.Object, eventtype, reason, message string) { + l.ensureRecording() + + l.prov.lock.RLock() + if !l.prov.stopped { + l.rec.Event(object, eventtype, reason, message) + } + l.prov.lock.RUnlock() +} +func (l *lazyRecorder) Eventf(object runtime.Object, eventtype, reason, messageFmt string, args ...interface{}) { + l.ensureRecording() + + l.prov.lock.RLock() + if !l.prov.stopped { + l.rec.Eventf(object, eventtype, reason, messageFmt, args...) + } + l.prov.lock.RUnlock() +} +func (l *lazyRecorder) AnnotatedEventf(object runtime.Object, annotations map[string]string, eventtype, reason, messageFmt string, args ...interface{}) { + l.ensureRecording() + + l.prov.lock.RLock() + if !l.prov.stopped { + l.rec.AnnotatedEventf(object, annotations, eventtype, reason, messageFmt, args...) + } + l.prov.lock.RUnlock() +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/leaderelection/doc.go b/vendor/sigs.k8s.io/controller-runtime/pkg/leaderelection/doc.go new file mode 100644 index 0000000000..37a9aefab5 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/leaderelection/doc.go @@ -0,0 +1,24 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* +Package leaderelection contains a constructor for a leader election resource lock. +This is used to ensure that multiple copies of a controller manager can be run with +only one active set of controllers, for active-passive HA. + +It uses built-in Kubernetes leader election APIs. +*/ +package leaderelection diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/leaderelection/leader_election.go b/vendor/sigs.k8s.io/controller-runtime/pkg/leaderelection/leader_election.go new file mode 100644 index 0000000000..ee4fcf4cbe --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/leaderelection/leader_election.go @@ -0,0 +1,127 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package leaderelection + +import ( + "errors" + "fmt" + "os" + + "k8s.io/apimachinery/pkg/util/uuid" + coordinationv1client "k8s.io/client-go/kubernetes/typed/coordination/v1" + corev1client "k8s.io/client-go/kubernetes/typed/core/v1" + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/leaderelection/resourcelock" + + "sigs.k8s.io/controller-runtime/pkg/recorder" +) + +const inClusterNamespacePath = "/var/run/secrets/kubernetes.io/serviceaccount/namespace" + +// Options provides the required configuration to create a new resource lock. +type Options struct { + // LeaderElection determines whether or not to use leader election when + // starting the manager. + LeaderElection bool + + // LeaderElectionResourceLock determines which resource lock to use for leader election, + // defaults to "leases". + LeaderElectionResourceLock string + + // LeaderElectionNamespace determines the namespace in which the leader + // election resource will be created. + LeaderElectionNamespace string + + // LeaderElectionID determines the name of the resource that leader election + // will use for holding the leader lock. + LeaderElectionID string +} + +// NewResourceLock creates a new resource lock for use in a leader election loop. +func NewResourceLock(config *rest.Config, recorderProvider recorder.Provider, options Options) (resourcelock.Interface, error) { + if !options.LeaderElection { + return nil, nil + } + + // Default resource lock to "leases". The previous default (from v0.7.0 to v0.11.x) was configmapsleases, which was + // used to migrate from configmaps to leases. Since the default was "configmapsleases" for over a year, spanning + // five minor releases, any actively maintained operators are very likely to have a released version that uses + // "configmapsleases". Therefore defaulting to "leases" should be safe. + if options.LeaderElectionResourceLock == "" { + options.LeaderElectionResourceLock = resourcelock.LeasesResourceLock + } + + // LeaderElectionID must be provided to prevent clashes + if options.LeaderElectionID == "" { + return nil, errors.New("LeaderElectionID must be configured") + } + + // Default the namespace (if running in cluster) + if options.LeaderElectionNamespace == "" { + var err error + options.LeaderElectionNamespace, err = getInClusterNamespace() + if err != nil { + return nil, fmt.Errorf("unable to find leader election namespace: %w", err) + } + } + + // Leader id, needs to be unique + id, err := os.Hostname() + if err != nil { + return nil, err + } + id = id + "_" + string(uuid.NewUUID()) + + // Construct clients for leader election + rest.AddUserAgent(config, "leader-election") + corev1Client, err := corev1client.NewForConfig(config) + if err != nil { + return nil, err + } + + coordinationClient, err := coordinationv1client.NewForConfig(config) + if err != nil { + return nil, err + } + + return resourcelock.New(options.LeaderElectionResourceLock, + options.LeaderElectionNamespace, + options.LeaderElectionID, + corev1Client, + coordinationClient, + resourcelock.ResourceLockConfig{ + Identity: id, + EventRecorder: recorderProvider.GetEventRecorderFor(id), + }) +} + +func getInClusterNamespace() (string, error) { + // Check whether the namespace file exists. + // If not, we are not running in cluster so can't guess the namespace. + if _, err := os.Stat(inClusterNamespacePath); os.IsNotExist(err) { + return "", fmt.Errorf("not running in-cluster, please specify LeaderElectionNamespace") + } else if err != nil { + return "", fmt.Errorf("error checking namespace file: %w", err) + } + + // Load the namespace file and return its content + namespace, err := os.ReadFile(inClusterNamespacePath) + if err != nil { + return "", fmt.Errorf("error reading namespace file: %w", err) + } + return string(namespace), nil +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/log/deleg.go b/vendor/sigs.k8s.io/controller-runtime/pkg/log/deleg.go new file mode 100644 index 0000000000..c82447d919 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/log/deleg.go @@ -0,0 +1,199 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package log + +import ( + "sync" + + "github.com/go-logr/logr" +) + +// loggerPromise knows how to populate a concrete logr.Logger +// with options, given an actual base logger later on down the line. +type loggerPromise struct { + logger *DelegatingLogSink + childPromises []*loggerPromise + promisesLock sync.Mutex + + name *string + tags []interface{} +} + +func (p *loggerPromise) WithName(l *DelegatingLogSink, name string) *loggerPromise { + res := &loggerPromise{ + logger: l, + name: &name, + promisesLock: sync.Mutex{}, + } + + p.promisesLock.Lock() + defer p.promisesLock.Unlock() + p.childPromises = append(p.childPromises, res) + return res +} + +// WithValues provides a new Logger with the tags appended. +func (p *loggerPromise) WithValues(l *DelegatingLogSink, tags ...interface{}) *loggerPromise { + res := &loggerPromise{ + logger: l, + tags: tags, + promisesLock: sync.Mutex{}, + } + + p.promisesLock.Lock() + defer p.promisesLock.Unlock() + p.childPromises = append(p.childPromises, res) + return res +} + +// Fulfill instantiates the Logger with the provided logger. +func (p *loggerPromise) Fulfill(parentLogSink logr.LogSink) { + sink := parentLogSink + if p.name != nil { + sink = sink.WithName(*p.name) + } + + if p.tags != nil { + sink = sink.WithValues(p.tags...) + } + + p.logger.lock.Lock() + p.logger.logger = sink + if withCallDepth, ok := sink.(logr.CallDepthLogSink); ok { + p.logger.logger = withCallDepth.WithCallDepth(1) + } + p.logger.promise = nil + p.logger.lock.Unlock() + + for _, childPromise := range p.childPromises { + childPromise.Fulfill(sink) + } +} + +// DelegatingLogSink is a logsink that delegates to another logr.LogSink. +// If the underlying promise is not nil, it registers calls to sub-loggers with +// the logging factory to be populated later, and returns a new delegating +// logger. It expects to have *some* logr.Logger set at all times (generally +// a no-op logger before the promises are fulfilled). +type DelegatingLogSink struct { + lock sync.RWMutex + logger logr.LogSink + promise *loggerPromise + info logr.RuntimeInfo +} + +// Init implements logr.LogSink. +func (l *DelegatingLogSink) Init(info logr.RuntimeInfo) { + l.lock.Lock() + defer l.lock.Unlock() + l.info = info +} + +// Enabled tests whether this Logger is enabled. For example, commandline +// flags might be used to set the logging verbosity and disable some info +// logs. +func (l *DelegatingLogSink) Enabled(level int) bool { + l.lock.RLock() + defer l.lock.RUnlock() + return l.logger.Enabled(level) +} + +// Info logs a non-error message with the given key/value pairs as context. +// +// The msg argument should be used to add some constant description to +// the log line. The key/value pairs can then be used to add additional +// variable information. The key/value pairs should alternate string +// keys and arbitrary values. +func (l *DelegatingLogSink) Info(level int, msg string, keysAndValues ...interface{}) { + l.lock.RLock() + defer l.lock.RUnlock() + l.logger.Info(level, msg, keysAndValues...) +} + +// Error logs an error, with the given message and key/value pairs as context. +// It functions similarly to calling Info with the "error" named value, but may +// have unique behavior, and should be preferred for logging errors (see the +// package documentations for more information). +// +// The msg field should be used to add context to any underlying error, +// while the err field should be used to attach the actual error that +// triggered this log line, if present. +func (l *DelegatingLogSink) Error(err error, msg string, keysAndValues ...interface{}) { + l.lock.RLock() + defer l.lock.RUnlock() + l.logger.Error(err, msg, keysAndValues...) +} + +// WithName provides a new Logger with the name appended. +func (l *DelegatingLogSink) WithName(name string) logr.LogSink { + l.lock.RLock() + defer l.lock.RUnlock() + + if l.promise == nil { + sink := l.logger.WithName(name) + if withCallDepth, ok := sink.(logr.CallDepthLogSink); ok { + sink = withCallDepth.WithCallDepth(-1) + } + return sink + } + + res := &DelegatingLogSink{logger: l.logger} + promise := l.promise.WithName(res, name) + res.promise = promise + + return res +} + +// WithValues provides a new Logger with the tags appended. +func (l *DelegatingLogSink) WithValues(tags ...interface{}) logr.LogSink { + l.lock.RLock() + defer l.lock.RUnlock() + + if l.promise == nil { + sink := l.logger.WithValues(tags...) + if withCallDepth, ok := sink.(logr.CallDepthLogSink); ok { + sink = withCallDepth.WithCallDepth(-1) + } + return sink + } + + res := &DelegatingLogSink{logger: l.logger} + promise := l.promise.WithValues(res, tags...) + res.promise = promise + + return res +} + +// Fulfill switches the logger over to use the actual logger +// provided, instead of the temporary initial one, if this method +// has not been previously called. +func (l *DelegatingLogSink) Fulfill(actual logr.LogSink) { + if l.promise != nil { + l.promise.Fulfill(actual) + } +} + +// NewDelegatingLogSink constructs a new DelegatingLogSink which uses +// the given logger before its promise is fulfilled. +func NewDelegatingLogSink(initial logr.LogSink) *DelegatingLogSink { + l := &DelegatingLogSink{ + logger: initial, + promise: &loggerPromise{promisesLock: sync.Mutex{}}, + } + l.promise.logger = l + return l +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/log/log.go b/vendor/sigs.k8s.io/controller-runtime/pkg/log/log.go new file mode 100644 index 0000000000..082dce3adb --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/log/log.go @@ -0,0 +1,102 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package log contains utilities for fetching a new logger +// when one is not already available. +// +// # The Log Handle +// +// This package contains a root logr.Logger Log. It may be used to +// get a handle to whatever the root logging implementation is. By +// default, no implementation exists, and the handle returns "promises" +// to loggers. When the implementation is set using SetLogger, these +// "promises" will be converted over to real loggers. +// +// # Logr +// +// All logging in controller-runtime is structured, using a set of interfaces +// defined by a package called logr +// (https://pkg.go.dev/github.com/go-logr/logr). The sub-package zap provides +// helpers for setting up logr backed by Zap (go.uber.org/zap). +package log + +import ( + "context" + "sync" + "time" + + "github.com/go-logr/logr" +) + +// SetLogger sets a concrete logging implementation for all deferred Loggers. +func SetLogger(l logr.Logger) { + loggerWasSetLock.Lock() + defer loggerWasSetLock.Unlock() + + loggerWasSet = true + dlog.Fulfill(l.GetSink()) +} + +// It is safe to assume that if this wasn't set within the first 30 seconds of a binaries +// lifetime, it will never get set. The DelegatingLogSink causes a high number of memory +// allocations when not given an actual Logger, so we set a NullLogSink to avoid that. +// +// We need to keep the DelegatingLogSink because we have various inits() that get a logger from +// here. They will always get executed before any code that imports controller-runtime +// has a chance to run and hence to set an actual logger. +func init() { + // Init is blocking, so start a new goroutine + go func() { + time.Sleep(30 * time.Second) + loggerWasSetLock.Lock() + defer loggerWasSetLock.Unlock() + if !loggerWasSet { + dlog.Fulfill(NullLogSink{}) + } + }() +} + +var ( + loggerWasSetLock sync.Mutex + loggerWasSet bool +) + +// Log is the base logger used by kubebuilder. It delegates +// to another logr.Logger. You *must* call SetLogger to +// get any actual logging. If SetLogger is not called within +// the first 30 seconds of a binaries lifetime, it will get +// set to a NullLogSink. +var ( + dlog = NewDelegatingLogSink(NullLogSink{}) + Log = logr.New(dlog) +) + +// FromContext returns a logger with predefined values from a context.Context. +func FromContext(ctx context.Context, keysAndValues ...interface{}) logr.Logger { + log := Log + if ctx != nil { + if logger, err := logr.FromContext(ctx); err == nil { + log = logger + } + } + return log.WithValues(keysAndValues...) +} + +// IntoContext takes a context and sets the logger as one of its values. +// Use FromContext function to retrieve the logger. +func IntoContext(ctx context.Context, log logr.Logger) context.Context { + return logr.NewContext(ctx, log) +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/log/null.go b/vendor/sigs.k8s.io/controller-runtime/pkg/log/null.go new file mode 100644 index 0000000000..f3e81074fe --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/log/null.go @@ -0,0 +1,59 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package log + +import ( + "github.com/go-logr/logr" +) + +// NB: this is the same as the null logger logr/testing, +// but avoids accidentally adding the testing flags to +// all binaries. + +// NullLogSink is a logr.Logger that does nothing. +type NullLogSink struct{} + +var _ logr.LogSink = NullLogSink{} + +// Init implements logr.LogSink. +func (log NullLogSink) Init(logr.RuntimeInfo) { +} + +// Info implements logr.InfoLogger. +func (NullLogSink) Info(_ int, _ string, _ ...interface{}) { + // Do nothing. +} + +// Enabled implements logr.InfoLogger. +func (NullLogSink) Enabled(level int) bool { + return false +} + +// Error implements logr.Logger. +func (NullLogSink) Error(_ error, _ string, _ ...interface{}) { + // Do nothing. +} + +// WithName implements logr.Logger. +func (log NullLogSink) WithName(_ string) logr.LogSink { + return log +} + +// WithValues implements logr.Logger. +func (log NullLogSink) WithValues(_ ...interface{}) logr.LogSink { + return log +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/log/warning_handler.go b/vendor/sigs.k8s.io/controller-runtime/pkg/log/warning_handler.go new file mode 100644 index 0000000000..e9522632d3 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/log/warning_handler.go @@ -0,0 +1,76 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package log + +import ( + "sync" + + "github.com/go-logr/logr" +) + +// KubeAPIWarningLoggerOptions controls the behavior +// of a rest.WarningHandler constructed using NewKubeAPIWarningLogger(). +type KubeAPIWarningLoggerOptions struct { + // Deduplicate indicates a given warning message should only be written once. + // Setting this to true in a long-running process handling many warnings can + // result in increased memory use. + Deduplicate bool +} + +// KubeAPIWarningLogger is a wrapper around +// a provided logr.Logger that implements the +// rest.WarningHandler interface. +type KubeAPIWarningLogger struct { + // logger is used to log responses with the warning header + logger logr.Logger + // opts contain options controlling warning output + opts KubeAPIWarningLoggerOptions + // writtenLock gurads written + writtenLock sync.Mutex + // used to keep track of already logged messages + // and help in de-duplication. + written map[string]struct{} +} + +// HandleWarningHeader handles logging for responses from API server that are +// warnings with code being 299 and uses a logr.Logger for its logging purposes. +func (l *KubeAPIWarningLogger) HandleWarningHeader(code int, agent string, message string) { + if code != 299 || len(message) == 0 { + return + } + + if l.opts.Deduplicate { + l.writtenLock.Lock() + defer l.writtenLock.Unlock() + + if _, alreadyLogged := l.written[message]; alreadyLogged { + return + } + l.written[message] = struct{}{} + } + l.logger.Info(message) +} + +// NewKubeAPIWarningLogger returns an implementation of rest.WarningHandler that logs warnings +// with code = 299 to the provided logr.Logger. +func NewKubeAPIWarningLogger(l logr.Logger, opts KubeAPIWarningLoggerOptions) *KubeAPIWarningLogger { + h := &KubeAPIWarningLogger{logger: l, opts: opts} + if opts.Deduplicate { + h.written = map[string]struct{}{} + } + return h +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/manager/doc.go b/vendor/sigs.k8s.io/controller-runtime/pkg/manager/doc.go new file mode 100644 index 0000000000..f2976c7f75 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/manager/doc.go @@ -0,0 +1,21 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* +Package manager is required to create Controllers and provides shared dependencies such as clients, caches, schemes, +etc. Controllers must be started by calling Manager.Start. +*/ +package manager diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/manager/internal.go b/vendor/sigs.k8s.io/controller-runtime/pkg/manager/internal.go new file mode 100644 index 0000000000..5b22c628f9 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/manager/internal.go @@ -0,0 +1,652 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package manager + +import ( + "context" + "errors" + "fmt" + "net" + "net/http" + "sync" + "sync/atomic" + "time" + + "github.com/go-logr/logr" + "github.com/prometheus/client_golang/prometheus/promhttp" + "k8s.io/apimachinery/pkg/api/meta" + "k8s.io/apimachinery/pkg/runtime" + kerrors "k8s.io/apimachinery/pkg/util/errors" + "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/leaderelection" + "k8s.io/client-go/tools/leaderelection/resourcelock" + "k8s.io/client-go/tools/record" + + "sigs.k8s.io/controller-runtime/pkg/cache" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/cluster" + "sigs.k8s.io/controller-runtime/pkg/config/v1alpha1" + "sigs.k8s.io/controller-runtime/pkg/healthz" + "sigs.k8s.io/controller-runtime/pkg/internal/httpserver" + intrec "sigs.k8s.io/controller-runtime/pkg/internal/recorder" + "sigs.k8s.io/controller-runtime/pkg/metrics" + "sigs.k8s.io/controller-runtime/pkg/runtime/inject" + "sigs.k8s.io/controller-runtime/pkg/webhook" +) + +const ( + // Values taken from: https://github.com/kubernetes/component-base/blob/master/config/v1alpha1/defaults.go + defaultLeaseDuration = 15 * time.Second + defaultRenewDeadline = 10 * time.Second + defaultRetryPeriod = 2 * time.Second + defaultGracefulShutdownPeriod = 30 * time.Second + + defaultReadinessEndpoint = "/readyz" + defaultLivenessEndpoint = "/healthz" + defaultMetricsEndpoint = "/metrics" +) + +var _ Runnable = &controllerManager{} + +type controllerManager struct { + sync.Mutex + started bool + + stopProcedureEngaged *int64 + errChan chan error + runnables *runnables + + // cluster holds a variety of methods to interact with a cluster. Required. + cluster cluster.Cluster + + // recorderProvider is used to generate event recorders that will be injected into Controllers + // (and EventHandlers, Sources and Predicates). + recorderProvider *intrec.Provider + + // resourceLock forms the basis for leader election + resourceLock resourcelock.Interface + + // leaderElectionReleaseOnCancel defines if the manager should step back from the leader lease + // on shutdown + leaderElectionReleaseOnCancel bool + + // metricsListener is used to serve prometheus metrics + metricsListener net.Listener + + // metricsExtraHandlers contains extra handlers to register on http server that serves metrics. + metricsExtraHandlers map[string]http.Handler + + // healthProbeListener is used to serve liveness probe + healthProbeListener net.Listener + + // Readiness probe endpoint name + readinessEndpointName string + + // Liveness probe endpoint name + livenessEndpointName string + + // Readyz probe handler + readyzHandler *healthz.Handler + + // Healthz probe handler + healthzHandler *healthz.Handler + + // controllerOptions are the global controller options. + controllerOptions v1alpha1.ControllerConfigurationSpec + + // Logger is the logger that should be used by this manager. + // If none is set, it defaults to log.Log global logger. + logger logr.Logger + + // leaderElectionStopped is an internal channel used to signal the stopping procedure that the + // LeaderElection.Run(...) function has returned and the shutdown can proceed. + leaderElectionStopped chan struct{} + + // leaderElectionCancel is used to cancel the leader election. It is distinct from internalStopper, + // because for safety reasons we need to os.Exit() when we lose the leader election, meaning that + // it must be deferred until after gracefulShutdown is done. + leaderElectionCancel context.CancelFunc + + // elected is closed when this manager becomes the leader of a group of + // managers, either because it won a leader election or because no leader + // election was configured. + elected chan struct{} + + // port is the port that the webhook server serves at. + port int + // host is the hostname that the webhook server binds to. + host string + // CertDir is the directory that contains the server key and certificate. + // if not set, webhook server would look up the server key and certificate in + // {TempDir}/k8s-webhook-server/serving-certs + certDir string + + webhookServer *webhook.Server + // webhookServerOnce will be called in GetWebhookServer() to optionally initialize + // webhookServer if unset, and Add() it to controllerManager. + webhookServerOnce sync.Once + + // leaseDuration is the duration that non-leader candidates will + // wait to force acquire leadership. + leaseDuration time.Duration + // renewDeadline is the duration that the acting controlplane will retry + // refreshing leadership before giving up. + renewDeadline time.Duration + // retryPeriod is the duration the LeaderElector clients should wait + // between tries of actions. + retryPeriod time.Duration + + // gracefulShutdownTimeout is the duration given to runnable to stop + // before the manager actually returns on stop. + gracefulShutdownTimeout time.Duration + + // onStoppedLeading is callled when the leader election lease is lost. + // It can be overridden for tests. + onStoppedLeading func() + + // shutdownCtx is the context that can be used during shutdown. It will be cancelled + // after the gracefulShutdownTimeout ended. It must not be accessed before internalStop + // is closed because it will be nil. + shutdownCtx context.Context + + internalCtx context.Context + internalCancel context.CancelFunc + + // internalProceduresStop channel is used internally to the manager when coordinating + // the proper shutdown of servers. This channel is also used for dependency injection. + internalProceduresStop chan struct{} +} + +type hasCache interface { + Runnable + GetCache() cache.Cache +} + +// Add sets dependencies on i, and adds it to the list of Runnables to start. +func (cm *controllerManager) Add(r Runnable) error { + cm.Lock() + defer cm.Unlock() + return cm.add(r) +} + +func (cm *controllerManager) add(r Runnable) error { + // Set dependencies on the object + if err := cm.SetFields(r); err != nil { + return err + } + return cm.runnables.Add(r) +} + +// Deprecated: use the equivalent Options field to set a field. This method will be removed in v0.10. +func (cm *controllerManager) SetFields(i interface{}) error { + if err := cm.cluster.SetFields(i); err != nil { + return err + } + if _, err := inject.InjectorInto(cm.SetFields, i); err != nil { + return err + } + if _, err := inject.StopChannelInto(cm.internalProceduresStop, i); err != nil { + return err + } + if _, err := inject.LoggerInto(cm.logger, i); err != nil { + return err + } + + return nil +} + +// AddMetricsExtraHandler adds extra handler served on path to the http server that serves metrics. +func (cm *controllerManager) AddMetricsExtraHandler(path string, handler http.Handler) error { + cm.Lock() + defer cm.Unlock() + + if cm.started { + return fmt.Errorf("unable to add new metrics handler because metrics endpoint has already been created") + } + + if path == defaultMetricsEndpoint { + return fmt.Errorf("overriding builtin %s endpoint is not allowed", defaultMetricsEndpoint) + } + + if _, found := cm.metricsExtraHandlers[path]; found { + return fmt.Errorf("can't register extra handler by duplicate path %q on metrics http server", path) + } + + cm.metricsExtraHandlers[path] = handler + cm.logger.V(2).Info("Registering metrics http server extra handler", "path", path) + return nil +} + +// AddHealthzCheck allows you to add Healthz checker. +func (cm *controllerManager) AddHealthzCheck(name string, check healthz.Checker) error { + cm.Lock() + defer cm.Unlock() + + if cm.started { + return fmt.Errorf("unable to add new checker because healthz endpoint has already been created") + } + + if cm.healthzHandler == nil { + cm.healthzHandler = &healthz.Handler{Checks: map[string]healthz.Checker{}} + } + + cm.healthzHandler.Checks[name] = check + return nil +} + +// AddReadyzCheck allows you to add Readyz checker. +func (cm *controllerManager) AddReadyzCheck(name string, check healthz.Checker) error { + cm.Lock() + defer cm.Unlock() + + if cm.started { + return fmt.Errorf("unable to add new checker because healthz endpoint has already been created") + } + + if cm.readyzHandler == nil { + cm.readyzHandler = &healthz.Handler{Checks: map[string]healthz.Checker{}} + } + + cm.readyzHandler.Checks[name] = check + return nil +} + +func (cm *controllerManager) GetConfig() *rest.Config { + return cm.cluster.GetConfig() +} + +func (cm *controllerManager) GetClient() client.Client { + return cm.cluster.GetClient() +} + +func (cm *controllerManager) GetScheme() *runtime.Scheme { + return cm.cluster.GetScheme() +} + +func (cm *controllerManager) GetFieldIndexer() client.FieldIndexer { + return cm.cluster.GetFieldIndexer() +} + +func (cm *controllerManager) GetCache() cache.Cache { + return cm.cluster.GetCache() +} + +func (cm *controllerManager) GetEventRecorderFor(name string) record.EventRecorder { + return cm.cluster.GetEventRecorderFor(name) +} + +func (cm *controllerManager) GetRESTMapper() meta.RESTMapper { + return cm.cluster.GetRESTMapper() +} + +func (cm *controllerManager) GetAPIReader() client.Reader { + return cm.cluster.GetAPIReader() +} + +func (cm *controllerManager) GetWebhookServer() *webhook.Server { + cm.webhookServerOnce.Do(func() { + if cm.webhookServer == nil { + cm.webhookServer = &webhook.Server{ + Port: cm.port, + Host: cm.host, + CertDir: cm.certDir, + } + } + if err := cm.Add(cm.webhookServer); err != nil { + panic(fmt.Sprintf("unable to add webhook server to the controller manager: %s", err)) + } + }) + return cm.webhookServer +} + +func (cm *controllerManager) GetLogger() logr.Logger { + return cm.logger +} + +func (cm *controllerManager) GetControllerOptions() v1alpha1.ControllerConfigurationSpec { + return cm.controllerOptions +} + +func (cm *controllerManager) serveMetrics() { + handler := promhttp.HandlerFor(metrics.Registry, promhttp.HandlerOpts{ + ErrorHandling: promhttp.HTTPErrorOnError, + }) + // TODO(JoelSpeed): Use existing Kubernetes machinery for serving metrics + mux := http.NewServeMux() + mux.Handle(defaultMetricsEndpoint, handler) + for path, extraHandler := range cm.metricsExtraHandlers { + mux.Handle(path, extraHandler) + } + + server := httpserver.New(mux) + go cm.httpServe("metrics", cm.logger.WithValues("path", defaultMetricsEndpoint), server, cm.metricsListener) +} + +func (cm *controllerManager) serveHealthProbes() { + mux := http.NewServeMux() + server := httpserver.New(mux) + + if cm.readyzHandler != nil { + mux.Handle(cm.readinessEndpointName, http.StripPrefix(cm.readinessEndpointName, cm.readyzHandler)) + // Append '/' suffix to handle subpaths + mux.Handle(cm.readinessEndpointName+"/", http.StripPrefix(cm.readinessEndpointName, cm.readyzHandler)) + } + if cm.healthzHandler != nil { + mux.Handle(cm.livenessEndpointName, http.StripPrefix(cm.livenessEndpointName, cm.healthzHandler)) + // Append '/' suffix to handle subpaths + mux.Handle(cm.livenessEndpointName+"/", http.StripPrefix(cm.livenessEndpointName, cm.healthzHandler)) + } + + go cm.httpServe("health probe", cm.logger, server, cm.healthProbeListener) +} + +func (cm *controllerManager) httpServe(kind string, log logr.Logger, server *http.Server, ln net.Listener) { + log = log.WithValues("kind", kind, "addr", ln.Addr()) + + go func() { + log.Info("Starting server") + if err := server.Serve(ln); err != nil { + if errors.Is(err, http.ErrServerClosed) { + return + } + if atomic.LoadInt64(cm.stopProcedureEngaged) > 0 { + // There might be cases where connections are still open and we try to shutdown + // but not having enough time to close the connection causes an error in Serve + // + // In that case we want to avoid returning an error to the main error channel. + log.Error(err, "error on Serve after stop has been engaged") + return + } + cm.errChan <- err + } + }() + + // Shutdown the server when stop is closed. + <-cm.internalProceduresStop + if err := server.Shutdown(cm.shutdownCtx); err != nil { + if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) { + // Avoid logging context related errors. + return + } + if atomic.LoadInt64(cm.stopProcedureEngaged) > 0 { + cm.logger.Error(err, "error on Shutdown after stop has been engaged") + return + } + cm.errChan <- err + } +} + +// Start starts the manager and waits indefinitely. +// There is only two ways to have start return: +// An error has occurred during in one of the internal operations, +// such as leader election, cache start, webhooks, and so on. +// Or, the context is cancelled. +func (cm *controllerManager) Start(ctx context.Context) (err error) { + cm.Lock() + if cm.started { + cm.Unlock() + return errors.New("manager already started") + } + var ready bool + defer func() { + // Only unlock the manager if we haven't reached + // the internal readiness condition. + if !ready { + cm.Unlock() + } + }() + + // Initialize the internal context. + cm.internalCtx, cm.internalCancel = context.WithCancel(ctx) + + // This chan indicates that stop is complete, in other words all runnables have returned or timeout on stop request + stopComplete := make(chan struct{}) + defer close(stopComplete) + // This must be deferred after closing stopComplete, otherwise we deadlock. + defer func() { + // https://hips.hearstapps.com/hmg-prod.s3.amazonaws.com/images/gettyimages-459889618-1533579787.jpg + stopErr := cm.engageStopProcedure(stopComplete) + if stopErr != nil { + if err != nil { + // Utilerrors.Aggregate allows to use errors.Is for all contained errors + // whereas fmt.Errorf allows wrapping at most one error which means the + // other one can not be found anymore. + err = kerrors.NewAggregate([]error{err, stopErr}) + } else { + err = stopErr + } + } + }() + + // Add the cluster runnable. + if err := cm.add(cm.cluster); err != nil { + return fmt.Errorf("failed to add cluster to runnables: %w", err) + } + + // Metrics should be served whether the controller is leader or not. + // (If we don't serve metrics for non-leaders, prometheus will still scrape + // the pod but will get a connection refused). + if cm.metricsListener != nil { + cm.serveMetrics() + } + + // Serve health probes. + if cm.healthProbeListener != nil { + cm.serveHealthProbes() + } + + // First start any webhook servers, which includes conversion, validation, and defaulting + // webhooks that are registered. + // + // WARNING: Webhooks MUST start before any cache is populated, otherwise there is a race condition + // between conversion webhooks and the cache sync (usually initial list) which causes the webhooks + // to never start because no cache can be populated. + if err := cm.runnables.Webhooks.Start(cm.internalCtx); err != nil { + if !errors.Is(err, wait.ErrWaitTimeout) { + return err + } + } + + // Start and wait for caches. + if err := cm.runnables.Caches.Start(cm.internalCtx); err != nil { + if !errors.Is(err, wait.ErrWaitTimeout) { + return err + } + } + + // Start the non-leaderelection Runnables after the cache has synced. + if err := cm.runnables.Others.Start(cm.internalCtx); err != nil { + if !errors.Is(err, wait.ErrWaitTimeout) { + return err + } + } + + // Start the leader election and all required runnables. + { + ctx, cancel := context.WithCancel(context.Background()) + cm.leaderElectionCancel = cancel + go func() { + if cm.resourceLock != nil { + if err := cm.startLeaderElection(ctx); err != nil { + cm.errChan <- err + } + } else { + // Treat not having leader election enabled the same as being elected. + if err := cm.startLeaderElectionRunnables(); err != nil { + cm.errChan <- err + } + close(cm.elected) + } + }() + } + + ready = true + cm.Unlock() + select { + case <-ctx.Done(): + // We are done + return nil + case err := <-cm.errChan: + // Error starting or running a runnable + return err + } +} + +// engageStopProcedure signals all runnables to stop, reads potential errors +// from the errChan and waits for them to end. It must not be called more than once. +func (cm *controllerManager) engageStopProcedure(stopComplete <-chan struct{}) error { + if !atomic.CompareAndSwapInt64(cm.stopProcedureEngaged, 0, 1) { + return errors.New("stop procedure already engaged") + } + + // Populate the shutdown context, this operation MUST be done before + // closing the internalProceduresStop channel. + // + // The shutdown context immediately expires if the gracefulShutdownTimeout is not set. + var shutdownCancel context.CancelFunc + cm.shutdownCtx, shutdownCancel = context.WithTimeout(context.Background(), cm.gracefulShutdownTimeout) + defer shutdownCancel() + + // Start draining the errors before acquiring the lock to make sure we don't deadlock + // if something that has the lock is blocked on trying to write into the unbuffered + // channel after something else already wrote into it. + var closeOnce sync.Once + go func() { + for { + // Closing in the for loop is required to avoid race conditions between + // the closure of all internal procedures and making sure to have a reader off the error channel. + closeOnce.Do(func() { + // Cancel the internal stop channel and wait for the procedures to stop and complete. + close(cm.internalProceduresStop) + cm.internalCancel() + }) + select { + case err, ok := <-cm.errChan: + if ok { + cm.logger.Error(err, "error received after stop sequence was engaged") + } + case <-stopComplete: + return + } + } + }() + + // We want to close this after the other runnables stop, because we don't + // want things like leader election to try and emit events on a closed + // channel + defer cm.recorderProvider.Stop(cm.shutdownCtx) + defer func() { + // Cancel leader election only after we waited. It will os.Exit() the app for safety. + if cm.resourceLock != nil { + // After asking the context to be cancelled, make sure + // we wait for the leader stopped channel to be closed, otherwise + // we might encounter race conditions between this code + // and the event recorder, which is used within leader election code. + cm.leaderElectionCancel() + <-cm.leaderElectionStopped + } + }() + + go func() { + // First stop the non-leader election runnables. + cm.logger.Info("Stopping and waiting for non leader election runnables") + cm.runnables.Others.StopAndWait(cm.shutdownCtx) + + // Stop all the leader election runnables, which includes reconcilers. + cm.logger.Info("Stopping and waiting for leader election runnables") + cm.runnables.LeaderElection.StopAndWait(cm.shutdownCtx) + + // Stop the caches before the leader election runnables, this is an important + // step to make sure that we don't race with the reconcilers by receiving more events + // from the API servers and enqueueing them. + cm.logger.Info("Stopping and waiting for caches") + cm.runnables.Caches.StopAndWait(cm.shutdownCtx) + + // Webhooks should come last, as they might be still serving some requests. + cm.logger.Info("Stopping and waiting for webhooks") + cm.runnables.Webhooks.StopAndWait(cm.shutdownCtx) + + // Proceed to close the manager and overall shutdown context. + cm.logger.Info("Wait completed, proceeding to shutdown the manager") + shutdownCancel() + }() + + <-cm.shutdownCtx.Done() + if err := cm.shutdownCtx.Err(); err != nil && !errors.Is(err, context.Canceled) { + if errors.Is(err, context.DeadlineExceeded) { + if cm.gracefulShutdownTimeout > 0 { + return fmt.Errorf("failed waiting for all runnables to end within grace period of %s: %w", cm.gracefulShutdownTimeout, err) + } + return nil + } + // For any other error, return the error. + return err + } + + return nil +} + +func (cm *controllerManager) startLeaderElectionRunnables() error { + return cm.runnables.LeaderElection.Start(cm.internalCtx) +} + +func (cm *controllerManager) startLeaderElection(ctx context.Context) (err error) { + l, err := leaderelection.NewLeaderElector(leaderelection.LeaderElectionConfig{ + Lock: cm.resourceLock, + LeaseDuration: cm.leaseDuration, + RenewDeadline: cm.renewDeadline, + RetryPeriod: cm.retryPeriod, + Callbacks: leaderelection.LeaderCallbacks{ + OnStartedLeading: func(_ context.Context) { + if err := cm.startLeaderElectionRunnables(); err != nil { + cm.errChan <- err + return + } + close(cm.elected) + }, + OnStoppedLeading: func() { + if cm.onStoppedLeading != nil { + cm.onStoppedLeading() + } + // Make sure graceful shutdown is skipped if we lost the leader lock without + // intending to. + cm.gracefulShutdownTimeout = time.Duration(0) + // Most implementations of leader election log.Fatal() here. + // Since Start is wrapped in log.Fatal when called, we can just return + // an error here which will cause the program to exit. + cm.errChan <- errors.New("leader election lost") + }, + }, + ReleaseOnCancel: cm.leaderElectionReleaseOnCancel, + }) + if err != nil { + return err + } + + // Start the leader elector process + go func() { + l.Run(ctx) + <-ctx.Done() + close(cm.leaderElectionStopped) + }() + return nil +} + +func (cm *controllerManager) Elected() <-chan struct{} { + return cm.elected +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/manager/manager.go b/vendor/sigs.k8s.io/controller-runtime/pkg/manager/manager.go new file mode 100644 index 0000000000..53716aa9fa --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/manager/manager.go @@ -0,0 +1,638 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package manager + +import ( + "context" + "fmt" + "net" + "net/http" + "reflect" + "time" + + "github.com/go-logr/logr" + "k8s.io/apimachinery/pkg/api/meta" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/leaderelection/resourcelock" + "k8s.io/client-go/tools/record" + "k8s.io/utils/pointer" + "sigs.k8s.io/controller-runtime/pkg/cache" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/cluster" + "sigs.k8s.io/controller-runtime/pkg/config" + "sigs.k8s.io/controller-runtime/pkg/config/v1alpha1" + "sigs.k8s.io/controller-runtime/pkg/healthz" + intrec "sigs.k8s.io/controller-runtime/pkg/internal/recorder" + "sigs.k8s.io/controller-runtime/pkg/leaderelection" + "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/metrics" + "sigs.k8s.io/controller-runtime/pkg/recorder" + "sigs.k8s.io/controller-runtime/pkg/runtime/inject" + "sigs.k8s.io/controller-runtime/pkg/webhook" +) + +// Manager initializes shared dependencies such as Caches and Clients, and provides them to Runnables. +// A Manager is required to create Controllers. +type Manager interface { + // Cluster holds a variety of methods to interact with a cluster. + cluster.Cluster + + // Add will set requested dependencies on the component, and cause the component to be + // started when Start is called. Add will inject any dependencies for which the argument + // implements the inject interface - e.g. inject.Client. + // Depending on if a Runnable implements LeaderElectionRunnable interface, a Runnable can be run in either + // non-leaderelection mode (always running) or leader election mode (managed by leader election if enabled). + Add(Runnable) error + + // Elected is closed when this manager is elected leader of a group of + // managers, either because it won a leader election or because no leader + // election was configured. + Elected() <-chan struct{} + + // AddMetricsExtraHandler adds an extra handler served on path to the http server that serves metrics. + // Might be useful to register some diagnostic endpoints e.g. pprof. Note that these endpoints meant to be + // sensitive and shouldn't be exposed publicly. + // If the simple path -> handler mapping offered here is not enough, a new http server/listener should be added as + // Runnable to the manager via Add method. + AddMetricsExtraHandler(path string, handler http.Handler) error + + // AddHealthzCheck allows you to add Healthz checker + AddHealthzCheck(name string, check healthz.Checker) error + + // AddReadyzCheck allows you to add Readyz checker + AddReadyzCheck(name string, check healthz.Checker) error + + // Start starts all registered Controllers and blocks until the context is cancelled. + // Returns an error if there is an error starting any controller. + // + // If LeaderElection is used, the binary must be exited immediately after this returns, + // otherwise components that need leader election might continue to run after the leader + // lock was lost. + Start(ctx context.Context) error + + // GetWebhookServer returns a webhook.Server + GetWebhookServer() *webhook.Server + + // GetLogger returns this manager's logger. + GetLogger() logr.Logger + + // GetControllerOptions returns controller global configuration options. + GetControllerOptions() v1alpha1.ControllerConfigurationSpec +} + +// Options are the arguments for creating a new Manager. +type Options struct { + // Scheme is the scheme used to resolve runtime.Objects to GroupVersionKinds / Resources. + // Defaults to the kubernetes/client-go scheme.Scheme, but it's almost always better + // to pass your own scheme in. See the documentation in pkg/scheme for more information. + Scheme *runtime.Scheme + + // MapperProvider provides the rest mapper used to map go types to Kubernetes APIs + MapperProvider func(c *rest.Config) (meta.RESTMapper, error) + + // SyncPeriod determines the minimum frequency at which watched resources are + // reconciled. A lower period will correct entropy more quickly, but reduce + // responsiveness to change if there are many watched resources. Change this + // value only if you know what you are doing. Defaults to 10 hours if unset. + // there will a 10 percent jitter between the SyncPeriod of all controllers + // so that all controllers will not send list requests simultaneously. + // + // This applies to all controllers. + // + // A period sync happens for two reasons: + // 1. To insure against a bug in the controller that causes an object to not + // be requeued, when it otherwise should be requeued. + // 2. To insure against an unknown bug in controller-runtime, or its dependencies, + // that causes an object to not be requeued, when it otherwise should be + // requeued, or to be removed from the queue, when it otherwise should not + // be removed. + // + // If you want + // 1. to insure against missed watch events, or + // 2. to poll services that cannot be watched, + // then we recommend that, instead of changing the default period, the + // controller requeue, with a constant duration `t`, whenever the controller + // is "done" with an object, and would otherwise not requeue it, i.e., we + // recommend the `Reconcile` function return `reconcile.Result{RequeueAfter: t}`, + // instead of `reconcile.Result{}`. + SyncPeriod *time.Duration + + // Logger is the logger that should be used by this manager. + // If none is set, it defaults to log.Log global logger. + Logger logr.Logger + + // LeaderElection determines whether or not to use leader election when + // starting the manager. + LeaderElection bool + + // LeaderElectionResourceLock determines which resource lock to use for leader election, + // defaults to "leases". Change this value only if you know what you are doing. + // + // If you are using `configmaps`/`endpoints` resource lock and want to migrate to "leases", + // you might do so by migrating to the respective multilock first ("configmapsleases" or "endpointsleases"), + // which will acquire a leader lock on both resources. + // After all your users have migrated to the multilock, you can go ahead and migrate to "leases". + // Please also keep in mind, that users might skip versions of your controller. + // + // Note: before controller-runtime version v0.7, it was set to "configmaps". + // And from v0.7 to v0.11, the default was "configmapsleases", which was + // used to migrate from configmaps to leases. + // Since the default was "configmapsleases" for over a year, spanning five minor releases, + // any actively maintained operators are very likely to have a released version that uses + // "configmapsleases". Therefore defaulting to "leases" should be safe since v0.12. + // + // So, what do you have to do when you are updating your controller-runtime dependency + // from a lower version to v0.12 or newer? + // - If your operator matches at least one of these conditions: + // - the LeaderElectionResourceLock in your operator has already been explicitly set to "leases" + // - the old controller-runtime version is between v0.7.0 and v0.11.x and the + // LeaderElectionResourceLock wasn't set or was set to "leases"/"configmapsleases"/"endpointsleases" + // feel free to update controller-runtime to v0.12 or newer. + // - Otherwise, you may have to take these steps: + // 1. update controller-runtime to v0.12 or newer in your go.mod + // 2. set LeaderElectionResourceLock to "configmapsleases" (or "endpointsleases") + // 3. package your operator and upgrade it in all your clusters + // 4. only if you have finished 3, you can remove the LeaderElectionResourceLock to use the default "leases" + // Otherwise, your operator might end up with multiple running instances that + // each acquired leadership through different resource locks during upgrades and thus + // act on the same resources concurrently. + LeaderElectionResourceLock string + + // LeaderElectionNamespace determines the namespace in which the leader + // election resource will be created. + LeaderElectionNamespace string + + // LeaderElectionID determines the name of the resource that leader election + // will use for holding the leader lock. + LeaderElectionID string + + // LeaderElectionConfig can be specified to override the default configuration + // that is used to build the leader election client. + LeaderElectionConfig *rest.Config + + // LeaderElectionReleaseOnCancel defines if the leader should step down voluntarily + // when the Manager ends. This requires the binary to immediately end when the + // Manager is stopped, otherwise this setting is unsafe. Setting this significantly + // speeds up voluntary leader transitions as the new leader doesn't have to wait + // LeaseDuration time first. + LeaderElectionReleaseOnCancel bool + + // LeaseDuration is the duration that non-leader candidates will + // wait to force acquire leadership. This is measured against time of + // last observed ack. Default is 15 seconds. + LeaseDuration *time.Duration + // RenewDeadline is the duration that the acting controlplane will retry + // refreshing leadership before giving up. Default is 10 seconds. + RenewDeadline *time.Duration + // RetryPeriod is the duration the LeaderElector clients should wait + // between tries of actions. Default is 2 seconds. + RetryPeriod *time.Duration + + // Namespace, if specified, restricts the manager's cache to watch objects in + // the desired namespace. Defaults to all namespaces. + // + // Note: If a namespace is specified, controllers can still Watch for a + // cluster-scoped resource (e.g Node). For namespaced resources, the cache + // will only hold objects from the desired namespace. + Namespace string + + // MetricsBindAddress is the TCP address that the controller should bind to + // for serving prometheus metrics. + // It can be set to "0" to disable the metrics serving. + MetricsBindAddress string + + // HealthProbeBindAddress is the TCP address that the controller should bind to + // for serving health probes + HealthProbeBindAddress string + + // Readiness probe endpoint name, defaults to "readyz" + ReadinessEndpointName string + + // Liveness probe endpoint name, defaults to "healthz" + LivenessEndpointName string + + // Port is the port that the webhook server serves at. + // It is used to set webhook.Server.Port if WebhookServer is not set. + Port int + // Host is the hostname that the webhook server binds to. + // It is used to set webhook.Server.Host if WebhookServer is not set. + Host string + + // CertDir is the directory that contains the server key and certificate. + // If not set, webhook server would look up the server key and certificate in + // {TempDir}/k8s-webhook-server/serving-certs. The server key and certificate + // must be named tls.key and tls.crt, respectively. + // It is used to set webhook.Server.CertDir if WebhookServer is not set. + CertDir string + + // WebhookServer is an externally configured webhook.Server. By default, + // a Manager will create a default server using Port, Host, and CertDir; + // if this is set, the Manager will use this server instead. + WebhookServer *webhook.Server + + // Functions to allow for a user to customize values that will be injected. + + // NewCache is the function that will create the cache to be used + // by the manager. If not set this will use the default new cache function. + NewCache cache.NewCacheFunc + + // NewClient is the func that creates the client to be used by the manager. + // If not set this will create the default DelegatingClient that will + // use the cache for reads and the client for writes. + NewClient cluster.NewClientFunc + + // BaseContext is the function that provides Context values to Runnables + // managed by the Manager. If a BaseContext function isn't provided, Runnables + // will receive a new Background Context instead. + BaseContext BaseContextFunc + + // ClientDisableCacheFor tells the client that, if any cache is used, to bypass it + // for the given objects. + ClientDisableCacheFor []client.Object + + // DryRunClient specifies whether the client should be configured to enforce + // dryRun mode. + DryRunClient bool + + // EventBroadcaster records Events emitted by the manager and sends them to the Kubernetes API + // Use this to customize the event correlator and spam filter + // + // Deprecated: using this may cause goroutine leaks if the lifetime of your manager or controllers + // is shorter than the lifetime of your process. + EventBroadcaster record.EventBroadcaster + + // GracefulShutdownTimeout is the duration given to runnable to stop before the manager actually returns on stop. + // To disable graceful shutdown, set to time.Duration(0) + // To use graceful shutdown without timeout, set to a negative duration, e.G. time.Duration(-1) + // The graceful shutdown is skipped for safety reasons in case the leader election lease is lost. + GracefulShutdownTimeout *time.Duration + + // Controller contains global configuration options for controllers + // registered within this manager. + // +optional + Controller v1alpha1.ControllerConfigurationSpec + + // makeBroadcaster allows deferring the creation of the broadcaster to + // avoid leaking goroutines if we never call Start on this manager. It also + // returns whether or not this is a "owned" broadcaster, and as such should be + // stopped with the manager. + makeBroadcaster intrec.EventBroadcasterProducer + + // Dependency injection for testing + newRecorderProvider func(config *rest.Config, scheme *runtime.Scheme, logger logr.Logger, makeBroadcaster intrec.EventBroadcasterProducer) (*intrec.Provider, error) + newResourceLock func(config *rest.Config, recorderProvider recorder.Provider, options leaderelection.Options) (resourcelock.Interface, error) + newMetricsListener func(addr string) (net.Listener, error) + newHealthProbeListener func(addr string) (net.Listener, error) +} + +// BaseContextFunc is a function used to provide a base Context to Runnables +// managed by a Manager. +type BaseContextFunc func() context.Context + +// Runnable allows a component to be started. +// It's very important that Start blocks until +// it's done running. +type Runnable interface { + // Start starts running the component. The component will stop running + // when the context is closed. Start blocks until the context is closed or + // an error occurs. + Start(context.Context) error +} + +// RunnableFunc implements Runnable using a function. +// It's very important that the given function block +// until it's done running. +type RunnableFunc func(context.Context) error + +// Start implements Runnable. +func (r RunnableFunc) Start(ctx context.Context) error { + return r(ctx) +} + +// LeaderElectionRunnable knows if a Runnable needs to be run in the leader election mode. +type LeaderElectionRunnable interface { + // NeedLeaderElection returns true if the Runnable needs to be run in the leader election mode. + // e.g. controllers need to be run in leader election mode, while webhook server doesn't. + NeedLeaderElection() bool +} + +// New returns a new Manager for creating Controllers. +func New(config *rest.Config, options Options) (Manager, error) { + // Set default values for options fields + options = setOptionsDefaults(options) + + cluster, err := cluster.New(config, func(clusterOptions *cluster.Options) { + clusterOptions.Scheme = options.Scheme + clusterOptions.MapperProvider = options.MapperProvider + clusterOptions.Logger = options.Logger + clusterOptions.SyncPeriod = options.SyncPeriod + clusterOptions.Namespace = options.Namespace + clusterOptions.NewCache = options.NewCache + clusterOptions.NewClient = options.NewClient + clusterOptions.ClientDisableCacheFor = options.ClientDisableCacheFor + clusterOptions.DryRunClient = options.DryRunClient + clusterOptions.EventBroadcaster = options.EventBroadcaster //nolint:staticcheck + }) + if err != nil { + return nil, err + } + + // Create the recorder provider to inject event recorders for the components. + // TODO(directxman12): the log for the event provider should have a context (name, tags, etc) specific + // to the particular controller that it's being injected into, rather than a generic one like is here. + recorderProvider, err := options.newRecorderProvider(config, cluster.GetScheme(), options.Logger.WithName("events"), options.makeBroadcaster) + if err != nil { + return nil, err + } + + // Create the resource lock to enable leader election) + var leaderConfig *rest.Config + var leaderRecorderProvider *intrec.Provider + + if options.LeaderElectionConfig == nil { + leaderConfig = rest.CopyConfig(config) + leaderRecorderProvider = recorderProvider + } else { + leaderConfig = rest.CopyConfig(options.LeaderElectionConfig) + leaderRecorderProvider, err = options.newRecorderProvider(leaderConfig, cluster.GetScheme(), options.Logger.WithName("events"), options.makeBroadcaster) + if err != nil { + return nil, err + } + } + + resourceLock, err := options.newResourceLock(leaderConfig, leaderRecorderProvider, leaderelection.Options{ + LeaderElection: options.LeaderElection, + LeaderElectionResourceLock: options.LeaderElectionResourceLock, + LeaderElectionID: options.LeaderElectionID, + LeaderElectionNamespace: options.LeaderElectionNamespace, + }) + if err != nil { + return nil, err + } + + // Create the metrics listener. This will throw an error if the metrics bind + // address is invalid or already in use. + metricsListener, err := options.newMetricsListener(options.MetricsBindAddress) + if err != nil { + return nil, err + } + + // By default we have no extra endpoints to expose on metrics http server. + metricsExtraHandlers := make(map[string]http.Handler) + + // Create health probes listener. This will throw an error if the bind + // address is invalid or already in use. + healthProbeListener, err := options.newHealthProbeListener(options.HealthProbeBindAddress) + if err != nil { + return nil, err + } + + errChan := make(chan error) + runnables := newRunnables(options.BaseContext, errChan) + + return &controllerManager{ + stopProcedureEngaged: pointer.Int64(0), + cluster: cluster, + runnables: runnables, + errChan: errChan, + recorderProvider: recorderProvider, + resourceLock: resourceLock, + metricsListener: metricsListener, + metricsExtraHandlers: metricsExtraHandlers, + controllerOptions: options.Controller, + logger: options.Logger, + elected: make(chan struct{}), + port: options.Port, + host: options.Host, + certDir: options.CertDir, + webhookServer: options.WebhookServer, + leaseDuration: *options.LeaseDuration, + renewDeadline: *options.RenewDeadline, + retryPeriod: *options.RetryPeriod, + healthProbeListener: healthProbeListener, + readinessEndpointName: options.ReadinessEndpointName, + livenessEndpointName: options.LivenessEndpointName, + gracefulShutdownTimeout: *options.GracefulShutdownTimeout, + internalProceduresStop: make(chan struct{}), + leaderElectionStopped: make(chan struct{}), + leaderElectionReleaseOnCancel: options.LeaderElectionReleaseOnCancel, + }, nil +} + +// AndFrom will use a supplied type and convert to Options +// any options already set on Options will be ignored, this is used to allow +// cli flags to override anything specified in the config file. +func (o Options) AndFrom(loader config.ControllerManagerConfiguration) (Options, error) { + if inj, wantsScheme := loader.(inject.Scheme); wantsScheme { + err := inj.InjectScheme(o.Scheme) + if err != nil { + return o, err + } + } + + newObj, err := loader.Complete() + if err != nil { + return o, err + } + + o = o.setLeaderElectionConfig(newObj) + + if o.SyncPeriod == nil && newObj.SyncPeriod != nil { + o.SyncPeriod = &newObj.SyncPeriod.Duration + } + + if o.Namespace == "" && newObj.CacheNamespace != "" { + o.Namespace = newObj.CacheNamespace + } + + if o.MetricsBindAddress == "" && newObj.Metrics.BindAddress != "" { + o.MetricsBindAddress = newObj.Metrics.BindAddress + } + + if o.HealthProbeBindAddress == "" && newObj.Health.HealthProbeBindAddress != "" { + o.HealthProbeBindAddress = newObj.Health.HealthProbeBindAddress + } + + if o.ReadinessEndpointName == "" && newObj.Health.ReadinessEndpointName != "" { + o.ReadinessEndpointName = newObj.Health.ReadinessEndpointName + } + + if o.LivenessEndpointName == "" && newObj.Health.LivenessEndpointName != "" { + o.LivenessEndpointName = newObj.Health.LivenessEndpointName + } + + if o.Port == 0 && newObj.Webhook.Port != nil { + o.Port = *newObj.Webhook.Port + } + + if o.Host == "" && newObj.Webhook.Host != "" { + o.Host = newObj.Webhook.Host + } + + if o.CertDir == "" && newObj.Webhook.CertDir != "" { + o.CertDir = newObj.Webhook.CertDir + } + + if newObj.Controller != nil { + if o.Controller.CacheSyncTimeout == nil && newObj.Controller.CacheSyncTimeout != nil { + o.Controller.CacheSyncTimeout = newObj.Controller.CacheSyncTimeout + } + + if len(o.Controller.GroupKindConcurrency) == 0 && len(newObj.Controller.GroupKindConcurrency) > 0 { + o.Controller.GroupKindConcurrency = newObj.Controller.GroupKindConcurrency + } + } + + return o, nil +} + +// AndFromOrDie will use options.AndFrom() and will panic if there are errors. +func (o Options) AndFromOrDie(loader config.ControllerManagerConfiguration) Options { + o, err := o.AndFrom(loader) + if err != nil { + panic(fmt.Sprintf("could not parse config file: %v", err)) + } + return o +} + +func (o Options) setLeaderElectionConfig(obj v1alpha1.ControllerManagerConfigurationSpec) Options { + if obj.LeaderElection == nil { + // The source does not have any configuration; noop + return o + } + + if !o.LeaderElection && obj.LeaderElection.LeaderElect != nil { + o.LeaderElection = *obj.LeaderElection.LeaderElect + } + + if o.LeaderElectionResourceLock == "" && obj.LeaderElection.ResourceLock != "" { + o.LeaderElectionResourceLock = obj.LeaderElection.ResourceLock + } + + if o.LeaderElectionNamespace == "" && obj.LeaderElection.ResourceNamespace != "" { + o.LeaderElectionNamespace = obj.LeaderElection.ResourceNamespace + } + + if o.LeaderElectionID == "" && obj.LeaderElection.ResourceName != "" { + o.LeaderElectionID = obj.LeaderElection.ResourceName + } + + if o.LeaseDuration == nil && !reflect.DeepEqual(obj.LeaderElection.LeaseDuration, metav1.Duration{}) { + o.LeaseDuration = &obj.LeaderElection.LeaseDuration.Duration + } + + if o.RenewDeadline == nil && !reflect.DeepEqual(obj.LeaderElection.RenewDeadline, metav1.Duration{}) { + o.RenewDeadline = &obj.LeaderElection.RenewDeadline.Duration + } + + if o.RetryPeriod == nil && !reflect.DeepEqual(obj.LeaderElection.RetryPeriod, metav1.Duration{}) { + o.RetryPeriod = &obj.LeaderElection.RetryPeriod.Duration + } + + return o +} + +// defaultHealthProbeListener creates the default health probes listener bound to the given address. +func defaultHealthProbeListener(addr string) (net.Listener, error) { + if addr == "" || addr == "0" { + return nil, nil + } + + ln, err := net.Listen("tcp", addr) + if err != nil { + return nil, fmt.Errorf("error listening on %s: %w", addr, err) + } + return ln, nil +} + +// defaultBaseContext is used as the BaseContext value in Options if one +// has not already been set. +func defaultBaseContext() context.Context { + return context.Background() +} + +// setOptionsDefaults set default values for Options fields. +func setOptionsDefaults(options Options) Options { + // Allow newResourceLock to be mocked + if options.newResourceLock == nil { + options.newResourceLock = leaderelection.NewResourceLock + } + + // Allow newRecorderProvider to be mocked + if options.newRecorderProvider == nil { + options.newRecorderProvider = intrec.NewProvider + } + + // This is duplicated with pkg/cluster, we need it here + // for the leader election and there to provide the user with + // an EventBroadcaster + if options.EventBroadcaster == nil { + // defer initialization to avoid leaking by default + options.makeBroadcaster = func() (record.EventBroadcaster, bool) { + return record.NewBroadcaster(), true + } + } else { + options.makeBroadcaster = func() (record.EventBroadcaster, bool) { + return options.EventBroadcaster, false + } + } + + if options.newMetricsListener == nil { + options.newMetricsListener = metrics.NewListener + } + leaseDuration, renewDeadline, retryPeriod := defaultLeaseDuration, defaultRenewDeadline, defaultRetryPeriod + if options.LeaseDuration == nil { + options.LeaseDuration = &leaseDuration + } + + if options.RenewDeadline == nil { + options.RenewDeadline = &renewDeadline + } + + if options.RetryPeriod == nil { + options.RetryPeriod = &retryPeriod + } + + if options.ReadinessEndpointName == "" { + options.ReadinessEndpointName = defaultReadinessEndpoint + } + + if options.LivenessEndpointName == "" { + options.LivenessEndpointName = defaultLivenessEndpoint + } + + if options.newHealthProbeListener == nil { + options.newHealthProbeListener = defaultHealthProbeListener + } + + if options.GracefulShutdownTimeout == nil { + gracefulShutdownTimeout := defaultGracefulShutdownPeriod + options.GracefulShutdownTimeout = &gracefulShutdownTimeout + } + + if options.Logger.GetSink() == nil { + options.Logger = log.Log + } + + if options.BaseContext == nil { + options.BaseContext = defaultBaseContext + } + + return options +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/manager/runnable_group.go b/vendor/sigs.k8s.io/controller-runtime/pkg/manager/runnable_group.go new file mode 100644 index 0000000000..f7b91a209f --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/manager/runnable_group.go @@ -0,0 +1,297 @@ +package manager + +import ( + "context" + "errors" + "sync" + + "sigs.k8s.io/controller-runtime/pkg/webhook" +) + +var ( + errRunnableGroupStopped = errors.New("can't accept new runnable as stop procedure is already engaged") +) + +// readyRunnable encapsulates a runnable with +// a ready check. +type readyRunnable struct { + Runnable + Check runnableCheck + signalReady bool +} + +// runnableCheck can be passed to Add() to let the runnable group determine that a +// runnable is ready. A runnable check should block until a runnable is ready, +// if the returned result is false, the runnable is considered not ready and failed. +type runnableCheck func(ctx context.Context) bool + +// runnables handles all the runnables for a manager by grouping them accordingly to their +// type (webhooks, caches etc.). +type runnables struct { + Webhooks *runnableGroup + Caches *runnableGroup + LeaderElection *runnableGroup + Others *runnableGroup +} + +// newRunnables creates a new runnables object. +func newRunnables(baseContext BaseContextFunc, errChan chan error) *runnables { + return &runnables{ + Webhooks: newRunnableGroup(baseContext, errChan), + Caches: newRunnableGroup(baseContext, errChan), + LeaderElection: newRunnableGroup(baseContext, errChan), + Others: newRunnableGroup(baseContext, errChan), + } +} + +// Add adds a runnable to closest group of runnable that they belong to. +// +// Add should be able to be called before and after Start, but not after StopAndWait. +// Add should return an error when called during StopAndWait. +// The runnables added before Start are started when Start is called. +// The runnables added after Start are started directly. +func (r *runnables) Add(fn Runnable) error { + switch runnable := fn.(type) { + case hasCache: + return r.Caches.Add(fn, func(ctx context.Context) bool { + return runnable.GetCache().WaitForCacheSync(ctx) + }) + case *webhook.Server: + return r.Webhooks.Add(fn, nil) + case LeaderElectionRunnable: + if !runnable.NeedLeaderElection() { + return r.Others.Add(fn, nil) + } + return r.LeaderElection.Add(fn, nil) + default: + return r.LeaderElection.Add(fn, nil) + } +} + +// runnableGroup manages a group of runnables that are +// meant to be running together until StopAndWait is called. +// +// Runnables can be added to a group after the group has started +// but not after it's stopped or while shutting down. +type runnableGroup struct { + ctx context.Context + cancel context.CancelFunc + + start sync.Mutex + startOnce sync.Once + started bool + startQueue []*readyRunnable + startReadyCh chan *readyRunnable + + stop sync.RWMutex + stopOnce sync.Once + stopped bool + + // errChan is the error channel passed by the caller + // when the group is created. + // All errors are forwarded to this channel once they occur. + errChan chan error + + // ch is the internal channel where the runnables are read off from. + ch chan *readyRunnable + + // wg is an internal sync.WaitGroup that allows us to properly stop + // and wait for all the runnables to finish before returning. + wg *sync.WaitGroup +} + +func newRunnableGroup(baseContext BaseContextFunc, errChan chan error) *runnableGroup { + r := &runnableGroup{ + startReadyCh: make(chan *readyRunnable), + errChan: errChan, + ch: make(chan *readyRunnable), + wg: new(sync.WaitGroup), + } + + r.ctx, r.cancel = context.WithCancel(baseContext()) + return r +} + +// Started returns true if the group has started. +func (r *runnableGroup) Started() bool { + r.start.Lock() + defer r.start.Unlock() + return r.started +} + +// Start starts the group and waits for all +// initially registered runnables to start. +// It can only be called once, subsequent calls have no effect. +func (r *runnableGroup) Start(ctx context.Context) error { + var retErr error + + r.startOnce.Do(func() { + defer close(r.startReadyCh) + + // Start the internal reconciler. + go r.reconcile() + + // Start the group and queue up all + // the runnables that were added prior. + r.start.Lock() + r.started = true + for _, rn := range r.startQueue { + rn.signalReady = true + r.ch <- rn + } + r.start.Unlock() + + // If we don't have any queue, return. + if len(r.startQueue) == 0 { + return + } + + // Wait for all runnables to signal. + for { + select { + case <-ctx.Done(): + if err := ctx.Err(); !errors.Is(err, context.Canceled) { + retErr = err + } + case rn := <-r.startReadyCh: + for i, existing := range r.startQueue { + if existing == rn { + // Remove the item from the start queue. + r.startQueue = append(r.startQueue[:i], r.startQueue[i+1:]...) + break + } + } + // We're done waiting if the queue is empty, return. + if len(r.startQueue) == 0 { + return + } + } + } + }) + + return retErr +} + +// reconcile is our main entrypoint for every runnable added +// to this group. Its primary job is to read off the internal channel +// and schedule runnables while tracking their state. +func (r *runnableGroup) reconcile() { + for runnable := range r.ch { + // Handle stop. + // If the shutdown has been called we want to avoid + // adding new goroutines to the WaitGroup because Wait() + // panics if Add() is called after it. + { + r.stop.RLock() + if r.stopped { + // Drop any runnables if we're stopped. + r.errChan <- errRunnableGroupStopped + r.stop.RUnlock() + continue + } + + // Why is this here? + // When StopAndWait is called, if a runnable is in the process + // of being added, we could end up in a situation where + // the WaitGroup is incremented while StopAndWait has called Wait(), + // which would result in a panic. + r.wg.Add(1) + r.stop.RUnlock() + } + + // Start the runnable. + go func(rn *readyRunnable) { + go func() { + if rn.Check(r.ctx) { + if rn.signalReady { + r.startReadyCh <- rn + } + } + }() + + // If we return, the runnable ended cleanly + // or returned an error to the channel. + // + // We should always decrement the WaitGroup here. + defer r.wg.Done() + + // Start the runnable. + if err := rn.Start(r.ctx); err != nil { + r.errChan <- err + } + }(runnable) + } +} + +// Add should be able to be called before and after Start, but not after StopAndWait. +// Add should return an error when called during StopAndWait. +func (r *runnableGroup) Add(rn Runnable, ready runnableCheck) error { + r.stop.RLock() + if r.stopped { + r.stop.RUnlock() + return errRunnableGroupStopped + } + r.stop.RUnlock() + + if ready == nil { + ready = func(_ context.Context) bool { return true } + } + + readyRunnable := &readyRunnable{ + Runnable: rn, + Check: ready, + } + + // Handle start. + // If the overall runnable group isn't started yet + // we want to buffer the runnables and let Start() + // queue them up again later. + { + r.start.Lock() + + // Check if we're already started. + if !r.started { + // Store the runnable in the internal if not. + r.startQueue = append(r.startQueue, readyRunnable) + r.start.Unlock() + return nil + } + r.start.Unlock() + } + + // Enqueue the runnable. + r.ch <- readyRunnable + return nil +} + +// StopAndWait waits for all the runnables to finish before returning. +func (r *runnableGroup) StopAndWait(ctx context.Context) { + r.stopOnce.Do(func() { + // Close the reconciler channel once we're done. + defer close(r.ch) + + _ = r.Start(ctx) + r.stop.Lock() + // Store the stopped variable so we don't accept any new + // runnables for the time being. + r.stopped = true + r.stop.Unlock() + + // Cancel the internal channel. + r.cancel() + + done := make(chan struct{}) + go func() { + defer close(done) + // Wait for all the runnables to finish. + r.wg.Wait() + }() + + select { + case <-done: + // We're done, exit. + case <-ctx.Done(): + // Calling context has expired, exit. + } + }) +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/manager/signals/doc.go b/vendor/sigs.k8s.io/controller-runtime/pkg/manager/signals/doc.go new file mode 100644 index 0000000000..737cc7eff2 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/manager/signals/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package signals contains libraries for handling signals to gracefully +// shutdown the manager in combination with Kubernetes pod graceful termination +// policy. +package signals diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/manager/signals/signal.go b/vendor/sigs.k8s.io/controller-runtime/pkg/manager/signals/signal.go new file mode 100644 index 0000000000..a79cfb42df --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/manager/signals/signal.go @@ -0,0 +1,45 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package signals + +import ( + "context" + "os" + "os/signal" +) + +var onlyOneSignalHandler = make(chan struct{}) + +// SetupSignalHandler registers for SIGTERM and SIGINT. A context is returned +// which is canceled on one of these signals. If a second signal is caught, the program +// is terminated with exit code 1. +func SetupSignalHandler() context.Context { + close(onlyOneSignalHandler) // panics when called twice + + ctx, cancel := context.WithCancel(context.Background()) + + c := make(chan os.Signal, 2) + signal.Notify(c, shutdownSignals...) + go func() { + <-c + cancel() + <-c + os.Exit(1) // second signal. Exit directly. + }() + + return ctx +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/manager/signals/signal_posix.go b/vendor/sigs.k8s.io/controller-runtime/pkg/manager/signals/signal_posix.go new file mode 100644 index 0000000000..a0f00a7321 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/manager/signals/signal_posix.go @@ -0,0 +1,27 @@ +//go:build !windows +// +build !windows + +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package signals + +import ( + "os" + "syscall" +) + +var shutdownSignals = []os.Signal{os.Interrupt, syscall.SIGTERM} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/manager/signals/signal_windows.go b/vendor/sigs.k8s.io/controller-runtime/pkg/manager/signals/signal_windows.go new file mode 100644 index 0000000000..4907d573fe --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/manager/signals/signal_windows.go @@ -0,0 +1,23 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package signals + +import ( + "os" +) + +var shutdownSignals = []os.Signal{os.Interrupt} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/metrics/client_go_adapter.go b/vendor/sigs.k8s.io/controller-runtime/pkg/metrics/client_go_adapter.go new file mode 100644 index 0000000000..dc805a9d04 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/metrics/client_go_adapter.go @@ -0,0 +1,111 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package metrics + +import ( + "context" + "net/url" + "time" + + "github.com/prometheus/client_golang/prometheus" + clientmetrics "k8s.io/client-go/tools/metrics" +) + +// this file contains setup logic to initialize the myriad of places +// that client-go registers metrics. We copy the names and formats +// from Kubernetes so that we match the core controllers. + +// Metrics subsystem and all of the keys used by the rest client. +const ( + RestClientSubsystem = "rest_client" + LatencyKey = "request_latency_seconds" + ResultKey = "requests_total" +) + +var ( + // client metrics. + + // RequestLatency reports the request latency in seconds per verb/URL. + // Deprecated: This metric is deprecated for removal in a future release: using the URL as a + // dimension results in cardinality explosion for some consumers. It was deprecated upstream + // in k8s v1.14 and hidden in v1.17 via https://github.com/kubernetes/kubernetes/pull/83836. + // It is not registered by default. To register: + // import ( + // clientmetrics "k8s.io/client-go/tools/metrics" + // clmetrics "sigs.k8s.io/controller-runtime/metrics" + // ) + // + // func init() { + // clmetrics.Registry.MustRegister(clmetrics.RequestLatency) + // clientmetrics.Register(clientmetrics.RegisterOpts{ + // RequestLatency: clmetrics.LatencyAdapter + // }) + // } + RequestLatency = prometheus.NewHistogramVec(prometheus.HistogramOpts{ + Subsystem: RestClientSubsystem, + Name: LatencyKey, + Help: "Request latency in seconds. Broken down by verb and URL.", + Buckets: prometheus.ExponentialBuckets(0.001, 2, 10), + }, []string{"verb", "url"}) + + requestResult = prometheus.NewCounterVec(prometheus.CounterOpts{ + Subsystem: RestClientSubsystem, + Name: ResultKey, + Help: "Number of HTTP requests, partitioned by status code, method, and host.", + }, []string{"code", "method", "host"}) +) + +func init() { + registerClientMetrics() +} + +// registerClientMetrics sets up the client latency metrics from client-go. +func registerClientMetrics() { + // register the metrics with our registry + Registry.MustRegister(requestResult) + + // register the metrics with client-go + clientmetrics.Register(clientmetrics.RegisterOpts{ + RequestResult: &resultAdapter{metric: requestResult}, + }) +} + +// this section contains adapters, implementations, and other sundry organic, artisanally +// hand-crafted syntax trees required to convince client-go that it actually wants to let +// someone use its metrics. + +// Client metrics adapters (method #1 for client-go metrics), +// copied (more-or-less directly) from k8s.io/kubernetes setup code +// (which isn't anywhere in an easily-importable place). + +// LatencyAdapter implements LatencyMetric. +type LatencyAdapter struct { + metric *prometheus.HistogramVec +} + +// Observe increments the request latency metric for the given verb/URL. +func (l *LatencyAdapter) Observe(_ context.Context, verb string, u url.URL, latency time.Duration) { + l.metric.WithLabelValues(verb, u.String()).Observe(latency.Seconds()) +} + +type resultAdapter struct { + metric *prometheus.CounterVec +} + +func (r *resultAdapter) Increment(_ context.Context, code, method, host string) { + r.metric.WithLabelValues(code, method, host).Inc() +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/metrics/doc.go b/vendor/sigs.k8s.io/controller-runtime/pkg/metrics/doc.go new file mode 100644 index 0000000000..6ed9df9514 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/metrics/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* +Package metrics contains controller related metrics utilities +*/ +package metrics diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/metrics/listener.go b/vendor/sigs.k8s.io/controller-runtime/pkg/metrics/listener.go new file mode 100644 index 0000000000..123d8c15f9 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/metrics/listener.go @@ -0,0 +1,52 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package metrics + +import ( + "fmt" + "net" + + logf "sigs.k8s.io/controller-runtime/pkg/internal/log" +) + +var log = logf.RuntimeLog.WithName("metrics") + +// DefaultBindAddress sets the default bind address for the metrics listener +// The metrics is on by default. +var DefaultBindAddress = ":8080" + +// NewListener creates a new TCP listener bound to the given address. +func NewListener(addr string) (net.Listener, error) { + if addr == "" { + // If the metrics bind address is empty, default to ":8080" + addr = DefaultBindAddress + } + + // Add a case to disable metrics altogether + if addr == "0" { + return nil, nil + } + + log.Info("Metrics server is starting to listen", "addr", addr) + ln, err := net.Listen("tcp", addr) + if err != nil { + er := fmt.Errorf("error listening on %s: %w", addr, err) + log.Error(er, "metrics server failed to listen. You may want to disable the metrics server or use another port if it is due to conflicts") + return nil, er + } + return ln, nil +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/metrics/registry.go b/vendor/sigs.k8s.io/controller-runtime/pkg/metrics/registry.go new file mode 100644 index 0000000000..ce17124d53 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/metrics/registry.go @@ -0,0 +1,30 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package metrics + +import "github.com/prometheus/client_golang/prometheus" + +// RegistererGatherer combines both parts of the API of a Prometheus +// registry, both the Registerer and the Gatherer interfaces. +type RegistererGatherer interface { + prometheus.Registerer + prometheus.Gatherer +} + +// Registry is a prometheus registry for storing metrics within the +// controller-runtime. +var Registry RegistererGatherer = prometheus.NewRegistry() diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/metrics/workqueue.go b/vendor/sigs.k8s.io/controller-runtime/pkg/metrics/workqueue.go new file mode 100644 index 0000000000..8ca47235da --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/metrics/workqueue.go @@ -0,0 +1,130 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package metrics + +import ( + "github.com/prometheus/client_golang/prometheus" + "k8s.io/client-go/util/workqueue" +) + +// This file is copied and adapted from k8s.io/kubernetes/pkg/util/workqueue/prometheus +// which registers metrics to the default prometheus Registry. We require very +// similar functionality, but must register metrics to a different Registry. + +// Metrics subsystem and all keys used by the workqueue. +const ( + WorkQueueSubsystem = "workqueue" + DepthKey = "depth" + AddsKey = "adds_total" + QueueLatencyKey = "queue_duration_seconds" + WorkDurationKey = "work_duration_seconds" + UnfinishedWorkKey = "unfinished_work_seconds" + LongestRunningProcessorKey = "longest_running_processor_seconds" + RetriesKey = "retries_total" +) + +var ( + depth = prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Subsystem: WorkQueueSubsystem, + Name: DepthKey, + Help: "Current depth of workqueue", + }, []string{"name"}) + + adds = prometheus.NewCounterVec(prometheus.CounterOpts{ + Subsystem: WorkQueueSubsystem, + Name: AddsKey, + Help: "Total number of adds handled by workqueue", + }, []string{"name"}) + + latency = prometheus.NewHistogramVec(prometheus.HistogramOpts{ + Subsystem: WorkQueueSubsystem, + Name: QueueLatencyKey, + Help: "How long in seconds an item stays in workqueue before being requested", + Buckets: prometheus.ExponentialBuckets(10e-9, 10, 10), + }, []string{"name"}) + + workDuration = prometheus.NewHistogramVec(prometheus.HistogramOpts{ + Subsystem: WorkQueueSubsystem, + Name: WorkDurationKey, + Help: "How long in seconds processing an item from workqueue takes.", + Buckets: prometheus.ExponentialBuckets(10e-9, 10, 10), + }, []string{"name"}) + + unfinished = prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Subsystem: WorkQueueSubsystem, + Name: UnfinishedWorkKey, + Help: "How many seconds of work has been done that " + + "is in progress and hasn't been observed by work_duration. Large " + + "values indicate stuck threads. One can deduce the number of stuck " + + "threads by observing the rate at which this increases.", + }, []string{"name"}) + + longestRunningProcessor = prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Subsystem: WorkQueueSubsystem, + Name: LongestRunningProcessorKey, + Help: "How many seconds has the longest running " + + "processor for workqueue been running.", + }, []string{"name"}) + + retries = prometheus.NewCounterVec(prometheus.CounterOpts{ + Subsystem: WorkQueueSubsystem, + Name: RetriesKey, + Help: "Total number of retries handled by workqueue", + }, []string{"name"}) +) + +func init() { + Registry.MustRegister(depth) + Registry.MustRegister(adds) + Registry.MustRegister(latency) + Registry.MustRegister(workDuration) + Registry.MustRegister(unfinished) + Registry.MustRegister(longestRunningProcessor) + Registry.MustRegister(retries) + + workqueue.SetProvider(workqueueMetricsProvider{}) +} + +type workqueueMetricsProvider struct{} + +func (workqueueMetricsProvider) NewDepthMetric(name string) workqueue.GaugeMetric { + return depth.WithLabelValues(name) +} + +func (workqueueMetricsProvider) NewAddsMetric(name string) workqueue.CounterMetric { + return adds.WithLabelValues(name) +} + +func (workqueueMetricsProvider) NewLatencyMetric(name string) workqueue.HistogramMetric { + return latency.WithLabelValues(name) +} + +func (workqueueMetricsProvider) NewWorkDurationMetric(name string) workqueue.HistogramMetric { + return workDuration.WithLabelValues(name) +} + +func (workqueueMetricsProvider) NewUnfinishedWorkSecondsMetric(name string) workqueue.SettableGaugeMetric { + return unfinished.WithLabelValues(name) +} + +func (workqueueMetricsProvider) NewLongestRunningProcessorSecondsMetric(name string) workqueue.SettableGaugeMetric { + return longestRunningProcessor.WithLabelValues(name) +} + +func (workqueueMetricsProvider) NewRetriesMetric(name string) workqueue.CounterMetric { + return retries.WithLabelValues(name) +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/predicate/doc.go b/vendor/sigs.k8s.io/controller-runtime/pkg/predicate/doc.go new file mode 100644 index 0000000000..e498107ef7 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/predicate/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* +Package predicate defines Predicates used by Controllers to filter Events before they are provided to EventHandlers. +*/ +package predicate diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/predicate/predicate.go b/vendor/sigs.k8s.io/controller-runtime/pkg/predicate/predicate.go new file mode 100644 index 0000000000..e79c03072a --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/predicate/predicate.go @@ -0,0 +1,353 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package predicate + +import ( + "reflect" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/event" + logf "sigs.k8s.io/controller-runtime/pkg/internal/log" + "sigs.k8s.io/controller-runtime/pkg/runtime/inject" +) + +var log = logf.RuntimeLog.WithName("predicate").WithName("eventFilters") + +// Predicate filters events before enqueuing the keys. +type Predicate interface { + // Create returns true if the Create event should be processed + Create(event.CreateEvent) bool + + // Delete returns true if the Delete event should be processed + Delete(event.DeleteEvent) bool + + // Update returns true if the Update event should be processed + Update(event.UpdateEvent) bool + + // Generic returns true if the Generic event should be processed + Generic(event.GenericEvent) bool +} + +var _ Predicate = Funcs{} +var _ Predicate = ResourceVersionChangedPredicate{} +var _ Predicate = GenerationChangedPredicate{} +var _ Predicate = AnnotationChangedPredicate{} +var _ Predicate = or{} +var _ Predicate = and{} + +// Funcs is a function that implements Predicate. +type Funcs struct { + // Create returns true if the Create event should be processed + CreateFunc func(event.CreateEvent) bool + + // Delete returns true if the Delete event should be processed + DeleteFunc func(event.DeleteEvent) bool + + // Update returns true if the Update event should be processed + UpdateFunc func(event.UpdateEvent) bool + + // Generic returns true if the Generic event should be processed + GenericFunc func(event.GenericEvent) bool +} + +// Create implements Predicate. +func (p Funcs) Create(e event.CreateEvent) bool { + if p.CreateFunc != nil { + return p.CreateFunc(e) + } + return true +} + +// Delete implements Predicate. +func (p Funcs) Delete(e event.DeleteEvent) bool { + if p.DeleteFunc != nil { + return p.DeleteFunc(e) + } + return true +} + +// Update implements Predicate. +func (p Funcs) Update(e event.UpdateEvent) bool { + if p.UpdateFunc != nil { + return p.UpdateFunc(e) + } + return true +} + +// Generic implements Predicate. +func (p Funcs) Generic(e event.GenericEvent) bool { + if p.GenericFunc != nil { + return p.GenericFunc(e) + } + return true +} + +// NewPredicateFuncs returns a predicate funcs that applies the given filter function +// on CREATE, UPDATE, DELETE and GENERIC events. For UPDATE events, the filter is applied +// to the new object. +func NewPredicateFuncs(filter func(object client.Object) bool) Funcs { + return Funcs{ + CreateFunc: func(e event.CreateEvent) bool { + return filter(e.Object) + }, + UpdateFunc: func(e event.UpdateEvent) bool { + return filter(e.ObjectNew) + }, + DeleteFunc: func(e event.DeleteEvent) bool { + return filter(e.Object) + }, + GenericFunc: func(e event.GenericEvent) bool { + return filter(e.Object) + }, + } +} + +// ResourceVersionChangedPredicate implements a default update predicate function on resource version change. +type ResourceVersionChangedPredicate struct { + Funcs +} + +// Update implements default UpdateEvent filter for validating resource version change. +func (ResourceVersionChangedPredicate) Update(e event.UpdateEvent) bool { + if e.ObjectOld == nil { + log.Error(nil, "Update event has no old object to update", "event", e) + return false + } + if e.ObjectNew == nil { + log.Error(nil, "Update event has no new object to update", "event", e) + return false + } + + return e.ObjectNew.GetResourceVersion() != e.ObjectOld.GetResourceVersion() +} + +// GenerationChangedPredicate implements a default update predicate function on Generation change. +// +// This predicate will skip update events that have no change in the object's metadata.generation field. +// The metadata.generation field of an object is incremented by the API server when writes are made to the spec field of an object. +// This allows a controller to ignore update events where the spec is unchanged, and only the metadata and/or status fields are changed. +// +// For CustomResource objects the Generation is only incremented when the status subresource is enabled. +// +// Caveats: +// +// * The assumption that the Generation is incremented only on writing to the spec does not hold for all APIs. +// E.g For Deployment objects the Generation is also incremented on writes to the metadata.annotations field. +// For object types other than CustomResources be sure to verify which fields will trigger a Generation increment when they are written to. +// +// * With this predicate, any update events with writes only to the status field will not be reconciled. +// So in the event that the status block is overwritten or wiped by someone else the controller will not self-correct to restore the correct status. +type GenerationChangedPredicate struct { + Funcs +} + +// Update implements default UpdateEvent filter for validating generation change. +func (GenerationChangedPredicate) Update(e event.UpdateEvent) bool { + if e.ObjectOld == nil { + log.Error(nil, "Update event has no old object to update", "event", e) + return false + } + if e.ObjectNew == nil { + log.Error(nil, "Update event has no new object for update", "event", e) + return false + } + + return e.ObjectNew.GetGeneration() != e.ObjectOld.GetGeneration() +} + +// AnnotationChangedPredicate implements a default update predicate function on annotation change. +// +// This predicate will skip update events that have no change in the object's annotation. +// It is intended to be used in conjunction with the GenerationChangedPredicate, as in the following example: +// +// Controller.Watch( +// &source.Kind{Type: v1.MyCustomKind}, +// &handler.EnqueueRequestForObject{}, +// predicate.Or(predicate.GenerationChangedPredicate{}, predicate.AnnotationChangedPredicate{})) +// +// This is mostly useful for controllers that needs to trigger both when the resource's generation is incremented +// (i.e., when the resource' .spec changes), or an annotation changes (e.g., for a staging/alpha API). +type AnnotationChangedPredicate struct { + Funcs +} + +// Update implements default UpdateEvent filter for validating annotation change. +func (AnnotationChangedPredicate) Update(e event.UpdateEvent) bool { + if e.ObjectOld == nil { + log.Error(nil, "Update event has no old object to update", "event", e) + return false + } + if e.ObjectNew == nil { + log.Error(nil, "Update event has no new object for update", "event", e) + return false + } + + return !reflect.DeepEqual(e.ObjectNew.GetAnnotations(), e.ObjectOld.GetAnnotations()) +} + +// LabelChangedPredicate implements a default update predicate function on label change. +// +// This predicate will skip update events that have no change in the object's label. +// It is intended to be used in conjunction with the GenerationChangedPredicate, as in the following example: +// +// Controller.Watch( +// +// &source.Kind{Type: v1.MyCustomKind}, +// &handler.EnqueueRequestForObject{}, +// predicate.Or(predicate.GenerationChangedPredicate{}, predicate.LabelChangedPredicate{})) +// +// This will be helpful when object's labels is carrying some extra specification information beyond object's spec, +// and the controller will be triggered if any valid spec change (not only in spec, but also in labels) happens. +type LabelChangedPredicate struct { + Funcs +} + +// Update implements default UpdateEvent filter for checking label change. +func (LabelChangedPredicate) Update(e event.UpdateEvent) bool { + if e.ObjectOld == nil { + log.Error(nil, "Update event has no old object to update", "event", e) + return false + } + if e.ObjectNew == nil { + log.Error(nil, "Update event has no new object for update", "event", e) + return false + } + + return !reflect.DeepEqual(e.ObjectNew.GetLabels(), e.ObjectOld.GetLabels()) +} + +// And returns a composite predicate that implements a logical AND of the predicates passed to it. +func And(predicates ...Predicate) Predicate { + return and{predicates} +} + +type and struct { + predicates []Predicate +} + +func (a and) InjectFunc(f inject.Func) error { + for _, p := range a.predicates { + if err := f(p); err != nil { + return err + } + } + return nil +} + +func (a and) Create(e event.CreateEvent) bool { + for _, p := range a.predicates { + if !p.Create(e) { + return false + } + } + return true +} + +func (a and) Update(e event.UpdateEvent) bool { + for _, p := range a.predicates { + if !p.Update(e) { + return false + } + } + return true +} + +func (a and) Delete(e event.DeleteEvent) bool { + for _, p := range a.predicates { + if !p.Delete(e) { + return false + } + } + return true +} + +func (a and) Generic(e event.GenericEvent) bool { + for _, p := range a.predicates { + if !p.Generic(e) { + return false + } + } + return true +} + +// Or returns a composite predicate that implements a logical OR of the predicates passed to it. +func Or(predicates ...Predicate) Predicate { + return or{predicates} +} + +type or struct { + predicates []Predicate +} + +func (o or) InjectFunc(f inject.Func) error { + for _, p := range o.predicates { + if err := f(p); err != nil { + return err + } + } + return nil +} + +func (o or) Create(e event.CreateEvent) bool { + for _, p := range o.predicates { + if p.Create(e) { + return true + } + } + return false +} + +func (o or) Update(e event.UpdateEvent) bool { + for _, p := range o.predicates { + if p.Update(e) { + return true + } + } + return false +} + +func (o or) Delete(e event.DeleteEvent) bool { + for _, p := range o.predicates { + if p.Delete(e) { + return true + } + } + return false +} + +func (o or) Generic(e event.GenericEvent) bool { + for _, p := range o.predicates { + if p.Generic(e) { + return true + } + } + return false +} + +// LabelSelectorPredicate constructs a Predicate from a LabelSelector. +// Only objects matching the LabelSelector will be admitted. +func LabelSelectorPredicate(s metav1.LabelSelector) (Predicate, error) { + selector, err := metav1.LabelSelectorAsSelector(&s) + if err != nil { + return Funcs{}, err + } + return NewPredicateFuncs(func(o client.Object) bool { + return selector.Matches(labels.Set(o.GetLabels())) + }), nil +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/ratelimiter/doc.go b/vendor/sigs.k8s.io/controller-runtime/pkg/ratelimiter/doc.go new file mode 100644 index 0000000000..a01d603fe5 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/ratelimiter/doc.go @@ -0,0 +1,22 @@ +/* +Copyright 2020 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* +Package ratelimiter defines rate limiters used by Controllers to limit how frequently requests may be queued. + +Typical rate limiters that can be used are implemented in client-go's workqueue package. +*/ +package ratelimiter diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/ratelimiter/ratelimiter.go b/vendor/sigs.k8s.io/controller-runtime/pkg/ratelimiter/ratelimiter.go new file mode 100644 index 0000000000..565a3a227f --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/ratelimiter/ratelimiter.go @@ -0,0 +1,30 @@ +/* +Copyright 2020 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package ratelimiter + +import "time" + +// RateLimiter is an identical interface of client-go workqueue RateLimiter. +type RateLimiter interface { + // When gets an item and gets to decide how long that item should wait + When(item interface{}) time.Duration + // Forget indicates that an item is finished being retried. Doesn't matter whether its for perm failing + // or for success, we'll stop tracking it + Forget(item interface{}) + // NumRequeues returns back how many failures the item has had + NumRequeues(item interface{}) int +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/reconcile/doc.go b/vendor/sigs.k8s.io/controller-runtime/pkg/reconcile/doc.go new file mode 100644 index 0000000000..d221dd7b3f --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/reconcile/doc.go @@ -0,0 +1,21 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* +Package reconcile defines the Reconciler interface to implement Kubernetes APIs. Reconciler is provided +to Controllers at creation time as the API implementation. +*/ +package reconcile diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/reconcile/reconcile.go b/vendor/sigs.k8s.io/controller-runtime/pkg/reconcile/reconcile.go new file mode 100644 index 0000000000..8285e2ca9b --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/reconcile/reconcile.go @@ -0,0 +1,102 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package reconcile + +import ( + "context" + "time" + + "k8s.io/apimachinery/pkg/types" +) + +// Result contains the result of a Reconciler invocation. +type Result struct { + // Requeue tells the Controller to requeue the reconcile key. Defaults to false. + Requeue bool + + // RequeueAfter if greater than 0, tells the Controller to requeue the reconcile key after the Duration. + // Implies that Requeue is true, there is no need to set Requeue to true at the same time as RequeueAfter. + RequeueAfter time.Duration +} + +// IsZero returns true if this result is empty. +func (r *Result) IsZero() bool { + if r == nil { + return true + } + return *r == Result{} +} + +// Request contains the information necessary to reconcile a Kubernetes object. This includes the +// information to uniquely identify the object - its Name and Namespace. It does NOT contain information about +// any specific Event or the object contents itself. +type Request struct { + // NamespacedName is the name and namespace of the object to reconcile. + types.NamespacedName +} + +/* +Reconciler implements a Kubernetes API for a specific Resource by Creating, Updating or Deleting Kubernetes +objects, or by making changes to systems external to the cluster (e.g. cloudproviders, github, etc). + +reconcile implementations compare the state specified in an object by a user against the actual cluster state, +and then perform operations to make the actual cluster state reflect the state specified by the user. + +Typically, reconcile is triggered by a Controller in response to cluster Events (e.g. Creating, Updating, +Deleting Kubernetes objects) or external Events (GitHub Webhooks, polling external sources, etc). + +Example reconcile Logic: + +* Read an object and all the Pods it owns. +* Observe that the object spec specifies 5 replicas but actual cluster contains only 1 Pod replica. +* Create 4 Pods and set their OwnerReferences to the object. + +reconcile may be implemented as either a type: + + type reconciler struct {} + + func (reconciler) Reconcile(ctx context.Context, o reconcile.Request) (reconcile.Result, error) { + // Implement business logic of reading and writing objects here + return reconcile.Result{}, nil + } + +Or as a function: + + reconcile.Func(func(ctx context.Context, o reconcile.Request) (reconcile.Result, error) { + // Implement business logic of reading and writing objects here + return reconcile.Result{}, nil + }) + +Reconciliation is level-based, meaning action isn't driven off changes in individual Events, but instead is +driven by actual cluster state read from the apiserver or a local cache. +For example if responding to a Pod Delete Event, the Request won't contain that a Pod was deleted, +instead the reconcile function observes this when reading the cluster state and seeing the Pod as missing. +*/ +type Reconciler interface { + // Reconcile performs a full reconciliation for the object referred to by the Request. + // The Controller will requeue the Request to be processed again if an error is non-nil or + // Result.Requeue is true, otherwise upon completion it will remove the work from the queue. + Reconcile(context.Context, Request) (Result, error) +} + +// Func is a function that implements the reconcile interface. +type Func func(context.Context, Request) (Result, error) + +var _ Reconciler = Func(nil) + +// Reconcile implements Reconciler. +func (r Func) Reconcile(ctx context.Context, o Request) (Result, error) { return r(ctx, o) } diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/recorder/recorder.go b/vendor/sigs.k8s.io/controller-runtime/pkg/recorder/recorder.go new file mode 100644 index 0000000000..f093f0a726 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/recorder/recorder.go @@ -0,0 +1,31 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package recorder defines interfaces for working with Kubernetes event recorders. +// +// You can use these to emit Kubernetes events associated with a particular Kubernetes +// object. +package recorder + +import ( + "k8s.io/client-go/tools/record" +) + +// Provider knows how to generate new event recorders with given name. +type Provider interface { + // NewRecorder returns an EventRecorder with given name. + GetEventRecorderFor(name string) record.EventRecorder +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/runtime/inject/doc.go b/vendor/sigs.k8s.io/controller-runtime/pkg/runtime/inject/doc.go new file mode 100644 index 0000000000..17c60895f0 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/runtime/inject/doc.go @@ -0,0 +1,22 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* +Package inject defines interfaces and functions for propagating dependencies from a ControllerManager to +the components registered with it. Dependencies are propagated to Reconciler, Source, EventHandler and Predicate +objects which implement the Injectable interfaces. +*/ +package inject diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/runtime/inject/inject.go b/vendor/sigs.k8s.io/controller-runtime/pkg/runtime/inject/inject.go new file mode 100644 index 0000000000..c8c56ba817 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/runtime/inject/inject.go @@ -0,0 +1,164 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package inject is used by a Manager to inject types into Sources, EventHandlers, Predicates, and Reconciles. +// Deprecated: Use manager.Options fields directly. This package will be removed in v0.10. +package inject + +import ( + "github.com/go-logr/logr" + "k8s.io/apimachinery/pkg/api/meta" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/rest" + + "sigs.k8s.io/controller-runtime/pkg/cache" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +// Cache is used by the ControllerManager to inject Cache into Sources, EventHandlers, Predicates, and +// Reconciles. +type Cache interface { + InjectCache(cache cache.Cache) error +} + +// CacheInto will set informers on i and return the result if it implements Cache. Returns +// false if i does not implement Cache. +func CacheInto(c cache.Cache, i interface{}) (bool, error) { + if s, ok := i.(Cache); ok { + return true, s.InjectCache(c) + } + return false, nil +} + +// APIReader is used by the Manager to inject the APIReader into necessary types. +type APIReader interface { + InjectAPIReader(client.Reader) error +} + +// APIReaderInto will set APIReader on i and return the result if it implements APIReaderInto. +// Returns false if i does not implement APIReader. +func APIReaderInto(reader client.Reader, i interface{}) (bool, error) { + if s, ok := i.(APIReader); ok { + return true, s.InjectAPIReader(reader) + } + return false, nil +} + +// Config is used by the ControllerManager to inject Config into Sources, EventHandlers, Predicates, and +// Reconciles. +type Config interface { + InjectConfig(*rest.Config) error +} + +// ConfigInto will set config on i and return the result if it implements Config. Returns +// false if i does not implement Config. +func ConfigInto(config *rest.Config, i interface{}) (bool, error) { + if s, ok := i.(Config); ok { + return true, s.InjectConfig(config) + } + return false, nil +} + +// Client is used by the ControllerManager to inject client into Sources, EventHandlers, Predicates, and +// Reconciles. +type Client interface { + InjectClient(client.Client) error +} + +// ClientInto will set client on i and return the result if it implements Client. Returns +// false if i does not implement Client. +func ClientInto(client client.Client, i interface{}) (bool, error) { + if s, ok := i.(Client); ok { + return true, s.InjectClient(client) + } + return false, nil +} + +// Scheme is used by the ControllerManager to inject Scheme into Sources, EventHandlers, Predicates, and +// Reconciles. +type Scheme interface { + InjectScheme(scheme *runtime.Scheme) error +} + +// SchemeInto will set scheme and return the result on i if it implements Scheme. Returns +// false if i does not implement Scheme. +func SchemeInto(scheme *runtime.Scheme, i interface{}) (bool, error) { + if is, ok := i.(Scheme); ok { + return true, is.InjectScheme(scheme) + } + return false, nil +} + +// Stoppable is used by the ControllerManager to inject stop channel into Sources, +// EventHandlers, Predicates, and Reconciles. +type Stoppable interface { + InjectStopChannel(<-chan struct{}) error +} + +// StopChannelInto will set stop channel on i and return the result if it implements Stoppable. +// Returns false if i does not implement Stoppable. +func StopChannelInto(stop <-chan struct{}, i interface{}) (bool, error) { + if s, ok := i.(Stoppable); ok { + return true, s.InjectStopChannel(stop) + } + return false, nil +} + +// Mapper is used to inject the rest mapper to components that may need it. +type Mapper interface { + InjectMapper(meta.RESTMapper) error +} + +// MapperInto will set the rest mapper on i and return the result if it implements Mapper. +// Returns false if i does not implement Mapper. +func MapperInto(mapper meta.RESTMapper, i interface{}) (bool, error) { + if m, ok := i.(Mapper); ok { + return true, m.InjectMapper(mapper) + } + return false, nil +} + +// Func injects dependencies into i. +type Func func(i interface{}) error + +// Injector is used by the ControllerManager to inject Func into Controllers. +type Injector interface { + InjectFunc(f Func) error +} + +// InjectorInto will set f and return the result on i if it implements Injector. Returns +// false if i does not implement Injector. +func InjectorInto(f Func, i interface{}) (bool, error) { + if ii, ok := i.(Injector); ok { + return true, ii.InjectFunc(f) + } + return false, nil +} + +// Logger is used to inject Loggers into components that need them +// and don't otherwise have opinions. +type Logger interface { + InjectLogger(l logr.Logger) error +} + +// LoggerInto will set the logger on the given object if it implements inject.Logger, +// returning true if a InjectLogger was called, and false otherwise. +func LoggerInto(l logr.Logger, i interface{}) (bool, error) { + if injectable, wantsLogger := i.(Logger); wantsLogger { + return true, injectable.InjectLogger(l) + } + return false, nil +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/scheme/scheme.go b/vendor/sigs.k8s.io/controller-runtime/pkg/scheme/scheme.go new file mode 100644 index 0000000000..55ebe21773 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/scheme/scheme.go @@ -0,0 +1,93 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package scheme contains utilities for gradually building Schemes, +// which contain information associating Go types with Kubernetes +// groups, versions, and kinds. +// +// Each API group should define a utility function +// called AddToScheme for adding its types to a Scheme: +// +// // in package myapigroupv1... +// var ( +// SchemeGroupVersion = schema.GroupVersion{Group: "my.api.group", Version: "v1"} +// SchemeBuilder = &scheme.Builder{GroupVersion: SchemeGroupVersion} +// AddToScheme = SchemeBuilder.AddToScheme +// ) +// +// func init() { +// SchemeBuilder.Register(&MyType{}, &MyTypeList) +// } +// var ( +// scheme *runtime.Scheme = runtime.NewScheme() +// ) +// +// This also true of the built-in Kubernetes types. Then, in the entrypoint for +// your manager, assemble the scheme containing exactly the types you need, +// panicing if scheme registration failed. For instance, if our controller needs +// types from the core/v1 API group (e.g. Pod), plus types from my.api.group/v1: +// +// func init() { +// utilruntime.Must(myapigroupv1.AddToScheme(scheme)) +// utilruntime.Must(kubernetesscheme.AddToScheme(scheme)) +// } +// +// func main() { +// mgr := controllers.NewManager(context.Background(), controllers.GetConfigOrDie(), manager.Options{ +// Scheme: scheme, +// }) +// // ... +// } +package scheme + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +// Builder builds a new Scheme for mapping go types to Kubernetes GroupVersionKinds. +type Builder struct { + GroupVersion schema.GroupVersion + runtime.SchemeBuilder +} + +// Register adds one or more objects to the SchemeBuilder so they can be added to a Scheme. Register mutates bld. +func (bld *Builder) Register(object ...runtime.Object) *Builder { + bld.SchemeBuilder.Register(func(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(bld.GroupVersion, object...) + metav1.AddToGroupVersion(scheme, bld.GroupVersion) + return nil + }) + return bld +} + +// RegisterAll registers all types from the Builder argument. RegisterAll mutates bld. +func (bld *Builder) RegisterAll(b *Builder) *Builder { + bld.SchemeBuilder = append(bld.SchemeBuilder, b.SchemeBuilder...) + return bld +} + +// AddToScheme adds all registered types to s. +func (bld *Builder) AddToScheme(s *runtime.Scheme) error { + return bld.SchemeBuilder.AddToScheme(s) +} + +// Build returns a new Scheme containing the registered types. +func (bld *Builder) Build() (*runtime.Scheme, error) { + s := runtime.NewScheme() + return s, bld.AddToScheme(s) +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/source/doc.go b/vendor/sigs.k8s.io/controller-runtime/pkg/source/doc.go new file mode 100644 index 0000000000..31935c83c1 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/source/doc.go @@ -0,0 +1,22 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* +Package source provides event streams to hook up to Controllers with Controller.Watch. Events are +used with handler.EventHandlers to enqueue reconcile.Requests and trigger Reconciles for Kubernetes +objects. +*/ +package source diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/source/internal/eventsource.go b/vendor/sigs.k8s.io/controller-runtime/pkg/source/internal/eventsource.go new file mode 100644 index 0000000000..f0cfe212ed --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/source/internal/eventsource.go @@ -0,0 +1,138 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package internal + +import ( + "fmt" + + "k8s.io/client-go/tools/cache" + "k8s.io/client-go/util/workqueue" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/event" + "sigs.k8s.io/controller-runtime/pkg/handler" + logf "sigs.k8s.io/controller-runtime/pkg/internal/log" + + "sigs.k8s.io/controller-runtime/pkg/predicate" +) + +var log = logf.RuntimeLog.WithName("source").WithName("EventHandler") + +var _ cache.ResourceEventHandler = EventHandler{} + +// EventHandler adapts a handler.EventHandler interface to a cache.ResourceEventHandler interface. +type EventHandler struct { + EventHandler handler.EventHandler + Queue workqueue.RateLimitingInterface + Predicates []predicate.Predicate +} + +// OnAdd creates CreateEvent and calls Create on EventHandler. +func (e EventHandler) OnAdd(obj interface{}) { + c := event.CreateEvent{} + + // Pull Object out of the object + if o, ok := obj.(client.Object); ok { + c.Object = o + } else { + log.Error(nil, "OnAdd missing Object", + "object", obj, "type", fmt.Sprintf("%T", obj)) + return + } + + for _, p := range e.Predicates { + if !p.Create(c) { + return + } + } + + // Invoke create handler + e.EventHandler.Create(c, e.Queue) +} + +// OnUpdate creates UpdateEvent and calls Update on EventHandler. +func (e EventHandler) OnUpdate(oldObj, newObj interface{}) { + u := event.UpdateEvent{} + + if o, ok := oldObj.(client.Object); ok { + u.ObjectOld = o + } else { + log.Error(nil, "OnUpdate missing ObjectOld", + "object", oldObj, "type", fmt.Sprintf("%T", oldObj)) + return + } + + // Pull Object out of the object + if o, ok := newObj.(client.Object); ok { + u.ObjectNew = o + } else { + log.Error(nil, "OnUpdate missing ObjectNew", + "object", newObj, "type", fmt.Sprintf("%T", newObj)) + return + } + + for _, p := range e.Predicates { + if !p.Update(u) { + return + } + } + + // Invoke update handler + e.EventHandler.Update(u, e.Queue) +} + +// OnDelete creates DeleteEvent and calls Delete on EventHandler. +func (e EventHandler) OnDelete(obj interface{}) { + d := event.DeleteEvent{} + + // Deal with tombstone events by pulling the object out. Tombstone events wrap the object in a + // DeleteFinalStateUnknown struct, so the object needs to be pulled out. + // Copied from sample-controller + // This should never happen if we aren't missing events, which we have concluded that we are not + // and made decisions off of this belief. Maybe this shouldn't be here? + var ok bool + if _, ok = obj.(client.Object); !ok { + // If the object doesn't have Metadata, assume it is a tombstone object of type DeletedFinalStateUnknown + tombstone, ok := obj.(cache.DeletedFinalStateUnknown) + if !ok { + log.Error(nil, "Error decoding objects. Expected cache.DeletedFinalStateUnknown", + "type", fmt.Sprintf("%T", obj), + "object", obj) + return + } + + // Set obj to the tombstone obj + obj = tombstone.Obj + } + + // Pull Object out of the object + if o, ok := obj.(client.Object); ok { + d.Object = o + } else { + log.Error(nil, "OnDelete missing Object", + "object", obj, "type", fmt.Sprintf("%T", obj)) + return + } + + for _, p := range e.Predicates { + if !p.Delete(d) { + return + } + } + + // Invoke delete handler + e.EventHandler.Delete(d, e.Queue) +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/source/source.go b/vendor/sigs.k8s.io/controller-runtime/pkg/source/source.go new file mode 100644 index 0000000000..241c582eff --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/source/source.go @@ -0,0 +1,375 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package source + +import ( + "context" + "errors" + "fmt" + "sync" + "time" + + "k8s.io/apimachinery/pkg/api/meta" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/client-go/util/workqueue" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/event" + "sigs.k8s.io/controller-runtime/pkg/handler" + logf "sigs.k8s.io/controller-runtime/pkg/internal/log" + "sigs.k8s.io/controller-runtime/pkg/runtime/inject" + "sigs.k8s.io/controller-runtime/pkg/source/internal" + + "sigs.k8s.io/controller-runtime/pkg/cache" + "sigs.k8s.io/controller-runtime/pkg/predicate" +) + +var log = logf.RuntimeLog.WithName("source") + +const ( + // defaultBufferSize is the default number of event notifications that can be buffered. + defaultBufferSize = 1024 +) + +// Source is a source of events (eh.g. Create, Update, Delete operations on Kubernetes Objects, Webhook callbacks, etc) +// which should be processed by event.EventHandlers to enqueue reconcile.Requests. +// +// * Use Kind for events originating in the cluster (e.g. Pod Create, Pod Update, Deployment Update). +// +// * Use Channel for events originating outside the cluster (eh.g. GitHub Webhook callback, Polling external urls). +// +// Users may build their own Source implementations. If their implementations implement any of the inject package +// interfaces, the dependencies will be injected by the Controller when Watch is called. +type Source interface { + // Start is internal and should be called only by the Controller to register an EventHandler with the Informer + // to enqueue reconcile.Requests. + Start(context.Context, handler.EventHandler, workqueue.RateLimitingInterface, ...predicate.Predicate) error +} + +// SyncingSource is a source that needs syncing prior to being usable. The controller +// will call its WaitForSync prior to starting workers. +type SyncingSource interface { + Source + WaitForSync(ctx context.Context) error +} + +// NewKindWithCache creates a Source without InjectCache, so that it is assured that the given cache is used +// and not overwritten. It can be used to watch objects in a different cluster by passing the cache +// from that other cluster. +func NewKindWithCache(object client.Object, cache cache.Cache) SyncingSource { + return &kindWithCache{kind: Kind{Type: object, cache: cache}} +} + +type kindWithCache struct { + kind Kind +} + +func (ks *kindWithCache) Start(ctx context.Context, handler handler.EventHandler, queue workqueue.RateLimitingInterface, + prct ...predicate.Predicate) error { + return ks.kind.Start(ctx, handler, queue, prct...) +} + +func (ks *kindWithCache) WaitForSync(ctx context.Context) error { + return ks.kind.WaitForSync(ctx) +} + +// Kind is used to provide a source of events originating inside the cluster from Watches (e.g. Pod Create). +type Kind struct { + // Type is the type of object to watch. e.g. &v1.Pod{} + Type client.Object + + // cache used to watch APIs + cache cache.Cache + + // started may contain an error if one was encountered during startup. If its closed and does not + // contain an error, startup and syncing finished. + started chan error + startCancel func() +} + +var _ SyncingSource = &Kind{} + +// Start is internal and should be called only by the Controller to register an EventHandler with the Informer +// to enqueue reconcile.Requests. +func (ks *Kind) Start(ctx context.Context, handler handler.EventHandler, queue workqueue.RateLimitingInterface, + prct ...predicate.Predicate) error { + // Type should have been specified by the user. + if ks.Type == nil { + return fmt.Errorf("must specify Kind.Type") + } + + // cache should have been injected before Start was called + if ks.cache == nil { + return fmt.Errorf("must call CacheInto on Kind before calling Start") + } + + // cache.GetInformer will block until its context is cancelled if the cache was already started and it can not + // sync that informer (most commonly due to RBAC issues). + ctx, ks.startCancel = context.WithCancel(ctx) + ks.started = make(chan error) + go func() { + var ( + i cache.Informer + lastErr error + ) + + // Tries to get an informer until it returns true, + // an error or the specified context is cancelled or expired. + if err := wait.PollImmediateUntilWithContext(ctx, 10*time.Second, func(ctx context.Context) (bool, error) { + // Lookup the Informer from the Cache and add an EventHandler which populates the Queue + i, lastErr = ks.cache.GetInformer(ctx, ks.Type) + if lastErr != nil { + kindMatchErr := &meta.NoKindMatchError{} + switch { + case errors.As(lastErr, &kindMatchErr): + log.Error(lastErr, "if kind is a CRD, it should be installed before calling Start", + "kind", kindMatchErr.GroupKind) + case runtime.IsNotRegisteredError(lastErr): + log.Error(lastErr, "kind must be registered to the Scheme") + default: + log.Error(lastErr, "failed to get informer from cache") + } + return false, nil // Retry. + } + return true, nil + }); err != nil { + if lastErr != nil { + ks.started <- fmt.Errorf("failed to get informer from cache: %w", lastErr) + return + } + ks.started <- err + return + } + + i.AddEventHandler(internal.EventHandler{Queue: queue, EventHandler: handler, Predicates: prct}) + if !ks.cache.WaitForCacheSync(ctx) { + // Would be great to return something more informative here + ks.started <- errors.New("cache did not sync") + } + close(ks.started) + }() + + return nil +} + +func (ks *Kind) String() string { + if ks.Type != nil { + return fmt.Sprintf("kind source: %T", ks.Type) + } + return "kind source: unknown type" +} + +// WaitForSync implements SyncingSource to allow controllers to wait with starting +// workers until the cache is synced. +func (ks *Kind) WaitForSync(ctx context.Context) error { + select { + case err := <-ks.started: + return err + case <-ctx.Done(): + ks.startCancel() + if errors.Is(ctx.Err(), context.Canceled) { + return nil + } + return errors.New("timed out waiting for cache to be synced") + } +} + +var _ inject.Cache = &Kind{} + +// InjectCache is internal should be called only by the Controller. InjectCache is used to inject +// the Cache dependency initialized by the ControllerManager. +func (ks *Kind) InjectCache(c cache.Cache) error { + if ks.cache == nil { + ks.cache = c + } + return nil +} + +var _ Source = &Channel{} + +// Channel is used to provide a source of events originating outside the cluster +// (e.g. GitHub Webhook callback). Channel requires the user to wire the external +// source (eh.g. http handler) to write GenericEvents to the underlying channel. +type Channel struct { + // once ensures the event distribution goroutine will be performed only once + once sync.Once + + // Source is the source channel to fetch GenericEvents + Source <-chan event.GenericEvent + + // stop is to end ongoing goroutine, and close the channels + stop <-chan struct{} + + // dest is the destination channels of the added event handlers + dest []chan event.GenericEvent + + // DestBufferSize is the specified buffer size of dest channels. + // Default to 1024 if not specified. + DestBufferSize int + + // destLock is to ensure the destination channels are safely added/removed + destLock sync.Mutex +} + +func (cs *Channel) String() string { + return fmt.Sprintf("channel source: %p", cs) +} + +var _ inject.Stoppable = &Channel{} + +// InjectStopChannel is internal should be called only by the Controller. +// It is used to inject the stop channel initialized by the ControllerManager. +func (cs *Channel) InjectStopChannel(stop <-chan struct{}) error { + if cs.stop == nil { + cs.stop = stop + } + + return nil +} + +// Start implements Source and should only be called by the Controller. +func (cs *Channel) Start( + ctx context.Context, + handler handler.EventHandler, + queue workqueue.RateLimitingInterface, + prct ...predicate.Predicate) error { + // Source should have been specified by the user. + if cs.Source == nil { + return fmt.Errorf("must specify Channel.Source") + } + + // stop should have been injected before Start was called + if cs.stop == nil { + return fmt.Errorf("must call InjectStop on Channel before calling Start") + } + + // use default value if DestBufferSize not specified + if cs.DestBufferSize == 0 { + cs.DestBufferSize = defaultBufferSize + } + + dst := make(chan event.GenericEvent, cs.DestBufferSize) + + cs.destLock.Lock() + cs.dest = append(cs.dest, dst) + cs.destLock.Unlock() + + cs.once.Do(func() { + // Distribute GenericEvents to all EventHandler / Queue pairs Watching this source + go cs.syncLoop(ctx) + }) + + go func() { + for evt := range dst { + shouldHandle := true + for _, p := range prct { + if !p.Generic(evt) { + shouldHandle = false + break + } + } + + if shouldHandle { + handler.Generic(evt, queue) + } + } + }() + + return nil +} + +func (cs *Channel) doStop() { + cs.destLock.Lock() + defer cs.destLock.Unlock() + + for _, dst := range cs.dest { + close(dst) + } +} + +func (cs *Channel) distribute(evt event.GenericEvent) { + cs.destLock.Lock() + defer cs.destLock.Unlock() + + for _, dst := range cs.dest { + // We cannot make it under goroutine here, or we'll meet the + // race condition of writing message to closed channels. + // To avoid blocking, the dest channels are expected to be of + // proper buffer size. If we still see it blocked, then + // the controller is thought to be in an abnormal state. + dst <- evt + } +} + +func (cs *Channel) syncLoop(ctx context.Context) { + for { + select { + case <-ctx.Done(): + // Close destination channels + cs.doStop() + return + case evt, stillOpen := <-cs.Source: + if !stillOpen { + // if the source channel is closed, we're never gonna get + // anything more on it, so stop & bail + cs.doStop() + return + } + cs.distribute(evt) + } + } +} + +// Informer is used to provide a source of events originating inside the cluster from Watches (e.g. Pod Create). +type Informer struct { + // Informer is the controller-runtime Informer + Informer cache.Informer +} + +var _ Source = &Informer{} + +// Start is internal and should be called only by the Controller to register an EventHandler with the Informer +// to enqueue reconcile.Requests. +func (is *Informer) Start(ctx context.Context, handler handler.EventHandler, queue workqueue.RateLimitingInterface, + prct ...predicate.Predicate) error { + // Informer should have been specified by the user. + if is.Informer == nil { + return fmt.Errorf("must specify Informer.Informer") + } + + is.Informer.AddEventHandler(internal.EventHandler{Queue: queue, EventHandler: handler, Predicates: prct}) + return nil +} + +func (is *Informer) String() string { + return fmt.Sprintf("informer source: %p", is.Informer) +} + +var _ Source = Func(nil) + +// Func is a function that implements Source. +type Func func(context.Context, handler.EventHandler, workqueue.RateLimitingInterface, ...predicate.Predicate) error + +// Start implements Source. +func (f Func) Start(ctx context.Context, evt handler.EventHandler, queue workqueue.RateLimitingInterface, + pr ...predicate.Predicate) error { + return f(ctx, evt, queue, pr...) +} + +func (f Func) String() string { + return fmt.Sprintf("func source: %p", f) +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/decode.go b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/decode.go new file mode 100644 index 0000000000..c7cb71b755 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/decode.go @@ -0,0 +1,72 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package admission + +import ( + "fmt" + + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/serializer" + "k8s.io/apimachinery/pkg/util/json" +) + +// Decoder knows how to decode the contents of an admission +// request into a concrete object. +type Decoder struct { + codecs serializer.CodecFactory +} + +// NewDecoder creates a Decoder given the runtime.Scheme. +func NewDecoder(scheme *runtime.Scheme) (*Decoder, error) { + return &Decoder{codecs: serializer.NewCodecFactory(scheme)}, nil +} + +// Decode decodes the inlined object in the AdmissionRequest into the passed-in runtime.Object. +// If you want decode the OldObject in the AdmissionRequest, use DecodeRaw. +// It errors out if req.Object.Raw is empty i.e. containing 0 raw bytes. +func (d *Decoder) Decode(req Request, into runtime.Object) error { + // we error out if rawObj is an empty object. + if len(req.Object.Raw) == 0 { + return fmt.Errorf("there is no content to decode") + } + return d.DecodeRaw(req.Object, into) +} + +// DecodeRaw decodes a RawExtension object into the passed-in runtime.Object. +// It errors out if rawObj is empty i.e. containing 0 raw bytes. +func (d *Decoder) DecodeRaw(rawObj runtime.RawExtension, into runtime.Object) error { + // NB(directxman12): there's a bug/weird interaction between decoders and + // the API server where the API server doesn't send a GVK on the embedded + // objects, which means the unstructured decoder refuses to decode. It + // also means we can't pass the unstructured directly in, since it'll try + // and call unstructured's special Unmarshal implementation, which calls + // back into that same decoder :-/ + // See kubernetes/kubernetes#74373. + + // we error out if rawObj is an empty object. + if len(rawObj.Raw) == 0 { + return fmt.Errorf("there is no content to decode") + } + if unstructuredInto, isUnstructured := into.(*unstructured.Unstructured); isUnstructured { + // unmarshal into unstructured's underlying object to avoid calling the decoder + return json.Unmarshal(rawObj.Raw, &unstructuredInto.Object) + } + + deserializer := d.codecs.UniversalDeserializer() + return runtime.DecodeInto(deserializer, rawObj.Raw, into) +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/defaulter.go b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/defaulter.go new file mode 100644 index 0000000000..e4e0778f57 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/defaulter.go @@ -0,0 +1,87 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package admission + +import ( + "context" + "encoding/json" + "net/http" + + admissionv1 "k8s.io/api/admission/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" +) + +// Defaulter defines functions for setting defaults on resources. +type Defaulter interface { + runtime.Object + Default() +} + +// DefaultingWebhookFor creates a new Webhook for Defaulting the provided type. +func DefaultingWebhookFor(defaulter Defaulter) *Webhook { + return &Webhook{ + Handler: &mutatingHandler{defaulter: defaulter}, + } +} + +type mutatingHandler struct { + defaulter Defaulter + decoder *Decoder +} + +var _ DecoderInjector = &mutatingHandler{} + +// InjectDecoder injects the decoder into a mutatingHandler. +func (h *mutatingHandler) InjectDecoder(d *Decoder) error { + h.decoder = d + return nil +} + +// Handle handles admission requests. +func (h *mutatingHandler) Handle(ctx context.Context, req Request) Response { + if h.defaulter == nil { + panic("defaulter should never be nil") + } + + // always skip when a DELETE operation received in mutation handler + // describe in https://github.com/kubernetes-sigs/controller-runtime/issues/1762 + if req.Operation == admissionv1.Delete { + return Response{AdmissionResponse: admissionv1.AdmissionResponse{ + Allowed: true, + Result: &metav1.Status{ + Code: http.StatusOK, + }, + }} + } + + // Get the object in the request + obj := h.defaulter.DeepCopyObject().(Defaulter) + if err := h.decoder.Decode(req, obj); err != nil { + return Errored(http.StatusBadRequest, err) + } + + // Default the object + obj.Default() + marshalled, err := json.Marshal(obj) + if err != nil { + return Errored(http.StatusInternalServerError, err) + } + + // Create the patch + return PatchResponseFromRaw(req.Object.Raw, marshalled) +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/defaulter_custom.go b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/defaulter_custom.go new file mode 100644 index 0000000000..d65727e62c --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/defaulter_custom.go @@ -0,0 +1,86 @@ +/* +Copyright 2021 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package admission + +import ( + "context" + "encoding/json" + "errors" + "net/http" + + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/runtime" +) + +// CustomDefaulter defines functions for setting defaults on resources. +type CustomDefaulter interface { + Default(ctx context.Context, obj runtime.Object) error +} + +// WithCustomDefaulter creates a new Webhook for a CustomDefaulter interface. +func WithCustomDefaulter(obj runtime.Object, defaulter CustomDefaulter) *Webhook { + return &Webhook{ + Handler: &defaulterForType{object: obj, defaulter: defaulter}, + } +} + +type defaulterForType struct { + defaulter CustomDefaulter + object runtime.Object + decoder *Decoder +} + +var _ DecoderInjector = &defaulterForType{} + +func (h *defaulterForType) InjectDecoder(d *Decoder) error { + h.decoder = d + return nil +} + +// Handle handles admission requests. +func (h *defaulterForType) Handle(ctx context.Context, req Request) Response { + if h.defaulter == nil { + panic("defaulter should never be nil") + } + if h.object == nil { + panic("object should never be nil") + } + + ctx = NewContextWithRequest(ctx, req) + + // Get the object in the request + obj := h.object.DeepCopyObject() + if err := h.decoder.Decode(req, obj); err != nil { + return Errored(http.StatusBadRequest, err) + } + + // Default the object + if err := h.defaulter.Default(ctx, obj); err != nil { + var apiStatus apierrors.APIStatus + if errors.As(err, &apiStatus) { + return validationResponseFromStatus(false, apiStatus.Status()) + } + return Denied(err.Error()) + } + + // Create the patch + marshalled, err := json.Marshal(obj) + if err != nil { + return Errored(http.StatusInternalServerError, err) + } + return PatchResponseFromRaw(req.Object.Raw, marshalled) +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/doc.go b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/doc.go new file mode 100644 index 0000000000..0b274dd02b --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/doc.go @@ -0,0 +1,28 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* +Package admission provides implementation for admission webhook and methods to implement admission webhook handlers. + +See examples/mutatingwebhook.go and examples/validatingwebhook.go for examples of admission webhooks. +*/ +package admission + +import ( + logf "sigs.k8s.io/controller-runtime/pkg/internal/log" +) + +var log = logf.RuntimeLog.WithName("admission") diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/http.go b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/http.go new file mode 100644 index 0000000000..066cc42256 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/http.go @@ -0,0 +1,153 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package admission + +import ( + "encoding/json" + "errors" + "fmt" + "io" + "net/http" + + v1 "k8s.io/api/admission/v1" + "k8s.io/api/admission/v1beta1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/runtime/serializer" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" +) + +var admissionScheme = runtime.NewScheme() +var admissionCodecs = serializer.NewCodecFactory(admissionScheme) + +func init() { + utilruntime.Must(v1.AddToScheme(admissionScheme)) + utilruntime.Must(v1beta1.AddToScheme(admissionScheme)) +} + +var _ http.Handler = &Webhook{} + +func (wh *Webhook) ServeHTTP(w http.ResponseWriter, r *http.Request) { + var body []byte + var err error + ctx := r.Context() + if wh.WithContextFunc != nil { + ctx = wh.WithContextFunc(ctx, r) + } + + var reviewResponse Response + if r.Body == nil { + err = errors.New("request body is empty") + wh.log.Error(err, "bad request") + reviewResponse = Errored(http.StatusBadRequest, err) + wh.writeResponse(w, reviewResponse) + return + } + + defer r.Body.Close() + if body, err = io.ReadAll(r.Body); err != nil { + wh.log.Error(err, "unable to read the body from the incoming request") + reviewResponse = Errored(http.StatusBadRequest, err) + wh.writeResponse(w, reviewResponse) + return + } + + // verify the content type is accurate + if contentType := r.Header.Get("Content-Type"); contentType != "application/json" { + err = fmt.Errorf("contentType=%s, expected application/json", contentType) + wh.log.Error(err, "unable to process a request with an unknown content type", "content type", contentType) + reviewResponse = Errored(http.StatusBadRequest, err) + wh.writeResponse(w, reviewResponse) + return + } + + // Both v1 and v1beta1 AdmissionReview types are exactly the same, so the v1beta1 type can + // be decoded into the v1 type. However the runtime codec's decoder guesses which type to + // decode into by type name if an Object's TypeMeta isn't set. By setting TypeMeta of an + // unregistered type to the v1 GVK, the decoder will coerce a v1beta1 AdmissionReview to v1. + // The actual AdmissionReview GVK will be used to write a typed response in case the + // webhook config permits multiple versions, otherwise this response will fail. + req := Request{} + ar := unversionedAdmissionReview{} + // avoid an extra copy + ar.Request = &req.AdmissionRequest + ar.SetGroupVersionKind(v1.SchemeGroupVersion.WithKind("AdmissionReview")) + _, actualAdmRevGVK, err := admissionCodecs.UniversalDeserializer().Decode(body, nil, &ar) + if err != nil { + wh.log.Error(err, "unable to decode the request") + reviewResponse = Errored(http.StatusBadRequest, err) + wh.writeResponse(w, reviewResponse) + return + } + wh.log.V(1).Info("received request", "UID", req.UID, "kind", req.Kind, "resource", req.Resource) + + reviewResponse = wh.Handle(ctx, req) + wh.writeResponseTyped(w, reviewResponse, actualAdmRevGVK) +} + +// writeResponse writes response to w generically, i.e. without encoding GVK information. +func (wh *Webhook) writeResponse(w io.Writer, response Response) { + wh.writeAdmissionResponse(w, v1.AdmissionReview{Response: &response.AdmissionResponse}) +} + +// writeResponseTyped writes response to w with GVK set to admRevGVK, which is necessary +// if multiple AdmissionReview versions are permitted by the webhook. +func (wh *Webhook) writeResponseTyped(w io.Writer, response Response, admRevGVK *schema.GroupVersionKind) { + ar := v1.AdmissionReview{ + Response: &response.AdmissionResponse, + } + // Default to a v1 AdmissionReview, otherwise the API server may not recognize the request + // if multiple AdmissionReview versions are permitted by the webhook config. + // TODO(estroz): this should be configurable since older API servers won't know about v1. + if admRevGVK == nil || *admRevGVK == (schema.GroupVersionKind{}) { + ar.SetGroupVersionKind(v1.SchemeGroupVersion.WithKind("AdmissionReview")) + } else { + ar.SetGroupVersionKind(*admRevGVK) + } + wh.writeAdmissionResponse(w, ar) +} + +// writeAdmissionResponse writes ar to w. +func (wh *Webhook) writeAdmissionResponse(w io.Writer, ar v1.AdmissionReview) { + if err := json.NewEncoder(w).Encode(ar); err != nil { + wh.log.Error(err, "unable to encode and write the response") + // Since the `ar v1.AdmissionReview` is a clear and legal object, + // it should not have problem to be marshalled into bytes. + // The error here is probably caused by the abnormal HTTP connection, + // e.g., broken pipe, so we can only write the error response once, + // to avoid endless circular calling. + serverError := Errored(http.StatusInternalServerError, err) + if err = json.NewEncoder(w).Encode(v1.AdmissionReview{Response: &serverError.AdmissionResponse}); err != nil { + wh.log.Error(err, "still unable to encode and write the InternalServerError response") + } + } else { + res := ar.Response + if log := wh.log; log.V(1).Enabled() { + if res.Result != nil { + log = log.WithValues("code", res.Result.Code, "reason", res.Result.Reason) + } + log.V(1).Info("wrote response", "UID", res.UID, "allowed", res.Allowed) + } + } +} + +// unversionedAdmissionReview is used to decode both v1 and v1beta1 AdmissionReview types. +type unversionedAdmissionReview struct { + v1.AdmissionReview +} + +var _ runtime.Object = &unversionedAdmissionReview{} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/inject.go b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/inject.go new file mode 100644 index 0000000000..d5af0d598f --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/inject.go @@ -0,0 +1,31 @@ +/* +Copyright 2019 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package admission + +// DecoderInjector is used by the ControllerManager to inject decoder into webhook handlers. +type DecoderInjector interface { + InjectDecoder(*Decoder) error +} + +// InjectDecoderInto will set decoder on i and return the result if it implements Decoder. Returns +// false if i does not implement Decoder. +func InjectDecoderInto(decoder *Decoder, i interface{}) (bool, error) { + if s, ok := i.(DecoderInjector); ok { + return true, s.InjectDecoder(decoder) + } + return false, nil +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/multi.go b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/multi.go new file mode 100644 index 0000000000..26900cf2eb --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/multi.go @@ -0,0 +1,147 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package admission + +import ( + "context" + "encoding/json" + "fmt" + "net/http" + + jsonpatch "gomodules.xyz/jsonpatch/v2" + admissionv1 "k8s.io/api/admission/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "sigs.k8s.io/controller-runtime/pkg/runtime/inject" +) + +type multiMutating []Handler + +func (hs multiMutating) Handle(ctx context.Context, req Request) Response { + patches := []jsonpatch.JsonPatchOperation{} + for _, handler := range hs { + resp := handler.Handle(ctx, req) + if !resp.Allowed { + return resp + } + if resp.PatchType != nil && *resp.PatchType != admissionv1.PatchTypeJSONPatch { + return Errored(http.StatusInternalServerError, + fmt.Errorf("unexpected patch type returned by the handler: %v, only allow: %v", + resp.PatchType, admissionv1.PatchTypeJSONPatch)) + } + patches = append(patches, resp.Patches...) + } + var err error + marshaledPatch, err := json.Marshal(patches) + if err != nil { + return Errored(http.StatusBadRequest, fmt.Errorf("error when marshaling the patch: %w", err)) + } + return Response{ + AdmissionResponse: admissionv1.AdmissionResponse{ + Allowed: true, + Result: &metav1.Status{ + Code: http.StatusOK, + }, + Patch: marshaledPatch, + PatchType: func() *admissionv1.PatchType { pt := admissionv1.PatchTypeJSONPatch; return &pt }(), + }, + } +} + +// InjectFunc injects the field setter into the handlers. +func (hs multiMutating) InjectFunc(f inject.Func) error { + // inject directly into the handlers. It would be more correct + // to do this in a sync.Once in Handle (since we don't have some + // other start/finalize-type method), but it's more efficient to + // do it here, presumably. + for _, handler := range hs { + if err := f(handler); err != nil { + return err + } + } + + return nil +} + +// InjectDecoder injects the decoder into the handlers. +func (hs multiMutating) InjectDecoder(d *Decoder) error { + for _, handler := range hs { + if _, err := InjectDecoderInto(d, handler); err != nil { + return err + } + } + return nil +} + +// MultiMutatingHandler combines multiple mutating webhook handlers into a single +// mutating webhook handler. Handlers are called in sequential order, and the first +// `allowed: false` response may short-circuit the rest. Users must take care to +// ensure patches are disjoint. +func MultiMutatingHandler(handlers ...Handler) Handler { + return multiMutating(handlers) +} + +type multiValidating []Handler + +func (hs multiValidating) Handle(ctx context.Context, req Request) Response { + for _, handler := range hs { + resp := handler.Handle(ctx, req) + if !resp.Allowed { + return resp + } + } + return Response{ + AdmissionResponse: admissionv1.AdmissionResponse{ + Allowed: true, + Result: &metav1.Status{ + Code: http.StatusOK, + }, + }, + } +} + +// MultiValidatingHandler combines multiple validating webhook handlers into a single +// validating webhook handler. Handlers are called in sequential order, and the first +// `allowed: false` response may short-circuit the rest. +func MultiValidatingHandler(handlers ...Handler) Handler { + return multiValidating(handlers) +} + +// InjectFunc injects the field setter into the handlers. +func (hs multiValidating) InjectFunc(f inject.Func) error { + // inject directly into the handlers. It would be more correct + // to do this in a sync.Once in Handle (since we don't have some + // other start/finalize-type method), but it's more efficient to + // do it here, presumably. + for _, handler := range hs { + if err := f(handler); err != nil { + return err + } + } + + return nil +} + +// InjectDecoder injects the decoder into the handlers. +func (hs multiValidating) InjectDecoder(d *Decoder) error { + for _, handler := range hs { + if _, err := InjectDecoderInto(d, handler); err != nil { + return err + } + } + return nil +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/response.go b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/response.go new file mode 100644 index 0000000000..24ff1dee3c --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/response.go @@ -0,0 +1,121 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package admission + +import ( + "net/http" + + jsonpatch "gomodules.xyz/jsonpatch/v2" + admissionv1 "k8s.io/api/admission/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// Allowed constructs a response indicating that the given operation +// is allowed (without any patches). +func Allowed(reason string) Response { + return ValidationResponse(true, reason) +} + +// Denied constructs a response indicating that the given operation +// is not allowed. +func Denied(reason string) Response { + return ValidationResponse(false, reason) +} + +// Patched constructs a response indicating that the given operation is +// allowed, and that the target object should be modified by the given +// JSONPatch operations. +func Patched(reason string, patches ...jsonpatch.JsonPatchOperation) Response { + resp := Allowed(reason) + resp.Patches = patches + + return resp +} + +// Errored creates a new Response for error-handling a request. +func Errored(code int32, err error) Response { + return Response{ + AdmissionResponse: admissionv1.AdmissionResponse{ + Allowed: false, + Result: &metav1.Status{ + Code: code, + Message: err.Error(), + }, + }, + } +} + +// ValidationResponse returns a response for admitting a request. +func ValidationResponse(allowed bool, reason string) Response { + code := http.StatusForbidden + if allowed { + code = http.StatusOK + } + resp := Response{ + AdmissionResponse: admissionv1.AdmissionResponse{ + Allowed: allowed, + Result: &metav1.Status{ + Code: int32(code), + }, + }, + } + if len(reason) > 0 { + resp.Result.Reason = metav1.StatusReason(reason) + } + return resp +} + +// PatchResponseFromRaw takes 2 byte arrays and returns a new response with json patch. +// The original object should be passed in as raw bytes to avoid the roundtripping problem +// described in https://github.com/kubernetes-sigs/kubebuilder/issues/510. +func PatchResponseFromRaw(original, current []byte) Response { + patches, err := jsonpatch.CreatePatch(original, current) + if err != nil { + return Errored(http.StatusInternalServerError, err) + } + return Response{ + Patches: patches, + AdmissionResponse: admissionv1.AdmissionResponse{ + Allowed: true, + PatchType: func() *admissionv1.PatchType { + if len(patches) == 0 { + return nil + } + pt := admissionv1.PatchTypeJSONPatch + return &pt + }(), + }, + } +} + +// validationResponseFromStatus returns a response for admitting a request with provided Status object. +func validationResponseFromStatus(allowed bool, status metav1.Status) Response { + resp := Response{ + AdmissionResponse: admissionv1.AdmissionResponse{ + Allowed: allowed, + Result: &status, + }, + } + return resp +} + +// WithWarnings adds the given warnings to the Response. +// If any warnings were already given, they will not be overwritten. +func (r Response) WithWarnings(warnings ...string) Response { + r.AdmissionResponse.Warnings = append(r.AdmissionResponse.Warnings, warnings...) + return r +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/validator.go b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/validator.go new file mode 100644 index 0000000000..4b27e75ede --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/validator.go @@ -0,0 +1,122 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package admission + +import ( + "context" + goerrors "errors" + "net/http" + + v1 "k8s.io/api/admission/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/runtime" +) + +// Validator defines functions for validating an operation. +type Validator interface { + runtime.Object + ValidateCreate() error + ValidateUpdate(old runtime.Object) error + ValidateDelete() error +} + +// ValidatingWebhookFor creates a new Webhook for validating the provided type. +func ValidatingWebhookFor(validator Validator) *Webhook { + return &Webhook{ + Handler: &validatingHandler{validator: validator}, + } +} + +type validatingHandler struct { + validator Validator + decoder *Decoder +} + +var _ DecoderInjector = &validatingHandler{} + +// InjectDecoder injects the decoder into a validatingHandler. +func (h *validatingHandler) InjectDecoder(d *Decoder) error { + h.decoder = d + return nil +} + +// Handle handles admission requests. +func (h *validatingHandler) Handle(ctx context.Context, req Request) Response { + if h.validator == nil { + panic("validator should never be nil") + } + + // Get the object in the request + obj := h.validator.DeepCopyObject().(Validator) + if req.Operation == v1.Create { + err := h.decoder.Decode(req, obj) + if err != nil { + return Errored(http.StatusBadRequest, err) + } + + err = obj.ValidateCreate() + if err != nil { + var apiStatus apierrors.APIStatus + if goerrors.As(err, &apiStatus) { + return validationResponseFromStatus(false, apiStatus.Status()) + } + return Denied(err.Error()) + } + } + + if req.Operation == v1.Update { + oldObj := obj.DeepCopyObject() + + err := h.decoder.DecodeRaw(req.Object, obj) + if err != nil { + return Errored(http.StatusBadRequest, err) + } + err = h.decoder.DecodeRaw(req.OldObject, oldObj) + if err != nil { + return Errored(http.StatusBadRequest, err) + } + + err = obj.ValidateUpdate(oldObj) + if err != nil { + var apiStatus apierrors.APIStatus + if goerrors.As(err, &apiStatus) { + return validationResponseFromStatus(false, apiStatus.Status()) + } + return Denied(err.Error()) + } + } + + if req.Operation == v1.Delete { + // In reference to PR: https://github.com/kubernetes/kubernetes/pull/76346 + // OldObject contains the object being deleted + err := h.decoder.DecodeRaw(req.OldObject, obj) + if err != nil { + return Errored(http.StatusBadRequest, err) + } + + err = obj.ValidateDelete() + if err != nil { + var apiStatus apierrors.APIStatus + if goerrors.As(err, &apiStatus) { + return validationResponseFromStatus(false, apiStatus.Status()) + } + return Denied(err.Error()) + } + } + + return Allowed("") +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/validator_custom.go b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/validator_custom.go new file mode 100644 index 0000000000..33252f1134 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/validator_custom.go @@ -0,0 +1,113 @@ +/* +Copyright 2021 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package admission + +import ( + "context" + "errors" + "fmt" + "net/http" + + v1 "k8s.io/api/admission/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/runtime" +) + +// CustomValidator defines functions for validating an operation. +type CustomValidator interface { + ValidateCreate(ctx context.Context, obj runtime.Object) error + ValidateUpdate(ctx context.Context, oldObj, newObj runtime.Object) error + ValidateDelete(ctx context.Context, obj runtime.Object) error +} + +// WithCustomValidator creates a new Webhook for validating the provided type. +func WithCustomValidator(obj runtime.Object, validator CustomValidator) *Webhook { + return &Webhook{ + Handler: &validatorForType{object: obj, validator: validator}, + } +} + +type validatorForType struct { + validator CustomValidator + object runtime.Object + decoder *Decoder +} + +var _ DecoderInjector = &validatorForType{} + +// InjectDecoder injects the decoder into a validatingHandler. +func (h *validatorForType) InjectDecoder(d *Decoder) error { + h.decoder = d + return nil +} + +// Handle handles admission requests. +func (h *validatorForType) Handle(ctx context.Context, req Request) Response { + if h.validator == nil { + panic("validator should never be nil") + } + if h.object == nil { + panic("object should never be nil") + } + + ctx = NewContextWithRequest(ctx, req) + + // Get the object in the request + obj := h.object.DeepCopyObject() + + var err error + switch req.Operation { + case v1.Create: + if err := h.decoder.Decode(req, obj); err != nil { + return Errored(http.StatusBadRequest, err) + } + + err = h.validator.ValidateCreate(ctx, obj) + case v1.Update: + oldObj := obj.DeepCopyObject() + if err := h.decoder.DecodeRaw(req.Object, obj); err != nil { + return Errored(http.StatusBadRequest, err) + } + if err := h.decoder.DecodeRaw(req.OldObject, oldObj); err != nil { + return Errored(http.StatusBadRequest, err) + } + + err = h.validator.ValidateUpdate(ctx, oldObj, obj) + case v1.Delete: + // In reference to PR: https://github.com/kubernetes/kubernetes/pull/76346 + // OldObject contains the object being deleted + if err := h.decoder.DecodeRaw(req.OldObject, obj); err != nil { + return Errored(http.StatusBadRequest, err) + } + + err = h.validator.ValidateDelete(ctx, obj) + default: + return Errored(http.StatusBadRequest, fmt.Errorf("unknown operation request %q", req.Operation)) + } + + // Check the error message first. + if err != nil { + var apiStatus apierrors.APIStatus + if errors.As(err, &apiStatus) { + return validationResponseFromStatus(false, apiStatus.Status()) + } + return Denied(err.Error()) + } + + // Return allowed if everything succeeded. + return Allowed("") +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/webhook.go b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/webhook.go new file mode 100644 index 0000000000..d10b97dddb --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/webhook.go @@ -0,0 +1,296 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package admission + +import ( + "context" + "errors" + "fmt" + "net/http" + + "github.com/go-logr/logr" + jsonpatch "gomodules.xyz/jsonpatch/v2" + admissionv1 "k8s.io/api/admission/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/json" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + "k8s.io/client-go/kubernetes/scheme" + + logf "sigs.k8s.io/controller-runtime/pkg/internal/log" + "sigs.k8s.io/controller-runtime/pkg/runtime/inject" + "sigs.k8s.io/controller-runtime/pkg/webhook/internal/metrics" +) + +var ( + errUnableToEncodeResponse = errors.New("unable to encode response") +) + +// Request defines the input for an admission handler. +// It contains information to identify the object in +// question (group, version, kind, resource, subresource, +// name, namespace), as well as the operation in question +// (e.g. Get, Create, etc), and the object itself. +type Request struct { + admissionv1.AdmissionRequest +} + +// Response is the output of an admission handler. +// It contains a response indicating if a given +// operation is allowed, as well as a set of patches +// to mutate the object in the case of a mutating admission handler. +type Response struct { + // Patches are the JSON patches for mutating webhooks. + // Using this instead of setting Response.Patch to minimize + // overhead of serialization and deserialization. + // Patches set here will override any patches in the response, + // so leave this empty if you want to set the patch response directly. + Patches []jsonpatch.JsonPatchOperation + // AdmissionResponse is the raw admission response. + // The Patch field in it will be overwritten by the listed patches. + admissionv1.AdmissionResponse +} + +// Complete populates any fields that are yet to be set in +// the underlying AdmissionResponse, It mutates the response. +func (r *Response) Complete(req Request) error { + r.UID = req.UID + + // ensure that we have a valid status code + if r.Result == nil { + r.Result = &metav1.Status{} + } + if r.Result.Code == 0 { + r.Result.Code = http.StatusOK + } + // TODO(directxman12): do we need to populate this further, and/or + // is code actually necessary (the same webhook doesn't use it) + + if len(r.Patches) == 0 { + return nil + } + + var err error + r.Patch, err = json.Marshal(r.Patches) + if err != nil { + return err + } + patchType := admissionv1.PatchTypeJSONPatch + r.PatchType = &patchType + + return nil +} + +// Handler can handle an AdmissionRequest. +type Handler interface { + // Handle yields a response to an AdmissionRequest. + // + // The supplied context is extracted from the received http.Request, allowing wrapping + // http.Handlers to inject values into and control cancelation of downstream request processing. + Handle(context.Context, Request) Response +} + +// HandlerFunc implements Handler interface using a single function. +type HandlerFunc func(context.Context, Request) Response + +var _ Handler = HandlerFunc(nil) + +// Handle process the AdmissionRequest by invoking the underlying function. +func (f HandlerFunc) Handle(ctx context.Context, req Request) Response { + return f(ctx, req) +} + +// Webhook represents each individual webhook. +// +// It must be registered with a webhook.Server or +// populated by StandaloneWebhook to be ran on an arbitrary HTTP server. +type Webhook struct { + // Handler actually processes an admission request returning whether it was allowed or denied, + // and potentially patches to apply to the handler. + Handler Handler + + // RecoverPanic indicates whether the panic caused by webhook should be recovered. + RecoverPanic bool + + // WithContextFunc will allow you to take the http.Request.Context() and + // add any additional information such as passing the request path or + // headers thus allowing you to read them from within the handler + WithContextFunc func(context.Context, *http.Request) context.Context + + // decoder is constructed on receiving a scheme and passed down to then handler + decoder *Decoder + + log logr.Logger +} + +// InjectLogger gets a handle to a logging instance, hopefully with more info about this particular webhook. +func (wh *Webhook) InjectLogger(l logr.Logger) error { + wh.log = l + return nil +} + +// WithRecoverPanic takes a bool flag which indicates whether the panic caused by webhook should be recovered. +func (wh *Webhook) WithRecoverPanic(recoverPanic bool) *Webhook { + wh.RecoverPanic = recoverPanic + return wh +} + +// Handle processes AdmissionRequest. +// If the webhook is mutating type, it delegates the AdmissionRequest to each handler and merge the patches. +// If the webhook is validating type, it delegates the AdmissionRequest to each handler and +// deny the request if anyone denies. +func (wh *Webhook) Handle(ctx context.Context, req Request) (response Response) { + if wh.RecoverPanic { + defer func() { + if r := recover(); r != nil { + for _, fn := range utilruntime.PanicHandlers { + fn(r) + } + response = Errored(http.StatusInternalServerError, fmt.Errorf("panic: %v [recovered]", r)) + return + } + }() + } + + resp := wh.Handler.Handle(ctx, req) + if err := resp.Complete(req); err != nil { + wh.log.Error(err, "unable to encode response") + return Errored(http.StatusInternalServerError, errUnableToEncodeResponse) + } + + return resp +} + +// InjectScheme injects a scheme into the webhook, in order to construct a Decoder. +func (wh *Webhook) InjectScheme(s *runtime.Scheme) error { + // TODO(directxman12): we should have a better way to pass this down + + var err error + wh.decoder, err = NewDecoder(s) + if err != nil { + return err + } + + // inject the decoder here too, just in case the order of calling this is not + // scheme first, then inject func + if wh.Handler != nil { + if _, err := InjectDecoderInto(wh.GetDecoder(), wh.Handler); err != nil { + return err + } + } + + return nil +} + +// GetDecoder returns a decoder to decode the objects embedded in admission requests. +// It may be nil if we haven't received a scheme to use to determine object types yet. +func (wh *Webhook) GetDecoder() *Decoder { + return wh.decoder +} + +// InjectFunc injects the field setter into the webhook. +func (wh *Webhook) InjectFunc(f inject.Func) error { + // inject directly into the handlers. It would be more correct + // to do this in a sync.Once in Handle (since we don't have some + // other start/finalize-type method), but it's more efficient to + // do it here, presumably. + + // also inject a decoder, and wrap this so that we get a setFields + // that injects a decoder (hopefully things don't ignore the duplicate + // InjectorInto call). + + var setFields inject.Func + setFields = func(target interface{}) error { + if err := f(target); err != nil { + return err + } + + if _, err := inject.InjectorInto(setFields, target); err != nil { + return err + } + + if _, err := InjectDecoderInto(wh.GetDecoder(), target); err != nil { + return err + } + + return nil + } + + return setFields(wh.Handler) +} + +// StandaloneOptions let you configure a StandaloneWebhook. +type StandaloneOptions struct { + // Scheme is the scheme used to resolve runtime.Objects to GroupVersionKinds / Resources + // Defaults to the kubernetes/client-go scheme.Scheme, but it's almost always better + // idea to pass your own scheme in. See the documentation in pkg/scheme for more information. + Scheme *runtime.Scheme + // Logger to be used by the webhook. + // If none is set, it defaults to log.Log global logger. + Logger logr.Logger + // MetricsPath is used for labelling prometheus metrics + // by the path is served on. + // If none is set, prometheus metrics will not be generated. + MetricsPath string +} + +// StandaloneWebhook prepares a webhook for use without a webhook.Server, +// passing in the information normally populated by webhook.Server +// and instrumenting the webhook with metrics. +// +// Use this to attach your webhook to an arbitrary HTTP server or mux. +// +// Note that you are responsible for terminating TLS if you use StandaloneWebhook +// in your own server/mux. In order to be accessed by a kubernetes cluster, +// all webhook servers require TLS. +func StandaloneWebhook(hook *Webhook, opts StandaloneOptions) (http.Handler, error) { + if opts.Scheme == nil { + opts.Scheme = scheme.Scheme + } + + if err := hook.InjectScheme(opts.Scheme); err != nil { + return nil, err + } + + if opts.Logger.GetSink() == nil { + opts.Logger = logf.RuntimeLog.WithName("webhook") + } + hook.log = opts.Logger + + if opts.MetricsPath == "" { + return hook, nil + } + return metrics.InstrumentedHook(opts.MetricsPath, hook), nil +} + +// requestContextKey is how we find the admission.Request in a context.Context. +type requestContextKey struct{} + +// RequestFromContext returns an admission.Request from ctx. +func RequestFromContext(ctx context.Context) (Request, error) { + if v, ok := ctx.Value(requestContextKey{}).(Request); ok { + return v, nil + } + + return Request{}, errors.New("admission.Request not found in context") +} + +// NewContextWithRequest returns a new Context, derived from ctx, which carries the +// provided admission.Request. +func NewContextWithRequest(ctx context.Context, req Request) context.Context { + return context.WithValue(ctx, requestContextKey{}, req) +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/alias.go b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/alias.go new file mode 100644 index 0000000000..293137db49 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/alias.go @@ -0,0 +1,79 @@ +/* +Copyright 2019 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package webhook + +import ( + "gomodules.xyz/jsonpatch/v2" + "sigs.k8s.io/controller-runtime/pkg/webhook/admission" +) + +// define some aliases for common bits of the webhook functionality + +// Defaulter defines functions for setting defaults on resources. +type Defaulter = admission.Defaulter + +// Validator defines functions for validating an operation. +type Validator = admission.Validator + +// CustomDefaulter defines functions for setting defaults on resources. +type CustomDefaulter = admission.CustomDefaulter + +// CustomValidator defines functions for validating an operation. +type CustomValidator = admission.CustomValidator + +// AdmissionRequest defines the input for an admission handler. +// It contains information to identify the object in +// question (group, version, kind, resource, subresource, +// name, namespace), as well as the operation in question +// (e.g. Get, Create, etc), and the object itself. +type AdmissionRequest = admission.Request + +// AdmissionResponse is the output of an admission handler. +// It contains a response indicating if a given +// operation is allowed, as well as a set of patches +// to mutate the object in the case of a mutating admission handler. +type AdmissionResponse = admission.Response + +// Admission is webhook suitable for registration with the server +// an admission webhook that validates API operations and potentially +// mutates their contents. +type Admission = admission.Webhook + +// AdmissionHandler knows how to process admission requests, validating them, +// and potentially mutating the objects they contain. +type AdmissionHandler = admission.Handler + +// AdmissionDecoder knows how to decode objects from admission requests. +type AdmissionDecoder = admission.Decoder + +// JSONPatchOp represents a single JSONPatch patch operation. +type JSONPatchOp = jsonpatch.Operation + +var ( + // Allowed indicates that the admission request should be allowed for the given reason. + Allowed = admission.Allowed + + // Denied indicates that the admission request should be denied for the given reason. + Denied = admission.Denied + + // Patched indicates that the admission request should be allowed for the given reason, + // and that the contained object should be mutated using the given patches. + Patched = admission.Patched + + // Errored indicates that an error occurred in the admission request. + Errored = admission.Errored +) diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/conversion/conversion.go b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/conversion/conversion.go new file mode 100644 index 0000000000..a5b7a282ce --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/conversion/conversion.go @@ -0,0 +1,345 @@ +/* +Copyright 2019 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* +Package conversion provides implementation for CRD conversion webhook that implements handler for version conversion requests for types that are convertible. + +See pkg/conversion for interface definitions required to ensure an API Type is convertible. +*/ +package conversion + +import ( + "encoding/json" + "fmt" + "net/http" + + apix "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + "k8s.io/apimachinery/pkg/api/meta" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "sigs.k8s.io/controller-runtime/pkg/conversion" + logf "sigs.k8s.io/controller-runtime/pkg/log" +) + +var ( + log = logf.Log.WithName("conversion-webhook") +) + +// Webhook implements a CRD conversion webhook HTTP handler. +type Webhook struct { + scheme *runtime.Scheme + decoder *Decoder +} + +// InjectScheme injects a scheme into the webhook, in order to construct a Decoder. +func (wh *Webhook) InjectScheme(s *runtime.Scheme) error { + var err error + wh.scheme = s + wh.decoder, err = NewDecoder(s) + if err != nil { + return err + } + + return nil +} + +// ensure Webhook implements http.Handler +var _ http.Handler = &Webhook{} + +func (wh *Webhook) ServeHTTP(w http.ResponseWriter, r *http.Request) { + convertReview := &apix.ConversionReview{} + err := json.NewDecoder(r.Body).Decode(convertReview) + if err != nil { + log.Error(err, "failed to read conversion request") + w.WriteHeader(http.StatusBadRequest) + return + } + + // TODO(droot): may be move the conversion logic to a separate module to + // decouple it from the http layer ? + resp, err := wh.handleConvertRequest(convertReview.Request) + if err != nil { + log.Error(err, "failed to convert", "request", convertReview.Request.UID) + convertReview.Response = errored(err) + } else { + convertReview.Response = resp + } + convertReview.Response.UID = convertReview.Request.UID + convertReview.Request = nil + + err = json.NewEncoder(w).Encode(convertReview) + if err != nil { + log.Error(err, "failed to write response") + return + } +} + +// handles a version conversion request. +func (wh *Webhook) handleConvertRequest(req *apix.ConversionRequest) (*apix.ConversionResponse, error) { + if req == nil { + return nil, fmt.Errorf("conversion request is nil") + } + var objects []runtime.RawExtension + + for _, obj := range req.Objects { + src, gvk, err := wh.decoder.Decode(obj.Raw) + if err != nil { + return nil, err + } + dst, err := wh.allocateDstObject(req.DesiredAPIVersion, gvk.Kind) + if err != nil { + return nil, err + } + err = wh.convertObject(src, dst) + if err != nil { + return nil, err + } + objects = append(objects, runtime.RawExtension{Object: dst}) + } + return &apix.ConversionResponse{ + UID: req.UID, + ConvertedObjects: objects, + Result: metav1.Status{ + Status: metav1.StatusSuccess, + }, + }, nil +} + +// convertObject will convert given a src object to dst object. +// Note(droot): couldn't find a way to reduce the cyclomatic complexity under 10 +// without compromising readability, so disabling gocyclo linter +func (wh *Webhook) convertObject(src, dst runtime.Object) error { + srcGVK := src.GetObjectKind().GroupVersionKind() + dstGVK := dst.GetObjectKind().GroupVersionKind() + + if srcGVK.GroupKind() != dstGVK.GroupKind() { + return fmt.Errorf("src %T and dst %T does not belong to same API Group", src, dst) + } + + if srcGVK == dstGVK { + return fmt.Errorf("conversion is not allowed between same type %T", src) + } + + srcIsHub, dstIsHub := isHub(src), isHub(dst) + srcIsConvertible, dstIsConvertible := isConvertible(src), isConvertible(dst) + + switch { + case srcIsHub && dstIsConvertible: + return dst.(conversion.Convertible).ConvertFrom(src.(conversion.Hub)) + case dstIsHub && srcIsConvertible: + return src.(conversion.Convertible).ConvertTo(dst.(conversion.Hub)) + case srcIsConvertible && dstIsConvertible: + return wh.convertViaHub(src.(conversion.Convertible), dst.(conversion.Convertible)) + default: + return fmt.Errorf("%T is not convertible to %T", src, dst) + } +} + +func (wh *Webhook) convertViaHub(src, dst conversion.Convertible) error { + hub, err := wh.getHub(src) + if err != nil { + return err + } + + if hub == nil { + return fmt.Errorf("%s does not have any Hub defined", src) + } + + err = src.ConvertTo(hub) + if err != nil { + return fmt.Errorf("%T failed to convert to hub version %T : %w", src, hub, err) + } + + err = dst.ConvertFrom(hub) + if err != nil { + return fmt.Errorf("%T failed to convert from hub version %T : %w", dst, hub, err) + } + + return nil +} + +// getHub returns an instance of the Hub for passed-in object's group/kind. +func (wh *Webhook) getHub(obj runtime.Object) (conversion.Hub, error) { + gvks, err := objectGVKs(wh.scheme, obj) + if err != nil { + return nil, err + } + if len(gvks) == 0 { + return nil, fmt.Errorf("error retrieving gvks for object : %v", obj) + } + + var hub conversion.Hub + var hubFoundAlready bool + for _, gvk := range gvks { + instance, err := wh.scheme.New(gvk) + if err != nil { + return nil, fmt.Errorf("failed to allocate an instance for gvk %v: %w", gvk, err) + } + if val, isHub := instance.(conversion.Hub); isHub { + if hubFoundAlready { + return nil, fmt.Errorf("multiple hub version defined for %T", obj) + } + hubFoundAlready = true + hub = val + } + } + return hub, nil +} + +// allocateDstObject returns an instance for a given GVK. +func (wh *Webhook) allocateDstObject(apiVersion, kind string) (runtime.Object, error) { + gvk := schema.FromAPIVersionAndKind(apiVersion, kind) + + obj, err := wh.scheme.New(gvk) + if err != nil { + return obj, err + } + + t, err := meta.TypeAccessor(obj) + if err != nil { + return obj, err + } + + t.SetAPIVersion(apiVersion) + t.SetKind(kind) + + return obj, nil +} + +// IsConvertible determines if given type is convertible or not. For a type +// to be convertible, the group-kind needs to have a Hub type defined and all +// non-hub types must be able to convert to/from Hub. +func IsConvertible(scheme *runtime.Scheme, obj runtime.Object) (bool, error) { + var hubs, spokes, nonSpokes []runtime.Object + + gvks, err := objectGVKs(scheme, obj) + if err != nil { + return false, err + } + if len(gvks) == 0 { + return false, fmt.Errorf("error retrieving gvks for object : %v", obj) + } + + for _, gvk := range gvks { + instance, err := scheme.New(gvk) + if err != nil { + return false, fmt.Errorf("failed to allocate an instance for gvk %v: %w", gvk, err) + } + + if isHub(instance) { + hubs = append(hubs, instance) + continue + } + + if !isConvertible(instance) { + nonSpokes = append(nonSpokes, instance) + continue + } + + spokes = append(spokes, instance) + } + + if len(gvks) == 1 { + return false, nil // single version + } + + if len(hubs) == 0 && len(spokes) == 0 { + // multiple version detected with no conversion implementation. This is + // true for multi-version built-in types. + return false, nil + } + + if len(hubs) == 1 && len(nonSpokes) == 0 { // convertible + return true, nil + } + + return false, PartialImplementationError{ + hubs: hubs, + nonSpokes: nonSpokes, + spokes: spokes, + } +} + +// objectGVKs returns all (Group,Version,Kind) for the Group/Kind of given object. +func objectGVKs(scheme *runtime.Scheme, obj runtime.Object) ([]schema.GroupVersionKind, error) { + // NB: we should not use `obj.GetObjectKind().GroupVersionKind()` to get the + // GVK here, since it is parsed from apiVersion and kind fields and it may + // return empty GVK if obj is an uninitialized object. + objGVKs, _, err := scheme.ObjectKinds(obj) + if err != nil { + return nil, err + } + if len(objGVKs) != 1 { + return nil, fmt.Errorf("expect to get only one GVK for %v", obj) + } + objGVK := objGVKs[0] + knownTypes := scheme.AllKnownTypes() + + var gvks []schema.GroupVersionKind + for gvk := range knownTypes { + if objGVK.GroupKind() == gvk.GroupKind() { + gvks = append(gvks, gvk) + } + } + return gvks, nil +} + +// PartialImplementationError represents an error due to partial conversion +// implementation such as hub without spokes, multiple hubs or spokes without hub. +type PartialImplementationError struct { + gvk schema.GroupVersionKind + hubs []runtime.Object + nonSpokes []runtime.Object + spokes []runtime.Object +} + +func (e PartialImplementationError) Error() string { + if len(e.hubs) == 0 { + return fmt.Sprintf("no hub defined for gvk %s", e.gvk) + } + if len(e.hubs) > 1 { + return fmt.Sprintf("multiple(%d) hubs defined for group-kind '%s' ", + len(e.hubs), e.gvk.GroupKind()) + } + if len(e.nonSpokes) > 0 { + return fmt.Sprintf("%d inconvertible types detected for group-kind '%s'", + len(e.nonSpokes), e.gvk.GroupKind()) + } + return "" +} + +// isHub determines if passed-in object is a Hub or not. +func isHub(obj runtime.Object) bool { + _, yes := obj.(conversion.Hub) + return yes +} + +// isConvertible determines if passed-in object is a convertible. +func isConvertible(obj runtime.Object) bool { + _, yes := obj.(conversion.Convertible) + return yes +} + +// helper to construct error response. +func errored(err error) *apix.ConversionResponse { + return &apix.ConversionResponse{ + Result: metav1.Status{ + Status: metav1.StatusFailure, + Message: err.Error(), + }, + } +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/conversion/decoder.go b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/conversion/decoder.go new file mode 100644 index 0000000000..6a9e9c2365 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/conversion/decoder.go @@ -0,0 +1,47 @@ +/* +Copyright 2021 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package conversion + +import ( + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/runtime/serializer" +) + +// Decoder knows how to decode the contents of a CRD version conversion +// request into a concrete object. +// TODO(droot): consider reusing decoder from admission pkg for this. +type Decoder struct { + codecs serializer.CodecFactory +} + +// NewDecoder creates a Decoder given the runtime.Scheme +func NewDecoder(scheme *runtime.Scheme) (*Decoder, error) { + return &Decoder{codecs: serializer.NewCodecFactory(scheme)}, nil +} + +// Decode decodes the inlined object. +func (d *Decoder) Decode(content []byte) (runtime.Object, *schema.GroupVersionKind, error) { + deserializer := d.codecs.UniversalDeserializer() + return deserializer.Decode(content, nil, nil) +} + +// DecodeInto decodes the inlined object in the into the passed-in runtime.Object. +func (d *Decoder) DecodeInto(content []byte, into runtime.Object) error { + deserializer := d.codecs.UniversalDeserializer() + return runtime.DecodeInto(deserializer, content, into) +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/doc.go b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/doc.go new file mode 100644 index 0000000000..2c93f0d995 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/doc.go @@ -0,0 +1,28 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* +Package webhook provides methods to build and bootstrap a webhook server. + +Currently, it only supports admission webhooks. It will support CRD conversion webhooks in the near future. +*/ +package webhook + +import ( + logf "sigs.k8s.io/controller-runtime/pkg/internal/log" +) + +var log = logf.RuntimeLog.WithName("webhook") diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/internal/metrics/metrics.go b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/internal/metrics/metrics.go new file mode 100644 index 0000000000..557004908b --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/internal/metrics/metrics.go @@ -0,0 +1,85 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package metrics + +import ( + "net/http" + + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promhttp" + + "sigs.k8s.io/controller-runtime/pkg/metrics" +) + +var ( + // RequestLatency is a prometheus metric which is a histogram of the latency + // of processing admission requests. + RequestLatency = prometheus.NewHistogramVec( + prometheus.HistogramOpts{ + Name: "controller_runtime_webhook_latency_seconds", + Help: "Histogram of the latency of processing admission requests", + }, + []string{"webhook"}, + ) + + // RequestTotal is a prometheus metric which is a counter of the total processed admission requests. + RequestTotal = func() *prometheus.CounterVec { + return prometheus.NewCounterVec( + prometheus.CounterOpts{ + Name: "controller_runtime_webhook_requests_total", + Help: "Total number of admission requests by HTTP status code.", + }, + []string{"webhook", "code"}, + ) + }() + + // RequestInFlight is a prometheus metric which is a gauge of the in-flight admission requests. + RequestInFlight = func() *prometheus.GaugeVec { + return prometheus.NewGaugeVec( + prometheus.GaugeOpts{ + Name: "controller_runtime_webhook_requests_in_flight", + Help: "Current number of admission requests being served.", + }, + []string{"webhook"}, + ) + }() +) + +func init() { + metrics.Registry.MustRegister(RequestLatency, RequestTotal, RequestInFlight) +} + +// InstrumentedHook adds some instrumentation on top of the given webhook. +func InstrumentedHook(path string, hookRaw http.Handler) http.Handler { + lbl := prometheus.Labels{"webhook": path} + + lat := RequestLatency.MustCurryWith(lbl) + cnt := RequestTotal.MustCurryWith(lbl) + gge := RequestInFlight.With(lbl) + + // Initialize the most likely HTTP status codes. + cnt.WithLabelValues("200") + cnt.WithLabelValues("500") + + return promhttp.InstrumentHandlerDuration( + lat, + promhttp.InstrumentHandlerCounter( + cnt, + promhttp.InstrumentHandlerInFlight(gge, hookRaw), + ), + ) +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/server.go b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/server.go new file mode 100644 index 0000000000..06f479208a --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/server.go @@ -0,0 +1,345 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package webhook + +import ( + "context" + "crypto/tls" + "crypto/x509" + "fmt" + "net" + "net/http" + "os" + "path/filepath" + "strconv" + "sync" + "time" + + "k8s.io/apimachinery/pkg/runtime" + kscheme "k8s.io/client-go/kubernetes/scheme" + "sigs.k8s.io/controller-runtime/pkg/certwatcher" + "sigs.k8s.io/controller-runtime/pkg/healthz" + "sigs.k8s.io/controller-runtime/pkg/internal/httpserver" + "sigs.k8s.io/controller-runtime/pkg/runtime/inject" + "sigs.k8s.io/controller-runtime/pkg/webhook/internal/metrics" +) + +// DefaultPort is the default port that the webhook server serves. +var DefaultPort = 9443 + +// Server is an admission webhook server that can serve traffic and +// generates related k8s resources for deploying. +// +// TLS is required for a webhook to be accessed by kubernetes, so +// you must provide a CertName and KeyName or have valid cert/key +// at the default locations (tls.crt and tls.key). If you do not +// want to configure TLS (i.e for testing purposes) run an +// admission.StandaloneWebhook in your own server. +type Server struct { + // Host is the address that the server will listen on. + // Defaults to "" - all addresses. + Host string + + // Port is the port number that the server will serve. + // It will be defaulted to 9443 if unspecified. + Port int + + // CertDir is the directory that contains the server key and certificate. The + // server key and certificate. + CertDir string + + // CertName is the server certificate name. Defaults to tls.crt. + CertName string + + // KeyName is the server key name. Defaults to tls.key. + KeyName string + + // ClientCAName is the CA certificate name which server used to verify remote(client)'s certificate. + // Defaults to "", which means server does not verify client's certificate. + ClientCAName string + + // TLSVersion is the minimum version of TLS supported. Accepts + // "", "1.0", "1.1", "1.2" and "1.3" only ("" is equivalent to "1.0" for backwards compatibility) + TLSMinVersion string + + // TLSOpts is used to allow configuring the TLS config used for the server + TLSOpts []func(*tls.Config) + + // WebhookMux is the multiplexer that handles different webhooks. + WebhookMux *http.ServeMux + + // webhooks keep track of all registered webhooks for dependency injection, + // and to provide better panic messages on duplicate webhook registration. + webhooks map[string]http.Handler + + // setFields allows injecting dependencies from an external source + setFields inject.Func + + // defaultingOnce ensures that the default fields are only ever set once. + defaultingOnce sync.Once + + // started is set to true immediately before the server is started + // and thus can be used to check if the server has been started + started bool + + // mu protects access to the webhook map & setFields for Start, Register, etc + mu sync.Mutex +} + +// setDefaults does defaulting for the Server. +func (s *Server) setDefaults() { + s.webhooks = map[string]http.Handler{} + if s.WebhookMux == nil { + s.WebhookMux = http.NewServeMux() + } + + if s.Port <= 0 { + s.Port = DefaultPort + } + + if len(s.CertDir) == 0 { + s.CertDir = filepath.Join(os.TempDir(), "k8s-webhook-server", "serving-certs") + } + + if len(s.CertName) == 0 { + s.CertName = "tls.crt" + } + + if len(s.KeyName) == 0 { + s.KeyName = "tls.key" + } +} + +// NeedLeaderElection implements the LeaderElectionRunnable interface, which indicates +// the webhook server doesn't need leader election. +func (*Server) NeedLeaderElection() bool { + return false +} + +// Register marks the given webhook as being served at the given path. +// It panics if two hooks are registered on the same path. +func (s *Server) Register(path string, hook http.Handler) { + s.mu.Lock() + defer s.mu.Unlock() + + s.defaultingOnce.Do(s.setDefaults) + if _, found := s.webhooks[path]; found { + panic(fmt.Errorf("can't register duplicate path: %v", path)) + } + // TODO(directxman12): call setfields if we've already started the server + s.webhooks[path] = hook + s.WebhookMux.Handle(path, metrics.InstrumentedHook(path, hook)) + + regLog := log.WithValues("path", path) + regLog.Info("Registering webhook") + + // we've already been "started", inject dependencies here. + // Otherwise, InjectFunc will do this for us later. + if s.setFields != nil { + if err := s.setFields(hook); err != nil { + // TODO(directxman12): swallowing this error isn't great, but we'd have to + // change the signature to fix that + regLog.Error(err, "unable to inject fields into webhook during registration") + } + + baseHookLog := log.WithName("webhooks") + + // NB(directxman12): we don't propagate this further by wrapping setFields because it's + // unclear if this is how we want to deal with log propagation. In this specific instance, + // we want to be able to pass a logger to webhooks because they don't know their own path. + if _, err := inject.LoggerInto(baseHookLog.WithValues("webhook", path), hook); err != nil { + regLog.Error(err, "unable to logger into webhook during registration") + } + } +} + +// StartStandalone runs a webhook server without +// a controller manager. +func (s *Server) StartStandalone(ctx context.Context, scheme *runtime.Scheme) error { + // Use the Kubernetes client-go scheme if none is specified + if scheme == nil { + scheme = kscheme.Scheme + } + + if err := s.InjectFunc(func(i interface{}) error { + if _, err := inject.SchemeInto(scheme, i); err != nil { + return err + } + return nil + }); err != nil { + return err + } + + return s.Start(ctx) +} + +// tlsVersion converts from human-readable TLS version (for example "1.1") +// to the values accepted by tls.Config (for example 0x301). +func tlsVersion(version string) (uint16, error) { + switch version { + // default is previous behaviour + case "": + return tls.VersionTLS10, nil + case "1.0": + return tls.VersionTLS10, nil + case "1.1": + return tls.VersionTLS11, nil + case "1.2": + return tls.VersionTLS12, nil + case "1.3": + return tls.VersionTLS13, nil + default: + return 0, fmt.Errorf("invalid TLSMinVersion %v: expects 1.0, 1.1, 1.2, 1.3 or empty", version) + } +} + +// Start runs the server. +// It will install the webhook related resources depend on the server configuration. +func (s *Server) Start(ctx context.Context) error { + s.defaultingOnce.Do(s.setDefaults) + + baseHookLog := log.WithName("webhooks") + baseHookLog.Info("Starting webhook server") + + certPath := filepath.Join(s.CertDir, s.CertName) + keyPath := filepath.Join(s.CertDir, s.KeyName) + + certWatcher, err := certwatcher.New(certPath, keyPath) + if err != nil { + return err + } + + go func() { + if err := certWatcher.Start(ctx); err != nil { + log.Error(err, "certificate watcher error") + } + }() + + tlsMinVersion, err := tlsVersion(s.TLSMinVersion) + if err != nil { + return err + } + + cfg := &tls.Config{ //nolint:gosec + NextProtos: []string{"h2"}, + GetCertificate: certWatcher.GetCertificate, + MinVersion: tlsMinVersion, + } + + // load CA to verify client certificate + if s.ClientCAName != "" { + certPool := x509.NewCertPool() + clientCABytes, err := os.ReadFile(filepath.Join(s.CertDir, s.ClientCAName)) + if err != nil { + return fmt.Errorf("failed to read client CA cert: %w", err) + } + + ok := certPool.AppendCertsFromPEM(clientCABytes) + if !ok { + return fmt.Errorf("failed to append client CA cert to CA pool") + } + + cfg.ClientCAs = certPool + cfg.ClientAuth = tls.RequireAndVerifyClientCert + } + + // fallback TLS config ready, will now mutate if passer wants full control over it + for _, op := range s.TLSOpts { + op(cfg) + } + + listener, err := tls.Listen("tcp", net.JoinHostPort(s.Host, strconv.Itoa(s.Port)), cfg) + if err != nil { + return err + } + + log.Info("Serving webhook server", "host", s.Host, "port", s.Port) + + srv := httpserver.New(s.WebhookMux) + + idleConnsClosed := make(chan struct{}) + go func() { + <-ctx.Done() + log.Info("shutting down webhook server") + + // TODO: use a context with reasonable timeout + if err := srv.Shutdown(context.Background()); err != nil { + // Error from closing listeners, or context timeout + log.Error(err, "error shutting down the HTTP server") + } + close(idleConnsClosed) + }() + + s.mu.Lock() + s.started = true + s.mu.Unlock() + if err := srv.Serve(listener); err != nil && err != http.ErrServerClosed { + return err + } + + <-idleConnsClosed + return nil +} + +// StartedChecker returns an healthz.Checker which is healthy after the +// server has been started. +func (s *Server) StartedChecker() healthz.Checker { + config := &tls.Config{ + InsecureSkipVerify: true, //nolint:gosec // config is used to connect to our own webhook port. + } + return func(req *http.Request) error { + s.mu.Lock() + defer s.mu.Unlock() + + if !s.started { + return fmt.Errorf("webhook server has not been started yet") + } + + d := &net.Dialer{Timeout: 10 * time.Second} + conn, err := tls.DialWithDialer(d, "tcp", net.JoinHostPort(s.Host, strconv.Itoa(s.Port)), config) + if err != nil { + return fmt.Errorf("webhook server is not reachable: %w", err) + } + + if err := conn.Close(); err != nil { + return fmt.Errorf("webhook server is not reachable: closing connection: %w", err) + } + + return nil + } +} + +// InjectFunc injects the field setter into the server. +func (s *Server) InjectFunc(f inject.Func) error { + s.setFields = f + + // inject fields here that weren't injected in Register because we didn't have setFields yet. + baseHookLog := log.WithName("webhooks") + for hookPath, webhook := range s.webhooks { + if err := s.setFields(webhook); err != nil { + return err + } + + // NB(directxman12): we don't propagate this further by wrapping setFields because it's + // unclear if this is how we want to deal with log propagation. In this specific instance, + // we want to be able to pass a logger to webhooks because they don't know their own path. + if _, err := inject.LoggerInto(baseHookLog.WithValues("webhook", hookPath), webhook); err != nil { + return err + } + } + return nil +}