From c360931054b56e6b2894cecfc02b9ca70cb58c92 Mon Sep 17 00:00:00 2001 From: Jingfang Liu Date: Thu, 28 Jun 2018 11:57:03 -0700 Subject: [PATCH] Add project v1 support --- cmd/Gopkg.lock | 20 +- cmd/Gopkg.toml | 4 + cmd/kubebuilder/initproject/apis.go | 2 +- cmd/kubebuilder/initproject/init.go | 80 ++-- cmd/kubebuilder/initproject/project.go | 158 ++++++++ cmd/kubebuilder/initproject/vendor.go | 6 +- cmd/kubebuilder/main.go | 74 +--- cmd/kubebuilder/util/stdin.go | 48 +++ cmd/kubebuilder/util/util.go | 13 + cmd/kubebuilder/v0/commands.go | 86 ++++ cmd/kubebuilder/v1/api.go | 175 +++++++++ cmd/kubebuilder/v1/commands.go | 71 ++++ .../github.com/emicklei/go-restful/LICENSE | 22 -- .../emicklei/go-restful/compress.go | 123 ------ .../emicklei/go-restful/compressor_cache.go | 103 ----- .../emicklei/go-restful/compressor_pools.go | 91 ----- .../emicklei/go-restful/compressors.go | 54 --- .../emicklei/go-restful/constants.go | 30 -- .../emicklei/go-restful/container.go | 366 ------------------ .../emicklei/go-restful/cors_filter.go | 202 ---------- .../github.com/emicklei/go-restful/curly.go | 164 -------- .../emicklei/go-restful/curly_route.go | 52 --- .../github.com/emicklei/go-restful/doc.go | 185 --------- .../emicklei/go-restful/entity_accessors.go | 163 -------- .../google_app_engine/datastore/main.go | 267 ------------- .../restful-appstats-integration.go | 12 - .../google_app_engine/restful-user-service.go | 162 -------- .../examples/msgpack/msgpack_entity.go | 34 -- .../examples/restful-CORS-filter.go | 68 ---- .../examples/restful-NCSA-logging.go | 54 --- .../examples/restful-basic-authentication.go | 35 -- .../examples/restful-cpuprofiler-service.go | 65 ---- .../examples/restful-curly-router.go | 107 ----- .../examples/restful-encoding-filter.go | 61 --- .../go-restful/examples/restful-filters.go | 114 ------ .../examples/restful-form-handling.go | 62 --- .../examples/restful-hello-world.go | 22 -- .../examples/restful-html-template.go | 35 -- .../examples/restful-multi-containers.go | 43 -- .../examples/restful-no-cache-filter.go | 24 -- .../examples/restful-options-filter.go | 51 --- .../go-restful/examples/restful-path-tail.go | 26 -- .../examples/restful-pre-post-filters.go | 98 ----- .../examples/restful-resource-functions.go | 63 --- .../examples/restful-serve-static.go | 47 --- .../go-restful/examples/restful-swagger.go | 61 --- .../examples/restful-user-resource.go | 152 -------- .../examples/restful-user-service.go | 143 ------- .../github.com/emicklei/go-restful/filter.go | 35 -- .../github.com/emicklei/go-restful/jsr311.go | 248 ------------ .../github.com/emicklei/go-restful/log/log.go | 34 -- .../github.com/emicklei/go-restful/logger.go | 32 -- .../github.com/emicklei/go-restful/mime.go | 45 --- .../emicklei/go-restful/options_filter.go | 26 -- .../emicklei/go-restful/parameter.go | 114 ------ .../emicklei/go-restful/path_expression.go | 69 ---- .../github.com/emicklei/go-restful/request.go | 113 ------ .../emicklei/go-restful/response.go | 236 ----------- .../github.com/emicklei/go-restful/route.go | 186 --------- .../emicklei/go-restful/route_builder.go | 293 -------------- .../github.com/emicklei/go-restful/router.go | 18 - .../emicklei/go-restful/service_error.go | 23 -- .../emicklei/go-restful/web_service.go | 290 -------------- .../go-restful/web_service_container.go | 39 -- .../sigs.k8s.io/controller-tools/LICENSE | 201 ++++++++++ .../cmd/controller-scaffold/cmd/api.go | 163 ++++++++ .../cmd/controller-scaffold/cmd/project.go | 140 +++++++ .../cmd/controller-scaffold/cmd/root.go | 87 +++++ .../cmd/controller-scaffold/cmd/stdin.go | 48 +++ .../cmd/controller-scaffold/doc.go | 20 + .../cmd/controller-scaffold/main.go | 21 + .../examples/godocbot/cmd/manager/main.go | 71 ++++ .../godocbot/pkg/apis/add_code_v1alpha1.go | 26 ++ .../examples/godocbot/pkg/apis/apis.go | 35 ++ .../examples/godocbot/pkg/apis/code/group.go | 18 + .../apis/code/v1alpha1/deepcopy_generated.go | 117 ++++++ .../godocbot/pkg/apis/code/v1alpha1/doc.go | 22 ++ .../apis/code/v1alpha1/pullrequest_types.go | 67 ++++ .../pkg/apis/code/v1alpha1/register.go | 57 +++ .../pkg/controller/add_pullrequest.go | 27 ++ .../godocbot/pkg/controller/controller.go | 34 ++ .../controller/pullrequest/github_syncer.go | 236 +++++++++++ .../controller/pullrequest/godoc_deployer.go | 260 +++++++++++++ .../controller-tools/pkg/generate/doc.go | 18 + .../pkg/scaffold/controller/add.go | 60 +++ .../pkg/scaffold/controller/controller.go | 250 ++++++++++++ .../controller/controllersuitetest.go | 102 +++++ .../pkg/scaffold/controller/controllertest.go | 134 +++++++ .../controller-tools/pkg/scaffold/doc.go | 18 + .../pkg/scaffold/input/input.go | 172 ++++++++ .../pkg/scaffold/manager/apis.go | 79 ++++ .../pkg/scaffold/manager/cmd.go | 86 ++++ .../pkg/scaffold/manager/config.go | 105 +++++ .../pkg/scaffold/manager/controller.go | 61 +++ .../pkg/scaffold/manager/dockerfile.go | 70 ++++ .../pkg/scaffold/project/boilerplate.go | 86 ++++ .../pkg/scaffold/project/gitignore.go | 62 +++ .../pkg/scaffold/project/gopkg.go | 317 +++++++++++++++ .../pkg/scaffold/project/makefile.go | 70 ++++ .../pkg/scaffold/project/project.go | 95 +++++ .../project/projectutil/projectutil.go | 48 +++ .../pkg/scaffold/resource/addtoscheme.go | 58 +++ .../pkg/scaffold/resource/crd.go | 77 ++++ .../pkg/scaffold/resource/doc.go | 56 +++ .../pkg/scaffold/resource/group.go | 48 +++ .../pkg/scaffold/resource/register.go | 68 ++++ .../pkg/scaffold/resource/resource.go | 84 ++++ .../pkg/scaffold/resource/role.go | 60 +++ .../pkg/scaffold/resource/rolebinding.go | 59 +++ .../pkg/scaffold/resource/types.go | 107 +++++ .../pkg/scaffold/resource/typestest.go | 90 +++++ .../scaffold/resource/version_suitetest.go | 87 +++++ .../controller-tools/pkg/scaffold/scaffold.go | 244 ++++++++++++ .../pkg/scaffold/scaffoldtest/scaffoldtest.go | 86 ++++ .../controller-tools/test/cmd/manager/main.go | 59 +++ .../apis/addtoscheme_creatures_v2alpha1.go | 26 ++ .../test/pkg/apis/addtoscheme_crew_v1.go | 26 ++ .../test/pkg/apis/addtoscheme_ship_v1beta1.go | 26 ++ .../controller-tools/test/pkg/apis/apis.go | 33 ++ .../test/pkg/apis/creatures/group.go | 18 + .../test/pkg/apis/creatures/v2alpha1/doc.go | 23 ++ .../apis/creatures/v2alpha1/kraken_types.go | 64 +++ .../pkg/apis/creatures/v2alpha1/register.go | 38 ++ .../test/pkg/apis/crew/group.go | 18 + .../test/pkg/apis/crew/v1/doc.go | 23 ++ .../test/pkg/apis/crew/v1/firstmate_types.go | 62 +++ .../test/pkg/apis/crew/v1/register.go | 38 ++ .../test/pkg/apis/ship/group.go | 18 + .../test/pkg/apis/ship/v1beta1/doc.go | 23 ++ .../pkg/apis/ship/v1beta1/frigate_types.go | 62 +++ .../test/pkg/apis/ship/v1beta1/register.go | 38 ++ .../test/pkg/controller/add_firstmate.go | 26 ++ .../test/pkg/controller/add_frigate.go | 26 ++ .../test/pkg/controller/add_kraken.go | 26 ++ .../test/pkg/controller/add_namespace.go | 26 ++ .../test/pkg/controller/controller.go | 34 ++ .../firstmate/firstmate_controller.go | 165 ++++++++ .../controller/frigate/frigate_controller.go | 105 +++++ .../controller/kraken/kraken_controller.go | 105 +++++ .../namespace/namespace_controller.go | 105 +++++ 140 files changed, 6460 insertions(+), 5259 deletions(-) create mode 100644 cmd/kubebuilder/initproject/project.go create mode 100644 cmd/kubebuilder/util/stdin.go create mode 100644 cmd/kubebuilder/v0/commands.go create mode 100644 cmd/kubebuilder/v1/api.go create mode 100644 cmd/kubebuilder/v1/commands.go delete mode 100644 cmd/vendor/github.com/emicklei/go-restful/LICENSE delete mode 100644 cmd/vendor/github.com/emicklei/go-restful/compress.go delete mode 100644 cmd/vendor/github.com/emicklei/go-restful/compressor_cache.go delete mode 100644 cmd/vendor/github.com/emicklei/go-restful/compressor_pools.go delete mode 100644 cmd/vendor/github.com/emicklei/go-restful/compressors.go delete mode 100644 cmd/vendor/github.com/emicklei/go-restful/constants.go delete mode 100644 cmd/vendor/github.com/emicklei/go-restful/container.go delete mode 100644 cmd/vendor/github.com/emicklei/go-restful/cors_filter.go delete mode 100644 cmd/vendor/github.com/emicklei/go-restful/curly.go delete mode 100644 cmd/vendor/github.com/emicklei/go-restful/curly_route.go delete mode 100644 cmd/vendor/github.com/emicklei/go-restful/doc.go delete mode 100644 cmd/vendor/github.com/emicklei/go-restful/entity_accessors.go delete mode 100644 cmd/vendor/github.com/emicklei/go-restful/examples/google_app_engine/datastore/main.go delete mode 100644 cmd/vendor/github.com/emicklei/go-restful/examples/google_app_engine/restful-appstats-integration.go delete mode 100644 cmd/vendor/github.com/emicklei/go-restful/examples/google_app_engine/restful-user-service.go delete mode 100644 cmd/vendor/github.com/emicklei/go-restful/examples/msgpack/msgpack_entity.go delete mode 100644 cmd/vendor/github.com/emicklei/go-restful/examples/restful-CORS-filter.go delete mode 100644 cmd/vendor/github.com/emicklei/go-restful/examples/restful-NCSA-logging.go delete mode 100644 cmd/vendor/github.com/emicklei/go-restful/examples/restful-basic-authentication.go delete mode 100644 cmd/vendor/github.com/emicklei/go-restful/examples/restful-cpuprofiler-service.go delete mode 100644 cmd/vendor/github.com/emicklei/go-restful/examples/restful-curly-router.go delete mode 100644 cmd/vendor/github.com/emicklei/go-restful/examples/restful-encoding-filter.go delete mode 100644 cmd/vendor/github.com/emicklei/go-restful/examples/restful-filters.go delete mode 100644 cmd/vendor/github.com/emicklei/go-restful/examples/restful-form-handling.go delete mode 100644 cmd/vendor/github.com/emicklei/go-restful/examples/restful-hello-world.go delete mode 100644 cmd/vendor/github.com/emicklei/go-restful/examples/restful-html-template.go delete mode 100644 cmd/vendor/github.com/emicklei/go-restful/examples/restful-multi-containers.go delete mode 100644 cmd/vendor/github.com/emicklei/go-restful/examples/restful-no-cache-filter.go delete mode 100644 cmd/vendor/github.com/emicklei/go-restful/examples/restful-options-filter.go delete mode 100644 cmd/vendor/github.com/emicklei/go-restful/examples/restful-path-tail.go delete mode 100644 cmd/vendor/github.com/emicklei/go-restful/examples/restful-pre-post-filters.go delete mode 100644 cmd/vendor/github.com/emicklei/go-restful/examples/restful-resource-functions.go delete mode 100644 cmd/vendor/github.com/emicklei/go-restful/examples/restful-serve-static.go delete mode 100644 cmd/vendor/github.com/emicklei/go-restful/examples/restful-swagger.go delete mode 100644 cmd/vendor/github.com/emicklei/go-restful/examples/restful-user-resource.go delete mode 100644 cmd/vendor/github.com/emicklei/go-restful/examples/restful-user-service.go delete mode 100644 cmd/vendor/github.com/emicklei/go-restful/filter.go delete mode 100644 cmd/vendor/github.com/emicklei/go-restful/jsr311.go delete mode 100644 cmd/vendor/github.com/emicklei/go-restful/log/log.go delete mode 100644 cmd/vendor/github.com/emicklei/go-restful/logger.go delete mode 100644 cmd/vendor/github.com/emicklei/go-restful/mime.go delete mode 100644 cmd/vendor/github.com/emicklei/go-restful/options_filter.go delete mode 100644 cmd/vendor/github.com/emicklei/go-restful/parameter.go delete mode 100644 cmd/vendor/github.com/emicklei/go-restful/path_expression.go delete mode 100644 cmd/vendor/github.com/emicklei/go-restful/request.go delete mode 100644 cmd/vendor/github.com/emicklei/go-restful/response.go delete mode 100644 cmd/vendor/github.com/emicklei/go-restful/route.go delete mode 100644 cmd/vendor/github.com/emicklei/go-restful/route_builder.go delete mode 100644 cmd/vendor/github.com/emicklei/go-restful/router.go delete mode 100644 cmd/vendor/github.com/emicklei/go-restful/service_error.go delete mode 100644 cmd/vendor/github.com/emicklei/go-restful/web_service.go delete mode 100644 cmd/vendor/github.com/emicklei/go-restful/web_service_container.go create mode 100644 cmd/vendor/sigs.k8s.io/controller-tools/LICENSE create mode 100644 cmd/vendor/sigs.k8s.io/controller-tools/cmd/controller-scaffold/cmd/api.go create mode 100644 cmd/vendor/sigs.k8s.io/controller-tools/cmd/controller-scaffold/cmd/project.go create mode 100644 cmd/vendor/sigs.k8s.io/controller-tools/cmd/controller-scaffold/cmd/root.go create mode 100644 cmd/vendor/sigs.k8s.io/controller-tools/cmd/controller-scaffold/cmd/stdin.go create mode 100644 cmd/vendor/sigs.k8s.io/controller-tools/cmd/controller-scaffold/doc.go create mode 100644 cmd/vendor/sigs.k8s.io/controller-tools/cmd/controller-scaffold/main.go create mode 100644 cmd/vendor/sigs.k8s.io/controller-tools/examples/godocbot/cmd/manager/main.go create mode 100644 cmd/vendor/sigs.k8s.io/controller-tools/examples/godocbot/pkg/apis/add_code_v1alpha1.go create mode 100644 cmd/vendor/sigs.k8s.io/controller-tools/examples/godocbot/pkg/apis/apis.go create mode 100644 cmd/vendor/sigs.k8s.io/controller-tools/examples/godocbot/pkg/apis/code/group.go create mode 100644 cmd/vendor/sigs.k8s.io/controller-tools/examples/godocbot/pkg/apis/code/v1alpha1/deepcopy_generated.go create mode 100644 cmd/vendor/sigs.k8s.io/controller-tools/examples/godocbot/pkg/apis/code/v1alpha1/doc.go create mode 100644 cmd/vendor/sigs.k8s.io/controller-tools/examples/godocbot/pkg/apis/code/v1alpha1/pullrequest_types.go create mode 100644 cmd/vendor/sigs.k8s.io/controller-tools/examples/godocbot/pkg/apis/code/v1alpha1/register.go create mode 100644 cmd/vendor/sigs.k8s.io/controller-tools/examples/godocbot/pkg/controller/add_pullrequest.go create mode 100644 cmd/vendor/sigs.k8s.io/controller-tools/examples/godocbot/pkg/controller/controller.go create mode 100644 cmd/vendor/sigs.k8s.io/controller-tools/examples/godocbot/pkg/controller/pullrequest/github_syncer.go create mode 100644 cmd/vendor/sigs.k8s.io/controller-tools/examples/godocbot/pkg/controller/pullrequest/godoc_deployer.go create mode 100644 cmd/vendor/sigs.k8s.io/controller-tools/pkg/generate/doc.go create mode 100644 cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/controller/add.go create mode 100644 cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/controller/controller.go create mode 100644 cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/controller/controllersuitetest.go create mode 100644 cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/controller/controllertest.go create mode 100644 cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/doc.go create mode 100644 cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/input/input.go create mode 100644 cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/manager/apis.go create mode 100644 cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/manager/cmd.go create mode 100644 cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/manager/config.go create mode 100644 cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/manager/controller.go create mode 100644 cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/manager/dockerfile.go create mode 100644 cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/project/boilerplate.go create mode 100644 cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/project/gitignore.go create mode 100644 cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/project/gopkg.go create mode 100644 cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/project/makefile.go create mode 100644 cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/project/project.go create mode 100644 cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/project/projectutil/projectutil.go create mode 100644 cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/resource/addtoscheme.go create mode 100644 cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/resource/crd.go create mode 100644 cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/resource/doc.go create mode 100644 cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/resource/group.go create mode 100644 cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/resource/register.go create mode 100644 cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/resource/resource.go create mode 100644 cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/resource/role.go create mode 100644 cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/resource/rolebinding.go create mode 100644 cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/resource/types.go create mode 100644 cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/resource/typestest.go create mode 100644 cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/resource/version_suitetest.go create mode 100644 cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/scaffold.go create mode 100644 cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/scaffoldtest/scaffoldtest.go create mode 100644 cmd/vendor/sigs.k8s.io/controller-tools/test/cmd/manager/main.go create mode 100644 cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/apis/addtoscheme_creatures_v2alpha1.go create mode 100644 cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/apis/addtoscheme_crew_v1.go create mode 100644 cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/apis/addtoscheme_ship_v1beta1.go create mode 100644 cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/apis/apis.go create mode 100644 cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/apis/creatures/group.go create mode 100644 cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/apis/creatures/v2alpha1/doc.go create mode 100644 cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/apis/creatures/v2alpha1/kraken_types.go create mode 100644 cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/apis/creatures/v2alpha1/register.go create mode 100644 cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/apis/crew/group.go create mode 100644 cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/apis/crew/v1/doc.go create mode 100644 cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/apis/crew/v1/firstmate_types.go create mode 100644 cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/apis/crew/v1/register.go create mode 100644 cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/apis/ship/group.go create mode 100644 cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/apis/ship/v1beta1/doc.go create mode 100644 cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/apis/ship/v1beta1/frigate_types.go create mode 100644 cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/apis/ship/v1beta1/register.go create mode 100644 cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/controller/add_firstmate.go create mode 100644 cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/controller/add_frigate.go create mode 100644 cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/controller/add_kraken.go create mode 100644 cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/controller/add_namespace.go create mode 100644 cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/controller/controller.go create mode 100644 cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/controller/firstmate/firstmate_controller.go create mode 100644 cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/controller/frigate/frigate_controller.go create mode 100644 cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/controller/kraken/kraken_controller.go create mode 100644 cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/controller/namespace/namespace_controller.go diff --git a/cmd/Gopkg.lock b/cmd/Gopkg.lock index ed98b6b173..ebde8442a8 100644 --- a/cmd/Gopkg.lock +++ b/cmd/Gopkg.lock @@ -1,11 +1,6 @@ # This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. -[[projects]] - name = "github.com/emicklei/go-restful" - packages = ["log"] - revision = "ff4f55a206334ef123e4f79bbf348980da81ca46" - [[projects]] name = "github.com/ghodss/yaml" packages = ["."] @@ -198,9 +193,22 @@ ] revision = "01a732e01d00cb9a81bb0ca050d3e6d2b947927b" +[[projects]] + branch = "master" + name = "sigs.k8s.io/controller-tools" + packages = [ + "pkg/scaffold", + "pkg/scaffold/controller", + "pkg/scaffold/input", + "pkg/scaffold/manager", + "pkg/scaffold/project", + "pkg/scaffold/resource" + ] + revision = "ebc6b604ffe8679ebc52cb1e67b76139ad7a7599" + [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "53c0546d5938231df9b5bf3a3e878723d37026c0048dd7238a5e57dcc5e47992" + inputs-digest = "5f2f7c7d77ad09b2125ce55c6718ca5871a9fb30afa58a0bb1728a6185dd51b2" solver-name = "gps-cdcl" solver-version = 1 diff --git a/cmd/Gopkg.toml b/cmd/Gopkg.toml index 02788c91bf..88f3055eca 100644 --- a/cmd/Gopkg.toml +++ b/cmd/Gopkg.toml @@ -43,3 +43,7 @@ [[constraint]] version = "kubernetes-1.10.1" name = "k8s.io/client-go" + +[[constraint]] + branch = "master" + name = "sigs.k8s.io/controller-tools" diff --git a/cmd/kubebuilder/initproject/apis.go b/cmd/kubebuilder/initproject/apis.go index 2a1084d920..bd2c7afd6a 100644 --- a/cmd/kubebuilder/initproject/apis.go +++ b/cmd/kubebuilder/initproject/apis.go @@ -22,7 +22,7 @@ import ( ) // createAPIs creates a new package under pkg/apis -func createAPIs(boilerplate string) { +func createAPIs(boilerplate, domain string) { fmt.Printf("\t%s/\n", filepath.Join("pkg", "apis")) execute( filepath.Join("pkg", "apis", "doc.go"), diff --git a/cmd/kubebuilder/initproject/init.go b/cmd/kubebuilder/initproject/init.go index fd1c429c85..5358469b0a 100644 --- a/cmd/kubebuilder/initproject/init.go +++ b/cmd/kubebuilder/initproject/init.go @@ -27,32 +27,56 @@ import ( "github.com/kubernetes-sigs/kubebuilder/cmd/kubebuilder/util" "github.com/spf13/cobra" + "sigs.k8s.io/controller-tools/pkg/scaffold/manager" + "sigs.k8s.io/controller-tools/pkg/scaffold/project" ) -var repoCmd = &cobra.Command{ - Use: "init", - Short: "Initialize a new project", - Long: `Initialize a new project including vendor/ directory and go package directories.`, - Example: `# Initialize project structure + +type initOptions struct { + domain string + copyright string + bazel bool + controllerOnly bool + projectVersion string + projectOptions +} + +func AddInit(cmd *cobra.Command) { + o := initOptions{} + + initCmd := &cobra.Command{ + Use: "init", + Short: "Initialize a new project", + Long: `Initialize a new project including vendor/ directory and Go package directories.`, + Example: `# Initialize project structure kubebuilder init repo --domain mydomain `, - Run: runInitRepo, -} + Run: func(cmd *cobra.Command, args []string) { + o.runInitRepo() + }, + } -var domain string -var copyright string -var bazel bool -var controllerOnly bool + initCmd.Flags().StringVar(&o.domain, "domain", "", "domain for the API groups") + initCmd.Flags().StringVar(&o.copyright, "copyright", filepath.Join("hack", "boilerplate.go.txt"), "Location of copyright boilerplate file.") + initCmd.Flags().BoolVar(&o.bazel, "bazel", false, "if true, setup Bazel workspace artifacts") + initCmd.Flags().BoolVar(&o.controllerOnly, "controller-only", false, "if true, setup controller only") + initCmd.Flags().StringVar(&o.projectVersion, "project-version", "v0", "if set to v1, init project with kubebuilder 1.0") -func AddInit(cmd *cobra.Command) { - cmd.AddCommand(repoCmd) - repoCmd.Flags().StringVar(&domain, "domain", "", "domain for the API groups") - repoCmd.Flags().StringVar(©right, "copyright", filepath.Join("hack", "boilerplate.go.txt"), "Location of copyright boilerplate file.") - repoCmd.Flags().BoolVar(&bazel, "bazel", false, "if true, setup Bazel workspace artifacts") - repoCmd.Flags().BoolVar(&controllerOnly, "controller-only", false, "if true, setup controller only") + + initCmd.Flags().BoolVar( + &o.dep, "dep", true, v1comment + "if specified, determines whether dep will be used.") + o.depFlag = initCmd.Flag("dep") + + o.prj = projectForFlags(initCmd.Flags()) + o.bp = boilerplateForFlags(initCmd.Flags()) + o.gopkg = &project.GopkgToml{} + o.mgr = &manager.Cmd{} + o.dkr = &manager.Dockerfile{} + + cmd.AddCommand(initCmd) } -func runInitRepo(cmd *cobra.Command, args []string) { +func (o *initOptions) runInitRepo() { version := runtime.Version() if versionCmp(version, "go1.10") < 0 { log.Fatalf("The go version is %v, must be 1.10+", version) @@ -61,18 +85,26 @@ func runInitRepo(cmd *cobra.Command, args []string) { log.Fatalf("Dep is not installed. Follow steps at: https://golang.github.io/dep/docs/installation.html") } - if len(domain) == 0 { + if o.projectVersion == "v1" { + if len(o.domain) != 0 { + o.prj.Domain = o.domain + } + o.RunInit() + return + } + + if len(o.domain) == 0 { log.Fatal("Must specify --domain") } - cr := util.GetCopyright(copyright) + cr := util.GetCopyright(o.copyright) fmt.Printf("Initializing project structure...\n") - if bazel { + if o.bazel { createBazelWorkspace() } createControllerManager(cr) //createInstaller(cr) - createAPIs(cr) + createAPIs(cr, o.domain) //runCreateApiserver(cr) pkgs := []string{ @@ -89,8 +121,8 @@ func runInitRepo(cmd *cobra.Command, args []string) { } doDockerfile() doInject(cr) - doArgs(cr, controllerOnly) - RunVendorInstall(nil, nil) + doArgs(cr, o.controllerOnly) + RunVendorInstall(nil, []string{o.copyright}) createBoilerplate() fmt.Printf("Next: Define a resource with:\n" + "$ kubebuilder create resource\n") diff --git a/cmd/kubebuilder/initproject/project.go b/cmd/kubebuilder/initproject/project.go new file mode 100644 index 0000000000..8f3a0978c5 --- /dev/null +++ b/cmd/kubebuilder/initproject/project.go @@ -0,0 +1,158 @@ +/* +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 initproject + +import ( + "fmt" + "log" + "os" + "os/exec" + "strings" + + "github.com/kubernetes-sigs/kubebuilder/cmd/kubebuilder/util" + "github.com/spf13/cobra" + flag "github.com/spf13/pflag" + "sigs.k8s.io/controller-tools/pkg/scaffold" + "sigs.k8s.io/controller-tools/pkg/scaffold/input" + "sigs.k8s.io/controller-tools/pkg/scaffold/manager" + "sigs.k8s.io/controller-tools/pkg/scaffold/project" +) + +type projectOptions struct { + prj *project.Project + bp *project.Boilerplate + gopkg *project.GopkgToml + mgr *manager.Cmd + dkr *manager.Dockerfile + dep bool + depFlag *flag.Flag +} + +var v1comment = "Works only with --project-version v1. " + +func (o *projectOptions) RunInit() { + if util.ProjectExist() { + fmt.Println("Failed to initialize project bacause project is already initialized") + return + } + // project and boilerplate must come before main so the boilerplate exists + s := &scaffold.Scaffold{ + BoilerplateOptional: true, + ProjectOptional: true, + } + + p, _ := o.prj.GetInput() + b, _ := o.bp.GetInput() + err := s.Execute(input.Options{ProjectPath: p.Path, BoilerplatePath: b.Path}, o.prj, o.bp) + if err != nil { + log.Fatal(err) + } + + s = &scaffold.Scaffold{} + err = s.Execute(input.Options{ProjectPath: p.Path, BoilerplatePath: b.Path}, + o.gopkg, o.mgr, &project.Makefile{}, o.dkr, &manager.APIs{}, &manager.Controller{}, &manager.Config{}, + &project.GitIgnore{}) + if err != nil { + log.Fatal(err) + } + + if !o.depFlag.Changed { + fmt.Println("Run `dep ensure` to fetch dependencies (Recommended) [y/n]?") + o.dep = util.Yesno() + } + if o.dep { + c := exec.Command("dep", "ensure") // #nosec + c.Stderr = os.Stderr + c.Stdout = os.Stdout + fmt.Println(strings.Join(c.Args, " ")) + if err := c.Run(); err != nil { + log.Fatal(err) + } + + fmt.Println("Running make...") + c = exec.Command("make") // #nosec + c.Stderr = os.Stderr + c.Stdout = os.Stdout + fmt.Println(strings.Join(c.Args, " ")) + if err := c.Run(); err != nil { + log.Fatal(err) + } + } else { + fmt.Println("Skipping `dep ensure`. Dependencies will not be fetched.") + } + fmt.Printf("Next: Define a resource with:\n" + + "$ kubebuilder create api\n") +} + +func AddProjectCommand(cmd *cobra.Command) { + o := projectOptions{} + + projectCmd := &cobra.Command{ + Use: "init", + Short: "Scaffold a new project.", + Long: `Scaffold a project. + +Writes the following files: +- a boilerplate license file +- a PROJECT file with the domain and repo +- a Makefile to build the project +- a Gopkg.toml with project dependencies +- a cmd/manager/main.go to run + +project will prompt the user to run 'dep ensure' after writing the project files. +`, + Example: `# Scaffold a project using the apache2 license with "The Kubernetes authors" as owners +kubebuilder init --domain k8s.io --license apache2 --owner "The Kubernetes authors" +`, + Run: func(cmd *cobra.Command, args []string) { + o.RunInit() + }, + } + + projectCmd.Flags().BoolVar( + &o.dep, "dep", true, "if specified, determines whether dep will be used.") + o.depFlag = projectCmd.Flag("dep") + + o.prj = projectForFlags(projectCmd.Flags()) + o.bp = boilerplateForFlags(projectCmd.Flags()) + o.gopkg = &project.GopkgToml{} + o.mgr = &manager.Cmd{} + o.dkr = &manager.Dockerfile{} + + cmd.AddCommand(projectCmd) +} + +// projectForFlags registers flags for Project fields and returns the Project +func projectForFlags(f *flag.FlagSet) *project.Project { + p := &project.Project{} + f.StringVar(&p.Repo, "repo", "", v1comment + "name of the github repo. "+ + "defaults to the go package of the current working directory.") + p.Version = "2" + p.Domain = "k8s.io" + return p +} + +// boilerplateForFlags registers flags for Boilerplate fields and returns the Boilerplate +func boilerplateForFlags(f *flag.FlagSet) *project.Boilerplate { + b := &project.Boilerplate{} + f.StringVar(&b.Path, "path", "", v1comment + "path for boilerplate") + f.StringVar(&b.License, "license", "apache2", + v1comment + "license to use to boilerplate. Maybe one of apache2,none") + f.StringVar(&b.Owner, "owner", "", + v1comment + "Owner to add to the copyright") + return b +} diff --git a/cmd/kubebuilder/initproject/vendor.go b/cmd/kubebuilder/initproject/vendor.go index f9700e1777..da918cbe19 100644 --- a/cmd/kubebuilder/initproject/vendor.go +++ b/cmd/kubebuilder/initproject/vendor.go @@ -52,8 +52,10 @@ var builderCommit string var Update bool func RunVendorInstall(cmd *cobra.Command, args []string) { - cr := util.GetCopyright(copyright) - doImports(cr) + if len(args) > 0 { + cr := util.GetCopyright(args[0]) + doImports(cr) + } if !depExists() { log.Fatalf("Dep is not installed. Follow steps at: https://golang.github.io/dep/docs/installation.html") } diff --git a/cmd/kubebuilder/main.go b/cmd/kubebuilder/main.go index a00fdaed66..18e647cd8a 100644 --- a/cmd/kubebuilder/main.go +++ b/cmd/kubebuilder/main.go @@ -23,16 +23,12 @@ import ( "path/filepath" "strings" - "github.com/spf13/cobra" - - "github.com/kubernetes-sigs/kubebuilder/cmd/kubebuilder/build" - "github.com/kubernetes-sigs/kubebuilder/cmd/kubebuilder/create" - "github.com/kubernetes-sigs/kubebuilder/cmd/kubebuilder/docs" - "github.com/kubernetes-sigs/kubebuilder/cmd/kubebuilder/generate" "github.com/kubernetes-sigs/kubebuilder/cmd/kubebuilder/initproject" - "github.com/kubernetes-sigs/kubebuilder/cmd/kubebuilder/update" "github.com/kubernetes-sigs/kubebuilder/cmd/kubebuilder/util" "github.com/kubernetes-sigs/kubebuilder/cmd/kubebuilder/version" + "github.com/kubernetes-sigs/kubebuilder/cmd/kubebuilder/v0" + "github.com/kubernetes-sigs/kubebuilder/cmd/kubebuilder/v1" + "github.com/spf13/cobra" ) func main() { @@ -53,15 +49,15 @@ func main() { "\nCurrent GOPATH=%s. \nCurrent directory=%s", gopath, wd) } util.Repo = strings.Replace(wd, util.GoSrc+string(filepath.Separator), "", 1) - - build.AddBuild(cmd) - create.AddCreate(cmd) - docs.AddDocs(cmd) - generate.AddGenerate(cmd) initproject.AddInit(cmd) - update.AddUpdate(cmd) version.AddVersion(cmd) + if util.IsNewVersion() { + v1.AddCmds(cmd) + } else { + v0.AddCmds(cmd) + } + if err := cmd.Execute(); err != nil { log.Fatal(err) } @@ -70,57 +66,7 @@ func main() { var cmd = &cobra.Command{ Use: "kubebuilder", Short: "Development kit for building Kubernetes extensions and tools.", - Long: `Development kit for building Kubernetes extensions and tools. - -Provides libraries and tools to create new projects, APIs and controllers. -Includes tools for packaging artifacts into an installer container. - -Typical project lifecycle: - -- initialize a project: - - kubebuilder init --domain example.com - -- create one or more a new resource APIs and add your code to them: - - kubebuilder create resource --group --version --kind - -- run the controller as a local process (e.g. not in a container), installing APIs into the cluster if they are missing: - - GOBIN=${PWD}/bin go install ${PWD#$GOPATH/src/}/cmd/controller-manager - bin/controller-manager --kubeconfig ~/.kube/config - - # In another terminal create a new instance of your resource and watch the controller-manager output - kubectl apply -f hack/sample/.yaml - - -- build a docker container to install the API and controller into a namespace with RBAC configured: - - Note: You may need to give yourself admin privs in order to install the RBAC rules - kubectl create clusterrolebinding --clusterrole=cluster-admin --user= - - docker build -f Dockerfile.controller . -t - docker push - kubebuilder create config --controller-image --name - kubectl apply -f hack/install.yaml - -More options: - -- run tests - kubebuilder generate - go test ./pkg/... - -- build reference documentation to docs/reference/build/index.html - kubebuilder create example --group --version --kind - kubebuilder docs -`, - Example: `# Initialize your project -kubebuilder init --domain example.com - -# Initialize your project adding a go-header file to all generated files -touch hack/boilerplate.go.txt -kubebuilder init --domain example.com`, - Run: RunMain, + Run: RunMain, } func RunMain(cmd *cobra.Command, args []string) { diff --git a/cmd/kubebuilder/util/stdin.go b/cmd/kubebuilder/util/stdin.go new file mode 100644 index 0000000000..230e768487 --- /dev/null +++ b/cmd/kubebuilder/util/stdin.go @@ -0,0 +1,48 @@ +/* +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 util + +import ( + "bufio" + "log" + "os" + "strings" +) + +// Yesno reads from stdin looking for one of "y", "yes", "n", "no" and returns +// true for "y" and false for "n" +func Yesno() bool { + reader := bufio.NewReader(os.Stdin) + for { + switch readstdin(reader) { + case "y", "yes": + return true + case "n", "no": + return false + } + } +} + +// Readstdin reads a line from stdin trimming spaces, and returns the value. +// log.Fatal's if there is an error. +func readstdin(reader *bufio.Reader) string { + text, err := reader.ReadString('\n') + if err != nil { + log.Fatal(err) + } + return strings.TrimSpace(text) +} diff --git a/cmd/kubebuilder/util/util.go b/cmd/kubebuilder/util/util.go index 94c004d522..4f8922a761 100644 --- a/cmd/kubebuilder/util/util.go +++ b/cmd/kubebuilder/util/util.go @@ -167,3 +167,16 @@ func CheckInstall() { strings.Join(missing, ",")) } } + +func IsNewVersion() bool { + _, err := os.Stat("PROJECT") + if err != nil { + return false + } + + return true +} + +func ProjectExist() bool { + return IsNewVersion() +} diff --git a/cmd/kubebuilder/v0/commands.go b/cmd/kubebuilder/v0/commands.go new file mode 100644 index 0000000000..99fc2ea840 --- /dev/null +++ b/cmd/kubebuilder/v0/commands.go @@ -0,0 +1,86 @@ +/* +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 v0 + +import ( + "github.com/spf13/cobra" + + "github.com/kubernetes-sigs/kubebuilder/cmd/kubebuilder/build" + "github.com/kubernetes-sigs/kubebuilder/cmd/kubebuilder/create" + "github.com/kubernetes-sigs/kubebuilder/cmd/kubebuilder/docs" + "github.com/kubernetes-sigs/kubebuilder/cmd/kubebuilder/generate" + "github.com/kubernetes-sigs/kubebuilder/cmd/kubebuilder/update" +) + +func AddCmds(cmd *cobra.Command) { + build.AddBuild(cmd) + create.AddCreate(cmd) + docs.AddDocs(cmd) + generate.AddGenerate(cmd) + update.AddUpdate(cmd) + cmd.Long = `Development kit for building Kubernetes extensions and tools. + +Provides libraries and tools to create new projects, APIs and controllers. +Includes tools for packaging artifacts into an installer container. + +Typical project lifecycle: + +- initialize a project: + + kubebuilder init --domain example.com + +- create one or more a new resource APIs and add your code to them: + + kubebuilder create resource --group --version --kind + +- run the controller as a local process (e.g. not in a container), installing APIs into the cluster if they are missing: + + GOBIN=${PWD}/bin go install ${PWD#$GOPATH/src/}/cmd/controller-manager + bin/controller-manager --kubeconfig ~/.kube/config + + # In another terminal create a new instance of your resource and watch the controller-manager output + kubectl apply -f hack/sample/.yaml + + +- build a docker container to install the API and controller into a namespace with RBAC configured: + + Note: You may need to give yourself admin privs in order to install the RBAC rules + kubectl create clusterrolebinding --clusterrole=cluster-admin --user= + + docker build -f Dockerfile.controller . -t + docker push + kubebuilder create config --controller-image --name + kubectl apply -f hack/install.yaml + +More options: + +- run tests + kubebuilder generate + go test ./pkg/... + +- build reference documentation to docs/reference/build/index.html + kubebuilder create example --group --version --kind + kubebuilder docs +` + + cmd.Example = `# Initialize your project +kubebuilder init --domain example.com + +# Initialize your project adding a go-header file to all generated files +touch hack/boilerplate.go.txt +kubebuilder init --domain example.com` +} diff --git a/cmd/kubebuilder/v1/api.go b/cmd/kubebuilder/v1/api.go new file mode 100644 index 0000000000..eba3bf19c5 --- /dev/null +++ b/cmd/kubebuilder/v1/api.go @@ -0,0 +1,175 @@ +/* +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 v1 + +import ( + "fmt" + "log" + "os" + "os/exec" + "path/filepath" + "strings" + + "github.com/kubernetes-sigs/kubebuilder/cmd/kubebuilder/util" + "github.com/spf13/cobra" + flag "github.com/spf13/pflag" + "sigs.k8s.io/controller-tools/pkg/scaffold" + "sigs.k8s.io/controller-tools/pkg/scaffold/controller" + "sigs.k8s.io/controller-tools/pkg/scaffold/input" + "sigs.k8s.io/controller-tools/pkg/scaffold/resource" +) + +type apiOptions struct { + r *resource.Resource + resourceFlag, controllerFlag *flag.Flag + doResource, doController, doMake bool +} + +// APICmd represents the resource command + +func (o *apiOptions) RunAddAPI() { + dieIfNoProject() + + if !o.resourceFlag.Changed { + fmt.Println("Create Resource under pkg/apis [y/n]?") + o.doResource = util.Yesno() + } + if !o.controllerFlag.Changed { + fmt.Println("Create Controller under pkg/controller [y/n]?") + o.doController = util.Yesno() + } + + fmt.Println("Writing scaffold for you to edit...") + + r := o.r + if o.doResource { + fmt.Println(filepath.Join("pkg", "apis", r.Group, r.Version, + fmt.Sprintf("%s_types.go", strings.ToLower(r.Kind)))) + fmt.Println(filepath.Join("pkg", "apis", r.Group, r.Version, + fmt.Sprintf("%s_types_test.go", strings.ToLower(r.Kind)))) + + err := (&scaffold.Scaffold{}).Execute(input.Options{}, + &resource.Register{Resource: r}, + &resource.Types{Resource: r}, + &resource.VersionSuiteTest{Resource: r}, + &resource.TypesTest{Resource: r}, + &resource.Doc{Resource: r}, + &resource.Group{Resource: r}, + &resource.AddToScheme{Resource: r}, + &resource.CRD{Resource: r}, + &resource.Role{Resource: r}, + &resource.RoleBinding{Resource: r}, + ) + if err != nil { + log.Fatal(err) + } + } + + if o.doController { + fmt.Println(filepath.Join("pkg", "controller", strings.ToLower(r.Kind), + fmt.Sprintf("%s_controller.go", strings.ToLower(r.Kind)))) + fmt.Println(filepath.Join("pkg", "apis", strings.ToLower(r.Kind), + fmt.Sprintf("%s_controller_test.go", strings.ToLower(r.Kind)))) + + err := (&scaffold.Scaffold{}).Execute(input.Options{}, + &controller.Controller{Resource: r}, + &controller.AddController{Resource: r}, + &controller.Test{Resource: r}, + &controller.SuiteTest{Resource: r}, + ) + if err != nil { + log.Fatal(err) + } + } + + if o.doMake { + fmt.Println("Running make...") + cm := exec.Command("make") // #nosec + cm.Stderr = os.Stderr + cm.Stdout = os.Stdout + if err := cm.Run(); err != nil { + log.Fatal(err) + } + } +} + +func AddAPICommand(cmd *cobra.Command) { + o := apiOptions{} + + apiCmd := &cobra.Command{ + Use: "create api", + Short: "Scaffold a Kubernetes API", + Long: `Scaffold a Kubernetes API by creating a Resource definition and / or a Controller. + +create resource will prompt the user for if it should scaffold the Resource and / or Controller. To only +scaffold a Controller for an existing Resource, select "n" for Resource. To only define +the schema for a Resource without writing a Controller, select "n" for Controller. + +After the scaffold is written, api will run make on the project. +`, + Example: ` # Create a frigates API with Group: ship, Version: v1beta1 and Kind: Frigate + kubebuilder create api --group ship --version v1beta1 --kind Frigate + + # Edit the API Scheme + nano pkg/apis/ship/v1beta1/frigate_types.go + + # Edit the Controller + nano pkg/controller/frigate/frigate_controller.go + + # Edit the Controller Test + nano pkg/controller/frigate/frigate_controller_test.go + + # Install CRDs into the Kubernetes cluster using kubectl apply + make install + + # Regenerate code and run against the Kubernetes cluster configured by ~/.kube/config + make run +`, + Run: func(cmd *cobra.Command, args []string) { + o.RunAddAPI() + }, + } + + apiCmd.Flags().BoolVar(&o.doMake, "make", true, + "if true, run make after generating files") + apiCmd.Flags().BoolVar(&o.doResource, "resource", true, + "if set, generate the resource without prompting the user") + o.resourceFlag = apiCmd.Flag("resource") + apiCmd.Flags().BoolVar(&o.doController, "controller", true, + "if set, generate the controller without prompting the user") + o.controllerFlag = apiCmd.Flag("controller") + o.r = ResourceForFlags(apiCmd.Flags()) + + cmd.AddCommand(apiCmd) +} + +// DieIfNoProject checks to make sure the command is run from a directory containing a project file. +func dieIfNoProject() { + if _, err := os.Stat("PROJECT"); os.IsNotExist(err) { + log.Fatalf("Command must be run from a diretory containing %s", "PROJECT") + } +} + + +// ResourceForFlags registers flags for Resource fields and returns the Resource +func ResourceForFlags(f *flag.FlagSet) *resource.Resource { + r := &resource.Resource{} + f.StringVar(&r.Kind, "kind", "", "resource Kind") + f.StringVar(&r.Group, "group", "", "resource Group") + f.StringVar(&r.Version, "version", "", "resource Version") + return r +} \ No newline at end of file diff --git a/cmd/kubebuilder/v1/commands.go b/cmd/kubebuilder/v1/commands.go new file mode 100644 index 0000000000..acf46810d4 --- /dev/null +++ b/cmd/kubebuilder/v1/commands.go @@ -0,0 +1,71 @@ +/* +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 v1 + +import ( + "github.com/spf13/cobra" +) + +func AddCmds(cmd *cobra.Command) { + AddAPICommand(cmd) + // TODO: User update commands from controller-tools once it is available + //update.AddUpdate(cmd) + + cmd.Example = `# Initialize your project + kubebuilder init --domain example.com --license apache2 --owner "The Kubernetes authors" + + # Create a frigates API with Group: ship, Version: v1beta1 and Kind: Frigate + kubebuilder create api --group ship --version v1beta1 --kind Frigate + + # Edit the API Scheme + nano pkg/apis/ship/v1beta1/frigate_types.go + + # Edit the Controller + nano pkg/controller/frigate/frigate_controller.go + + # Edit the Controller Test + nano pkg/controller/frigate/frigate_controller_test.go + + # Install CRDs into the Kubernetes cluster using kubectl apply + make install + + # Regenerate code and run against the Kubernetes cluster configured by ~/.kube/config + make run` + + cmd.Long = ` +Development kit for building Kubernetes extensions and tools. + +Provides libraries and tools to create new projects, APIs and controllers. +Includes tools for packaging artifacts into an installer container. + +Typical project lifecycle: + +- initialize a project: + + kubebuilder init --domain k8s.io --license apache2 --owner "The Kubernetes authors + +- create one or more a new resource APIs and add your code to them: + + kubebuilder create api --group --version --kind + +create resource will prompt the user for if it should scaffold the Resource and / or Controller. To only +scaffold a Controller for an existing Resource, select "n" for Resource. To only define +the schema for a Resource without writing a Controller, select "n" for Controller. + +After the scaffold is written, api will run make on the project. + ` +} diff --git a/cmd/vendor/github.com/emicklei/go-restful/LICENSE b/cmd/vendor/github.com/emicklei/go-restful/LICENSE deleted file mode 100644 index ece7ec61ef..0000000000 --- a/cmd/vendor/github.com/emicklei/go-restful/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -Copyright (c) 2012,2013 Ernest Micklei - -MIT License - -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/cmd/vendor/github.com/emicklei/go-restful/compress.go b/cmd/vendor/github.com/emicklei/go-restful/compress.go deleted file mode 100644 index 220b37712f..0000000000 --- a/cmd/vendor/github.com/emicklei/go-restful/compress.go +++ /dev/null @@ -1,123 +0,0 @@ -package restful - -// Copyright 2013 Ernest Micklei. All rights reserved. -// Use of this source code is governed by a license -// that can be found in the LICENSE file. - -import ( - "bufio" - "compress/gzip" - "compress/zlib" - "errors" - "io" - "net" - "net/http" - "strings" -) - -// OBSOLETE : use restful.DefaultContainer.EnableContentEncoding(true) to change this setting. -var EnableContentEncoding = false - -// CompressingResponseWriter is a http.ResponseWriter that can perform content encoding (gzip and zlib) -type CompressingResponseWriter struct { - writer http.ResponseWriter - compressor io.WriteCloser - encoding string -} - -// Header is part of http.ResponseWriter interface -func (c *CompressingResponseWriter) Header() http.Header { - return c.writer.Header() -} - -// WriteHeader is part of http.ResponseWriter interface -func (c *CompressingResponseWriter) WriteHeader(status int) { - c.writer.WriteHeader(status) -} - -// Write is part of http.ResponseWriter interface -// It is passed through the compressor -func (c *CompressingResponseWriter) Write(bytes []byte) (int, error) { - if c.isCompressorClosed() { - return -1, errors.New("Compressing error: tried to write data using closed compressor") - } - return c.compressor.Write(bytes) -} - -// CloseNotify is part of http.CloseNotifier interface -func (c *CompressingResponseWriter) CloseNotify() <-chan bool { - return c.writer.(http.CloseNotifier).CloseNotify() -} - -// Close the underlying compressor -func (c *CompressingResponseWriter) Close() error { - if c.isCompressorClosed() { - return errors.New("Compressing error: tried to close already closed compressor") - } - - c.compressor.Close() - if ENCODING_GZIP == c.encoding { - currentCompressorProvider.ReleaseGzipWriter(c.compressor.(*gzip.Writer)) - } - if ENCODING_DEFLATE == c.encoding { - currentCompressorProvider.ReleaseZlibWriter(c.compressor.(*zlib.Writer)) - } - // gc hint needed? - c.compressor = nil - return nil -} - -func (c *CompressingResponseWriter) isCompressorClosed() bool { - return nil == c.compressor -} - -// Hijack implements the Hijacker interface -// This is especially useful when combining Container.EnabledContentEncoding -// in combination with websockets (for instance gorilla/websocket) -func (c *CompressingResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) { - hijacker, ok := c.writer.(http.Hijacker) - if !ok { - return nil, nil, errors.New("ResponseWriter doesn't support Hijacker interface") - } - return hijacker.Hijack() -} - -// WantsCompressedResponse reads the Accept-Encoding header to see if and which encoding is requested. -func wantsCompressedResponse(httpRequest *http.Request) (bool, string) { - header := httpRequest.Header.Get(HEADER_AcceptEncoding) - gi := strings.Index(header, ENCODING_GZIP) - zi := strings.Index(header, ENCODING_DEFLATE) - // use in order of appearance - if gi == -1 { - return zi != -1, ENCODING_DEFLATE - } else if zi == -1 { - return gi != -1, ENCODING_GZIP - } else { - if gi < zi { - return true, ENCODING_GZIP - } - return true, ENCODING_DEFLATE - } -} - -// NewCompressingResponseWriter create a CompressingResponseWriter for a known encoding = {gzip,deflate} -func NewCompressingResponseWriter(httpWriter http.ResponseWriter, encoding string) (*CompressingResponseWriter, error) { - httpWriter.Header().Set(HEADER_ContentEncoding, encoding) - c := new(CompressingResponseWriter) - c.writer = httpWriter - var err error - if ENCODING_GZIP == encoding { - w := currentCompressorProvider.AcquireGzipWriter() - w.Reset(httpWriter) - c.compressor = w - c.encoding = ENCODING_GZIP - } else if ENCODING_DEFLATE == encoding { - w := currentCompressorProvider.AcquireZlibWriter() - w.Reset(httpWriter) - c.compressor = w - c.encoding = ENCODING_DEFLATE - } else { - return nil, errors.New("Unknown encoding:" + encoding) - } - return c, err -} diff --git a/cmd/vendor/github.com/emicklei/go-restful/compressor_cache.go b/cmd/vendor/github.com/emicklei/go-restful/compressor_cache.go deleted file mode 100644 index ee426010a2..0000000000 --- a/cmd/vendor/github.com/emicklei/go-restful/compressor_cache.go +++ /dev/null @@ -1,103 +0,0 @@ -package restful - -// Copyright 2015 Ernest Micklei. All rights reserved. -// Use of this source code is governed by a license -// that can be found in the LICENSE file. - -import ( - "compress/gzip" - "compress/zlib" -) - -// BoundedCachedCompressors is a CompressorProvider that uses a cache with a fixed amount -// of writers and readers (resources). -// If a new resource is acquired and all are in use, it will return a new unmanaged resource. -type BoundedCachedCompressors struct { - gzipWriters chan *gzip.Writer - gzipReaders chan *gzip.Reader - zlibWriters chan *zlib.Writer - writersCapacity int - readersCapacity int -} - -// NewBoundedCachedCompressors returns a new, with filled cache, BoundedCachedCompressors. -func NewBoundedCachedCompressors(writersCapacity, readersCapacity int) *BoundedCachedCompressors { - b := &BoundedCachedCompressors{ - gzipWriters: make(chan *gzip.Writer, writersCapacity), - gzipReaders: make(chan *gzip.Reader, readersCapacity), - zlibWriters: make(chan *zlib.Writer, writersCapacity), - writersCapacity: writersCapacity, - readersCapacity: readersCapacity, - } - for ix := 0; ix < writersCapacity; ix++ { - b.gzipWriters <- newGzipWriter() - b.zlibWriters <- newZlibWriter() - } - for ix := 0; ix < readersCapacity; ix++ { - b.gzipReaders <- newGzipReader() - } - return b -} - -// AcquireGzipWriter returns an resettable *gzip.Writer. Needs to be released. -func (b *BoundedCachedCompressors) AcquireGzipWriter() *gzip.Writer { - var writer *gzip.Writer - select { - case writer, _ = <-b.gzipWriters: - default: - // return a new unmanaged one - writer = newGzipWriter() - } - return writer -} - -// ReleaseGzipWriter accepts a writer (does not have to be one that was cached) -// only when the cache has room for it. It will ignore it otherwise. -func (b *BoundedCachedCompressors) ReleaseGzipWriter(w *gzip.Writer) { - // forget the unmanaged ones - if len(b.gzipWriters) < b.writersCapacity { - b.gzipWriters <- w - } -} - -// AcquireGzipReader returns a *gzip.Reader. Needs to be released. -func (b *BoundedCachedCompressors) AcquireGzipReader() *gzip.Reader { - var reader *gzip.Reader - select { - case reader, _ = <-b.gzipReaders: - default: - // return a new unmanaged one - reader = newGzipReader() - } - return reader -} - -// ReleaseGzipReader accepts a reader (does not have to be one that was cached) -// only when the cache has room for it. It will ignore it otherwise. -func (b *BoundedCachedCompressors) ReleaseGzipReader(r *gzip.Reader) { - // forget the unmanaged ones - if len(b.gzipReaders) < b.readersCapacity { - b.gzipReaders <- r - } -} - -// AcquireZlibWriter returns an resettable *zlib.Writer. Needs to be released. -func (b *BoundedCachedCompressors) AcquireZlibWriter() *zlib.Writer { - var writer *zlib.Writer - select { - case writer, _ = <-b.zlibWriters: - default: - // return a new unmanaged one - writer = newZlibWriter() - } - return writer -} - -// ReleaseZlibWriter accepts a writer (does not have to be one that was cached) -// only when the cache has room for it. It will ignore it otherwise. -func (b *BoundedCachedCompressors) ReleaseZlibWriter(w *zlib.Writer) { - // forget the unmanaged ones - if len(b.zlibWriters) < b.writersCapacity { - b.zlibWriters <- w - } -} diff --git a/cmd/vendor/github.com/emicklei/go-restful/compressor_pools.go b/cmd/vendor/github.com/emicklei/go-restful/compressor_pools.go deleted file mode 100644 index d866ce64bb..0000000000 --- a/cmd/vendor/github.com/emicklei/go-restful/compressor_pools.go +++ /dev/null @@ -1,91 +0,0 @@ -package restful - -// Copyright 2015 Ernest Micklei. All rights reserved. -// Use of this source code is governed by a license -// that can be found in the LICENSE file. - -import ( - "bytes" - "compress/gzip" - "compress/zlib" - "sync" -) - -// SyncPoolCompessors is a CompressorProvider that use the standard sync.Pool. -type SyncPoolCompessors struct { - GzipWriterPool *sync.Pool - GzipReaderPool *sync.Pool - ZlibWriterPool *sync.Pool -} - -// NewSyncPoolCompessors returns a new ("empty") SyncPoolCompessors. -func NewSyncPoolCompessors() *SyncPoolCompessors { - return &SyncPoolCompessors{ - GzipWriterPool: &sync.Pool{ - New: func() interface{} { return newGzipWriter() }, - }, - GzipReaderPool: &sync.Pool{ - New: func() interface{} { return newGzipReader() }, - }, - ZlibWriterPool: &sync.Pool{ - New: func() interface{} { return newZlibWriter() }, - }, - } -} - -func (s *SyncPoolCompessors) AcquireGzipWriter() *gzip.Writer { - return s.GzipWriterPool.Get().(*gzip.Writer) -} - -func (s *SyncPoolCompessors) ReleaseGzipWriter(w *gzip.Writer) { - s.GzipWriterPool.Put(w) -} - -func (s *SyncPoolCompessors) AcquireGzipReader() *gzip.Reader { - return s.GzipReaderPool.Get().(*gzip.Reader) -} - -func (s *SyncPoolCompessors) ReleaseGzipReader(r *gzip.Reader) { - s.GzipReaderPool.Put(r) -} - -func (s *SyncPoolCompessors) AcquireZlibWriter() *zlib.Writer { - return s.ZlibWriterPool.Get().(*zlib.Writer) -} - -func (s *SyncPoolCompessors) ReleaseZlibWriter(w *zlib.Writer) { - s.ZlibWriterPool.Put(w) -} - -func newGzipWriter() *gzip.Writer { - // create with an empty bytes writer; it will be replaced before using the gzipWriter - writer, err := gzip.NewWriterLevel(new(bytes.Buffer), gzip.BestSpeed) - if err != nil { - panic(err.Error()) - } - return writer -} - -func newGzipReader() *gzip.Reader { - // create with an empty reader (but with GZIP header); it will be replaced before using the gzipReader - // we can safely use currentCompressProvider because it is set on package initialization. - w := currentCompressorProvider.AcquireGzipWriter() - defer currentCompressorProvider.ReleaseGzipWriter(w) - b := new(bytes.Buffer) - w.Reset(b) - w.Flush() - w.Close() - reader, err := gzip.NewReader(bytes.NewReader(b.Bytes())) - if err != nil { - panic(err.Error()) - } - return reader -} - -func newZlibWriter() *zlib.Writer { - writer, err := zlib.NewWriterLevel(new(bytes.Buffer), gzip.BestSpeed) - if err != nil { - panic(err.Error()) - } - return writer -} diff --git a/cmd/vendor/github.com/emicklei/go-restful/compressors.go b/cmd/vendor/github.com/emicklei/go-restful/compressors.go deleted file mode 100644 index cb32f7ef53..0000000000 --- a/cmd/vendor/github.com/emicklei/go-restful/compressors.go +++ /dev/null @@ -1,54 +0,0 @@ -package restful - -// Copyright 2015 Ernest Micklei. All rights reserved. -// Use of this source code is governed by a license -// that can be found in the LICENSE file. - -import ( - "compress/gzip" - "compress/zlib" -) - -// CompressorProvider describes a component that can provider compressors for the std methods. -type CompressorProvider interface { - // Returns a *gzip.Writer which needs to be released later. - // Before using it, call Reset(). - AcquireGzipWriter() *gzip.Writer - - // Releases an aqcuired *gzip.Writer. - ReleaseGzipWriter(w *gzip.Writer) - - // Returns a *gzip.Reader which needs to be released later. - AcquireGzipReader() *gzip.Reader - - // Releases an aqcuired *gzip.Reader. - ReleaseGzipReader(w *gzip.Reader) - - // Returns a *zlib.Writer which needs to be released later. - // Before using it, call Reset(). - AcquireZlibWriter() *zlib.Writer - - // Releases an aqcuired *zlib.Writer. - ReleaseZlibWriter(w *zlib.Writer) -} - -// DefaultCompressorProvider is the actual provider of compressors (zlib or gzip). -var currentCompressorProvider CompressorProvider - -func init() { - currentCompressorProvider = NewSyncPoolCompessors() -} - -// CurrentCompressorProvider returns the current CompressorProvider. -// It is initialized using a SyncPoolCompessors. -func CurrentCompressorProvider() CompressorProvider { - return currentCompressorProvider -} - -// CompressorProvider sets the actual provider of compressors (zlib or gzip). -func SetCompressorProvider(p CompressorProvider) { - if p == nil { - panic("cannot set compressor provider to nil") - } - currentCompressorProvider = p -} diff --git a/cmd/vendor/github.com/emicklei/go-restful/constants.go b/cmd/vendor/github.com/emicklei/go-restful/constants.go deleted file mode 100644 index 203439c5e5..0000000000 --- a/cmd/vendor/github.com/emicklei/go-restful/constants.go +++ /dev/null @@ -1,30 +0,0 @@ -package restful - -// Copyright 2013 Ernest Micklei. All rights reserved. -// Use of this source code is governed by a license -// that can be found in the LICENSE file. - -const ( - MIME_XML = "application/xml" // Accept or Content-Type used in Consumes() and/or Produces() - MIME_JSON = "application/json" // Accept or Content-Type used in Consumes() and/or Produces() - MIME_OCTET = "application/octet-stream" // If Content-Type is not present in request, use the default - - HEADER_Allow = "Allow" - HEADER_Accept = "Accept" - HEADER_Origin = "Origin" - HEADER_ContentType = "Content-Type" - HEADER_LastModified = "Last-Modified" - HEADER_AcceptEncoding = "Accept-Encoding" - HEADER_ContentEncoding = "Content-Encoding" - HEADER_AccessControlExposeHeaders = "Access-Control-Expose-Headers" - HEADER_AccessControlRequestMethod = "Access-Control-Request-Method" - HEADER_AccessControlRequestHeaders = "Access-Control-Request-Headers" - HEADER_AccessControlAllowMethods = "Access-Control-Allow-Methods" - HEADER_AccessControlAllowOrigin = "Access-Control-Allow-Origin" - HEADER_AccessControlAllowCredentials = "Access-Control-Allow-Credentials" - HEADER_AccessControlAllowHeaders = "Access-Control-Allow-Headers" - HEADER_AccessControlMaxAge = "Access-Control-Max-Age" - - ENCODING_GZIP = "gzip" - ENCODING_DEFLATE = "deflate" -) diff --git a/cmd/vendor/github.com/emicklei/go-restful/container.go b/cmd/vendor/github.com/emicklei/go-restful/container.go deleted file mode 100644 index 657d5b6ddd..0000000000 --- a/cmd/vendor/github.com/emicklei/go-restful/container.go +++ /dev/null @@ -1,366 +0,0 @@ -package restful - -// Copyright 2013 Ernest Micklei. All rights reserved. -// Use of this source code is governed by a license -// that can be found in the LICENSE file. - -import ( - "bytes" - "errors" - "fmt" - "net/http" - "os" - "runtime" - "strings" - "sync" - - "github.com/emicklei/go-restful/log" -) - -// Container holds a collection of WebServices and a http.ServeMux to dispatch http requests. -// The requests are further dispatched to routes of WebServices using a RouteSelector -type Container struct { - webServicesLock sync.RWMutex - webServices []*WebService - ServeMux *http.ServeMux - isRegisteredOnRoot bool - containerFilters []FilterFunction - doNotRecover bool // default is true - recoverHandleFunc RecoverHandleFunction - serviceErrorHandleFunc ServiceErrorHandleFunction - router RouteSelector // default is a CurlyRouter (RouterJSR311 is a slower alternative) - contentEncodingEnabled bool // default is false -} - -// NewContainer creates a new Container using a new ServeMux and default router (CurlyRouter) -func NewContainer() *Container { - return &Container{ - webServices: []*WebService{}, - ServeMux: http.NewServeMux(), - isRegisteredOnRoot: false, - containerFilters: []FilterFunction{}, - doNotRecover: true, - recoverHandleFunc: logStackOnRecover, - serviceErrorHandleFunc: writeServiceError, - router: CurlyRouter{}, - contentEncodingEnabled: false} -} - -// RecoverHandleFunction declares functions that can be used to handle a panic situation. -// The first argument is what recover() returns. The second must be used to communicate an error response. -type RecoverHandleFunction func(interface{}, http.ResponseWriter) - -// RecoverHandler changes the default function (logStackOnRecover) to be called -// when a panic is detected. DoNotRecover must be have its default value (=false). -func (c *Container) RecoverHandler(handler RecoverHandleFunction) { - c.recoverHandleFunc = handler -} - -// ServiceErrorHandleFunction declares functions that can be used to handle a service error situation. -// The first argument is the service error, the second is the request that resulted in the error and -// the third must be used to communicate an error response. -type ServiceErrorHandleFunction func(ServiceError, *Request, *Response) - -// ServiceErrorHandler changes the default function (writeServiceError) to be called -// when a ServiceError is detected. -func (c *Container) ServiceErrorHandler(handler ServiceErrorHandleFunction) { - c.serviceErrorHandleFunc = handler -} - -// DoNotRecover controls whether panics will be caught to return HTTP 500. -// If set to true, Route functions are responsible for handling any error situation. -// Default value is true. -func (c *Container) DoNotRecover(doNot bool) { - c.doNotRecover = doNot -} - -// Router changes the default Router (currently CurlyRouter) -func (c *Container) Router(aRouter RouteSelector) { - c.router = aRouter -} - -// EnableContentEncoding (default=false) allows for GZIP or DEFLATE encoding of responses. -func (c *Container) EnableContentEncoding(enabled bool) { - c.contentEncodingEnabled = enabled -} - -// Add a WebService to the Container. It will detect duplicate root paths and exit in that case. -func (c *Container) Add(service *WebService) *Container { - c.webServicesLock.Lock() - defer c.webServicesLock.Unlock() - - // if rootPath was not set then lazy initialize it - if len(service.rootPath) == 0 { - service.Path("/") - } - - // cannot have duplicate root paths - for _, each := range c.webServices { - if each.RootPath() == service.RootPath() { - log.Printf("[restful] WebService with duplicate root path detected:['%v']", each) - os.Exit(1) - } - } - - // If not registered on root then add specific mapping - if !c.isRegisteredOnRoot { - c.isRegisteredOnRoot = c.addHandler(service, c.ServeMux) - } - c.webServices = append(c.webServices, service) - return c -} - -// addHandler may set a new HandleFunc for the serveMux -// this function must run inside the critical region protected by the webServicesLock. -// returns true if the function was registered on root ("/") -func (c *Container) addHandler(service *WebService, serveMux *http.ServeMux) bool { - pattern := fixedPrefixPath(service.RootPath()) - // check if root path registration is needed - if "/" == pattern || "" == pattern { - serveMux.HandleFunc("/", c.dispatch) - return true - } - // detect if registration already exists - alreadyMapped := false - for _, each := range c.webServices { - if each.RootPath() == service.RootPath() { - alreadyMapped = true - break - } - } - if !alreadyMapped { - serveMux.HandleFunc(pattern, c.dispatch) - if !strings.HasSuffix(pattern, "/") { - serveMux.HandleFunc(pattern+"/", c.dispatch) - } - } - return false -} - -func (c *Container) Remove(ws *WebService) error { - if c.ServeMux == http.DefaultServeMux { - errMsg := fmt.Sprintf("[restful] cannot remove a WebService from a Container using the DefaultServeMux: ['%v']", ws) - log.Printf(errMsg) - return errors.New(errMsg) - } - c.webServicesLock.Lock() - defer c.webServicesLock.Unlock() - // build a new ServeMux and re-register all WebServices - newServeMux := http.NewServeMux() - newServices := []*WebService{} - newIsRegisteredOnRoot := false - for _, each := range c.webServices { - if each.rootPath != ws.rootPath { - // If not registered on root then add specific mapping - if !newIsRegisteredOnRoot { - newIsRegisteredOnRoot = c.addHandler(each, newServeMux) - } - newServices = append(newServices, each) - } - } - c.webServices, c.ServeMux, c.isRegisteredOnRoot = newServices, newServeMux, newIsRegisteredOnRoot - return nil -} - -// logStackOnRecover is the default RecoverHandleFunction and is called -// when DoNotRecover is false and the recoverHandleFunc is not set for the container. -// Default implementation logs the stacktrace and writes the stacktrace on the response. -// This may be a security issue as it exposes sourcecode information. -func logStackOnRecover(panicReason interface{}, httpWriter http.ResponseWriter) { - var buffer bytes.Buffer - buffer.WriteString(fmt.Sprintf("[restful] recover from panic situation: - %v\r\n", panicReason)) - for i := 2; ; i += 1 { - _, file, line, ok := runtime.Caller(i) - if !ok { - break - } - buffer.WriteString(fmt.Sprintf(" %s:%d\r\n", file, line)) - } - log.Print(buffer.String()) - httpWriter.WriteHeader(http.StatusInternalServerError) - httpWriter.Write(buffer.Bytes()) -} - -// writeServiceError is the default ServiceErrorHandleFunction and is called -// when a ServiceError is returned during route selection. Default implementation -// calls resp.WriteErrorString(err.Code, err.Message) -func writeServiceError(err ServiceError, req *Request, resp *Response) { - resp.WriteErrorString(err.Code, err.Message) -} - -// Dispatch the incoming Http Request to a matching WebService. -func (c *Container) Dispatch(httpWriter http.ResponseWriter, httpRequest *http.Request) { - if httpWriter == nil { - panic("httpWriter cannot be nil") - } - if httpRequest == nil { - panic("httpRequest cannot be nil") - } - c.dispatch(httpWriter, httpRequest) -} - -// Dispatch the incoming Http Request to a matching WebService. -func (c *Container) dispatch(httpWriter http.ResponseWriter, httpRequest *http.Request) { - writer := httpWriter - - // CompressingResponseWriter should be closed after all operations are done - defer func() { - if compressWriter, ok := writer.(*CompressingResponseWriter); ok { - compressWriter.Close() - } - }() - - // Instal panic recovery unless told otherwise - if !c.doNotRecover { // catch all for 500 response - defer func() { - if r := recover(); r != nil { - c.recoverHandleFunc(r, writer) - return - } - }() - } - - // Detect if compression is needed - // assume without compression, test for override - if c.contentEncodingEnabled { - doCompress, encoding := wantsCompressedResponse(httpRequest) - if doCompress { - var err error - writer, err = NewCompressingResponseWriter(httpWriter, encoding) - if err != nil { - log.Print("[restful] unable to install compressor: ", err) - httpWriter.WriteHeader(http.StatusInternalServerError) - return - } - } - } - // Find best match Route ; err is non nil if no match was found - var webService *WebService - var route *Route - var err error - func() { - c.webServicesLock.RLock() - defer c.webServicesLock.RUnlock() - webService, route, err = c.router.SelectRoute( - c.webServices, - httpRequest) - }() - if err != nil { - // a non-200 response has already been written - // run container filters anyway ; they should not touch the response... - chain := FilterChain{Filters: c.containerFilters, Target: func(req *Request, resp *Response) { - switch err.(type) { - case ServiceError: - ser := err.(ServiceError) - c.serviceErrorHandleFunc(ser, req, resp) - } - // TODO - }} - chain.ProcessFilter(NewRequest(httpRequest), NewResponse(writer)) - return - } - wrappedRequest, wrappedResponse := route.wrapRequestResponse(writer, httpRequest) - // pass through filters (if any) - if len(c.containerFilters)+len(webService.filters)+len(route.Filters) > 0 { - // compose filter chain - allFilters := []FilterFunction{} - allFilters = append(allFilters, c.containerFilters...) - allFilters = append(allFilters, webService.filters...) - allFilters = append(allFilters, route.Filters...) - chain := FilterChain{Filters: allFilters, Target: func(req *Request, resp *Response) { - // handle request by route after passing all filters - route.Function(wrappedRequest, wrappedResponse) - }} - chain.ProcessFilter(wrappedRequest, wrappedResponse) - } else { - // no filters, handle request by route - route.Function(wrappedRequest, wrappedResponse) - } -} - -// fixedPrefixPath returns the fixed part of the partspec ; it may include template vars {} -func fixedPrefixPath(pathspec string) string { - varBegin := strings.Index(pathspec, "{") - if -1 == varBegin { - return pathspec - } - return pathspec[:varBegin] -} - -// ServeHTTP implements net/http.Handler therefore a Container can be a Handler in a http.Server -func (c *Container) ServeHTTP(httpwriter http.ResponseWriter, httpRequest *http.Request) { - c.ServeMux.ServeHTTP(httpwriter, httpRequest) -} - -// Handle registers the handler for the given pattern. If a handler already exists for pattern, Handle panics. -func (c *Container) Handle(pattern string, handler http.Handler) { - c.ServeMux.Handle(pattern, handler) -} - -// HandleWithFilter registers the handler for the given pattern. -// Container's filter chain is applied for handler. -// If a handler already exists for pattern, HandleWithFilter panics. -func (c *Container) HandleWithFilter(pattern string, handler http.Handler) { - f := func(httpResponse http.ResponseWriter, httpRequest *http.Request) { - if len(c.containerFilters) == 0 { - handler.ServeHTTP(httpResponse, httpRequest) - return - } - - chain := FilterChain{Filters: c.containerFilters, Target: func(req *Request, resp *Response) { - handler.ServeHTTP(httpResponse, httpRequest) - }} - chain.ProcessFilter(NewRequest(httpRequest), NewResponse(httpResponse)) - } - - c.Handle(pattern, http.HandlerFunc(f)) -} - -// Filter appends a container FilterFunction. These are called before dispatching -// a http.Request to a WebService from the container -func (c *Container) Filter(filter FilterFunction) { - c.containerFilters = append(c.containerFilters, filter) -} - -// RegisteredWebServices returns the collections of added WebServices -func (c *Container) RegisteredWebServices() []*WebService { - c.webServicesLock.RLock() - defer c.webServicesLock.RUnlock() - result := make([]*WebService, len(c.webServices)) - for ix := range c.webServices { - result[ix] = c.webServices[ix] - } - return result -} - -// computeAllowedMethods returns a list of HTTP methods that are valid for a Request -func (c *Container) computeAllowedMethods(req *Request) []string { - // Go through all RegisteredWebServices() and all its Routes to collect the options - methods := []string{} - requestPath := req.Request.URL.Path - for _, ws := range c.RegisteredWebServices() { - matches := ws.pathExpr.Matcher.FindStringSubmatch(requestPath) - if matches != nil { - finalMatch := matches[len(matches)-1] - for _, rt := range ws.Routes() { - matches := rt.pathExpr.Matcher.FindStringSubmatch(finalMatch) - if matches != nil { - lastMatch := matches[len(matches)-1] - if lastMatch == "" || lastMatch == "/" { // do not include if value is neither empty nor ‘/’. - methods = append(methods, rt.Method) - } - } - } - } - } - // methods = append(methods, "OPTIONS") not sure about this - return methods -} - -// newBasicRequestResponse creates a pair of Request,Response from its http versions. -// It is basic because no parameter or (produces) content-type information is given. -func newBasicRequestResponse(httpWriter http.ResponseWriter, httpRequest *http.Request) (*Request, *Response) { - resp := NewResponse(httpWriter) - resp.requestAccept = httpRequest.Header.Get(HEADER_Accept) - return NewRequest(httpRequest), resp -} diff --git a/cmd/vendor/github.com/emicklei/go-restful/cors_filter.go b/cmd/vendor/github.com/emicklei/go-restful/cors_filter.go deleted file mode 100644 index 1efeef072d..0000000000 --- a/cmd/vendor/github.com/emicklei/go-restful/cors_filter.go +++ /dev/null @@ -1,202 +0,0 @@ -package restful - -// Copyright 2013 Ernest Micklei. All rights reserved. -// Use of this source code is governed by a license -// that can be found in the LICENSE file. - -import ( - "regexp" - "strconv" - "strings" -) - -// CrossOriginResourceSharing is used to create a Container Filter that implements CORS. -// Cross-origin resource sharing (CORS) is a mechanism that allows JavaScript on a web page -// to make XMLHttpRequests to another domain, not the domain the JavaScript originated from. -// -// http://en.wikipedia.org/wiki/Cross-origin_resource_sharing -// http://enable-cors.org/server.html -// http://www.html5rocks.com/en/tutorials/cors/#toc-handling-a-not-so-simple-request -type CrossOriginResourceSharing struct { - ExposeHeaders []string // list of Header names - AllowedHeaders []string // list of Header names - AllowedDomains []string // list of allowed values for Http Origin. An allowed value can be a regular expression to support subdomain matching. If empty all are allowed. - AllowedMethods []string - MaxAge int // number of seconds before requiring new Options request - CookiesAllowed bool - Container *Container - - allowedOriginPatterns []*regexp.Regexp // internal field for origin regexp check. -} - -// Filter is a filter function that implements the CORS flow as documented on http://enable-cors.org/server.html -// and http://www.html5rocks.com/static/images/cors_server_flowchart.png -func (c CrossOriginResourceSharing) Filter(req *Request, resp *Response, chain *FilterChain) { - origin := req.Request.Header.Get(HEADER_Origin) - if len(origin) == 0 { - if trace { - traceLogger.Print("no Http header Origin set") - } - chain.ProcessFilter(req, resp) - return - } - if !c.isOriginAllowed(origin) { // check whether this origin is allowed - if trace { - traceLogger.Printf("HTTP Origin:%s is not part of %v, neither matches any part of %v", origin, c.AllowedDomains, c.allowedOriginPatterns) - } - chain.ProcessFilter(req, resp) - return - } - if req.Request.Method != "OPTIONS" { - c.doActualRequest(req, resp) - chain.ProcessFilter(req, resp) - return - } - if acrm := req.Request.Header.Get(HEADER_AccessControlRequestMethod); acrm != "" { - c.doPreflightRequest(req, resp) - } else { - c.doActualRequest(req, resp) - chain.ProcessFilter(req, resp) - return - } -} - -func (c CrossOriginResourceSharing) doActualRequest(req *Request, resp *Response) { - c.setOptionsHeaders(req, resp) - // continue processing the response -} - -func (c *CrossOriginResourceSharing) doPreflightRequest(req *Request, resp *Response) { - if len(c.AllowedMethods) == 0 { - if c.Container == nil { - c.AllowedMethods = DefaultContainer.computeAllowedMethods(req) - } else { - c.AllowedMethods = c.Container.computeAllowedMethods(req) - } - } - - acrm := req.Request.Header.Get(HEADER_AccessControlRequestMethod) - if !c.isValidAccessControlRequestMethod(acrm, c.AllowedMethods) { - if trace { - traceLogger.Printf("Http header %s:%s is not in %v", - HEADER_AccessControlRequestMethod, - acrm, - c.AllowedMethods) - } - return - } - acrhs := req.Request.Header.Get(HEADER_AccessControlRequestHeaders) - if len(acrhs) > 0 { - for _, each := range strings.Split(acrhs, ",") { - if !c.isValidAccessControlRequestHeader(strings.Trim(each, " ")) { - if trace { - traceLogger.Printf("Http header %s:%s is not in %v", - HEADER_AccessControlRequestHeaders, - acrhs, - c.AllowedHeaders) - } - return - } - } - } - resp.AddHeader(HEADER_AccessControlAllowMethods, strings.Join(c.AllowedMethods, ",")) - resp.AddHeader(HEADER_AccessControlAllowHeaders, acrhs) - c.setOptionsHeaders(req, resp) - - // return http 200 response, no body -} - -func (c CrossOriginResourceSharing) setOptionsHeaders(req *Request, resp *Response) { - c.checkAndSetExposeHeaders(resp) - c.setAllowOriginHeader(req, resp) - c.checkAndSetAllowCredentials(resp) - if c.MaxAge > 0 { - resp.AddHeader(HEADER_AccessControlMaxAge, strconv.Itoa(c.MaxAge)) - } -} - -func (c CrossOriginResourceSharing) isOriginAllowed(origin string) bool { - if len(origin) == 0 { - return false - } - if len(c.AllowedDomains) == 0 { - return true - } - - allowed := false - for _, domain := range c.AllowedDomains { - if domain == origin { - allowed = true - break - } - } - - if !allowed { - if len(c.allowedOriginPatterns) == 0 { - // compile allowed domains to allowed origin patterns - allowedOriginRegexps, err := compileRegexps(c.AllowedDomains) - if err != nil { - return false - } - c.allowedOriginPatterns = allowedOriginRegexps - } - - for _, pattern := range c.allowedOriginPatterns { - if allowed = pattern.MatchString(origin); allowed { - break - } - } - } - - return allowed -} - -func (c CrossOriginResourceSharing) setAllowOriginHeader(req *Request, resp *Response) { - origin := req.Request.Header.Get(HEADER_Origin) - if c.isOriginAllowed(origin) { - resp.AddHeader(HEADER_AccessControlAllowOrigin, origin) - } -} - -func (c CrossOriginResourceSharing) checkAndSetExposeHeaders(resp *Response) { - if len(c.ExposeHeaders) > 0 { - resp.AddHeader(HEADER_AccessControlExposeHeaders, strings.Join(c.ExposeHeaders, ",")) - } -} - -func (c CrossOriginResourceSharing) checkAndSetAllowCredentials(resp *Response) { - if c.CookiesAllowed { - resp.AddHeader(HEADER_AccessControlAllowCredentials, "true") - } -} - -func (c CrossOriginResourceSharing) isValidAccessControlRequestMethod(method string, allowedMethods []string) bool { - for _, each := range allowedMethods { - if each == method { - return true - } - } - return false -} - -func (c CrossOriginResourceSharing) isValidAccessControlRequestHeader(header string) bool { - for _, each := range c.AllowedHeaders { - if strings.ToLower(each) == strings.ToLower(header) { - return true - } - } - return false -} - -// Take a list of strings and compile them into a list of regular expressions. -func compileRegexps(regexpStrings []string) ([]*regexp.Regexp, error) { - regexps := []*regexp.Regexp{} - for _, regexpStr := range regexpStrings { - r, err := regexp.Compile(regexpStr) - if err != nil { - return regexps, err - } - regexps = append(regexps, r) - } - return regexps, nil -} diff --git a/cmd/vendor/github.com/emicklei/go-restful/curly.go b/cmd/vendor/github.com/emicklei/go-restful/curly.go deleted file mode 100644 index 79f1f5aa20..0000000000 --- a/cmd/vendor/github.com/emicklei/go-restful/curly.go +++ /dev/null @@ -1,164 +0,0 @@ -package restful - -// Copyright 2013 Ernest Micklei. All rights reserved. -// Use of this source code is governed by a license -// that can be found in the LICENSE file. - -import ( - "net/http" - "regexp" - "sort" - "strings" -) - -// CurlyRouter expects Routes with paths that contain zero or more parameters in curly brackets. -type CurlyRouter struct{} - -// SelectRoute is part of the Router interface and returns the best match -// for the WebService and its Route for the given Request. -func (c CurlyRouter) SelectRoute( - webServices []*WebService, - httpRequest *http.Request) (selectedService *WebService, selected *Route, err error) { - - requestTokens := tokenizePath(httpRequest.URL.Path) - - detectedService := c.detectWebService(requestTokens, webServices) - if detectedService == nil { - if trace { - traceLogger.Printf("no WebService was found to match URL path:%s\n", httpRequest.URL.Path) - } - return nil, nil, NewError(http.StatusNotFound, "404: Page Not Found") - } - candidateRoutes := c.selectRoutes(detectedService, requestTokens) - if len(candidateRoutes) == 0 { - if trace { - traceLogger.Printf("no Route in WebService with path %s was found to match URL path:%s\n", detectedService.rootPath, httpRequest.URL.Path) - } - return detectedService, nil, NewError(http.StatusNotFound, "404: Page Not Found") - } - selectedRoute, err := c.detectRoute(candidateRoutes, httpRequest) - if selectedRoute == nil { - return detectedService, nil, err - } - return detectedService, selectedRoute, nil -} - -// selectRoutes return a collection of Route from a WebService that matches the path tokens from the request. -func (c CurlyRouter) selectRoutes(ws *WebService, requestTokens []string) sortableCurlyRoutes { - candidates := sortableCurlyRoutes{} - for _, each := range ws.routes { - matches, paramCount, staticCount := c.matchesRouteByPathTokens(each.pathParts, requestTokens) - if matches { - candidates.add(curlyRoute{each, paramCount, staticCount}) // TODO make sure Routes() return pointers? - } - } - sort.Sort(sort.Reverse(candidates)) - return candidates -} - -// matchesRouteByPathTokens computes whether it matches, howmany parameters do match and what the number of static path elements are. -func (c CurlyRouter) matchesRouteByPathTokens(routeTokens, requestTokens []string) (matches bool, paramCount int, staticCount int) { - if len(routeTokens) < len(requestTokens) { - // proceed in matching only if last routeToken is wildcard - count := len(routeTokens) - if count == 0 || !strings.HasSuffix(routeTokens[count-1], "*}") { - return false, 0, 0 - } - // proceed - } - for i, routeToken := range routeTokens { - if i == len(requestTokens) { - // reached end of request path - return false, 0, 0 - } - requestToken := requestTokens[i] - if strings.HasPrefix(routeToken, "{") { - paramCount++ - if colon := strings.Index(routeToken, ":"); colon != -1 { - // match by regex - matchesToken, matchesRemainder := c.regularMatchesPathToken(routeToken, colon, requestToken) - if !matchesToken { - return false, 0, 0 - } - if matchesRemainder { - break - } - } - } else { // no { prefix - if requestToken != routeToken { - return false, 0, 0 - } - staticCount++ - } - } - return true, paramCount, staticCount -} - -// regularMatchesPathToken tests whether the regular expression part of routeToken matches the requestToken or all remaining tokens -// format routeToken is {someVar:someExpression}, e.g. {zipcode:[\d][\d][\d][\d][A-Z][A-Z]} -func (c CurlyRouter) regularMatchesPathToken(routeToken string, colon int, requestToken string) (matchesToken bool, matchesRemainder bool) { - regPart := routeToken[colon+1 : len(routeToken)-1] - if regPart == "*" { - if trace { - traceLogger.Printf("wildcard parameter detected in route token %s that matches %s\n", routeToken, requestToken) - } - return true, true - } - matched, err := regexp.MatchString(regPart, requestToken) - return (matched && err == nil), false -} - -var jsr311Router = RouterJSR311{} - -// detectRoute selectes from a list of Route the first match by inspecting both the Accept and Content-Type -// headers of the Request. See also RouterJSR311 in jsr311.go -func (c CurlyRouter) detectRoute(candidateRoutes sortableCurlyRoutes, httpRequest *http.Request) (*Route, error) { - // tracing is done inside detectRoute - return jsr311Router.detectRoute(candidateRoutes.routes(), httpRequest) -} - -// detectWebService returns the best matching webService given the list of path tokens. -// see also computeWebserviceScore -func (c CurlyRouter) detectWebService(requestTokens []string, webServices []*WebService) *WebService { - var best *WebService - score := -1 - for _, each := range webServices { - matches, eachScore := c.computeWebserviceScore(requestTokens, each.pathExpr.tokens) - if matches && (eachScore > score) { - best = each - score = eachScore - } - } - return best -} - -// computeWebserviceScore returns whether tokens match and -// the weighted score of the longest matching consecutive tokens from the beginning. -func (c CurlyRouter) computeWebserviceScore(requestTokens []string, tokens []string) (bool, int) { - if len(tokens) > len(requestTokens) { - return false, 0 - } - score := 0 - for i := 0; i < len(tokens); i++ { - each := requestTokens[i] - other := tokens[i] - if len(each) == 0 && len(other) == 0 { - score++ - continue - } - if len(other) > 0 && strings.HasPrefix(other, "{") { - // no empty match - if len(each) == 0 { - return false, score - } - score += 1 - } else { - // not a parameter - if each != other { - return false, score - } - score += (len(tokens) - i) * 10 //fuzzy - } - } - return true, score -} diff --git a/cmd/vendor/github.com/emicklei/go-restful/curly_route.go b/cmd/vendor/github.com/emicklei/go-restful/curly_route.go deleted file mode 100644 index 296f94650e..0000000000 --- a/cmd/vendor/github.com/emicklei/go-restful/curly_route.go +++ /dev/null @@ -1,52 +0,0 @@ -package restful - -// Copyright 2013 Ernest Micklei. All rights reserved. -// Use of this source code is governed by a license -// that can be found in the LICENSE file. - -// curlyRoute exits for sorting Routes by the CurlyRouter based on number of parameters and number of static path elements. -type curlyRoute struct { - route Route - paramCount int - staticCount int -} - -type sortableCurlyRoutes []curlyRoute - -func (s *sortableCurlyRoutes) add(route curlyRoute) { - *s = append(*s, route) -} - -func (s sortableCurlyRoutes) routes() (routes []Route) { - for _, each := range s { - routes = append(routes, each.route) // TODO change return type - } - return routes -} - -func (s sortableCurlyRoutes) Len() int { - return len(s) -} -func (s sortableCurlyRoutes) Swap(i, j int) { - s[i], s[j] = s[j], s[i] -} -func (s sortableCurlyRoutes) Less(i, j int) bool { - ci := s[i] - cj := s[j] - - // primary key - if ci.staticCount < cj.staticCount { - return true - } - if ci.staticCount > cj.staticCount { - return false - } - // secundary key - if ci.paramCount < cj.paramCount { - return true - } - if ci.paramCount > cj.paramCount { - return false - } - return ci.route.Path < cj.route.Path -} diff --git a/cmd/vendor/github.com/emicklei/go-restful/doc.go b/cmd/vendor/github.com/emicklei/go-restful/doc.go deleted file mode 100644 index f7c16b01fe..0000000000 --- a/cmd/vendor/github.com/emicklei/go-restful/doc.go +++ /dev/null @@ -1,185 +0,0 @@ -/* -Package restful , a lean package for creating REST-style WebServices without magic. - -WebServices and Routes - -A WebService has a collection of Route objects that dispatch incoming Http Requests to a function calls. -Typically, a WebService has a root path (e.g. /users) and defines common MIME types for its routes. -WebServices must be added to a container (see below) in order to handler Http requests from a server. - -A Route is defined by a HTTP method, an URL path and (optionally) the MIME types it consumes (Content-Type) and produces (Accept). -This package has the logic to find the best matching Route and if found, call its Function. - - ws := new(restful.WebService) - ws. - Path("/users"). - Consumes(restful.MIME_JSON, restful.MIME_XML). - Produces(restful.MIME_JSON, restful.MIME_XML) - - ws.Route(ws.GET("/{user-id}").To(u.findUser)) // u is a UserResource - - ... - - // GET http://localhost:8080/users/1 - func (u UserResource) findUser(request *restful.Request, response *restful.Response) { - id := request.PathParameter("user-id") - ... - } - -The (*Request, *Response) arguments provide functions for reading information from the request and writing information back to the response. - -See the example https://github.com/emicklei/go-restful/blob/master/examples/restful-user-resource.go with a full implementation. - -Regular expression matching Routes - -A Route parameter can be specified using the format "uri/{var[:regexp]}" or the special version "uri/{var:*}" for matching the tail of the path. -For example, /persons/{name:[A-Z][A-Z]} can be used to restrict values for the parameter "name" to only contain capital alphabetic characters. -Regular expressions must use the standard Go syntax as described in the regexp package. (https://code.google.com/p/re2/wiki/Syntax) -This feature requires the use of a CurlyRouter. - -Containers - -A Container holds a collection of WebServices, Filters and a http.ServeMux for multiplexing http requests. -Using the statements "restful.Add(...) and restful.Filter(...)" will register WebServices and Filters to the Default Container. -The Default container of go-restful uses the http.DefaultServeMux. -You can create your own Container and create a new http.Server for that particular container. - - container := restful.NewContainer() - server := &http.Server{Addr: ":8081", Handler: container} - -Filters - -A filter dynamically intercepts requests and responses to transform or use the information contained in the requests or responses. -You can use filters to perform generic logging, measurement, authentication, redirect, set response headers etc. -In the restful package there are three hooks into the request,response flow where filters can be added. -Each filter must define a FilterFunction: - - func (req *restful.Request, resp *restful.Response, chain *restful.FilterChain) - -Use the following statement to pass the request,response pair to the next filter or RouteFunction - - chain.ProcessFilter(req, resp) - -Container Filters - -These are processed before any registered WebService. - - // install a (global) filter for the default container (processed before any webservice) - restful.Filter(globalLogging) - -WebService Filters - -These are processed before any Route of a WebService. - - // install a webservice filter (processed before any route) - ws.Filter(webserviceLogging).Filter(measureTime) - - -Route Filters - -These are processed before calling the function associated with the Route. - - // install 2 chained route filters (processed before calling findUser) - ws.Route(ws.GET("/{user-id}").Filter(routeLogging).Filter(NewCountFilter().routeCounter).To(findUser)) - -See the example https://github.com/emicklei/go-restful/blob/master/examples/restful-filters.go with full implementations. - -Response Encoding - -Two encodings are supported: gzip and deflate. To enable this for all responses: - - restful.DefaultContainer.EnableContentEncoding(true) - -If a Http request includes the Accept-Encoding header then the response content will be compressed using the specified encoding. -Alternatively, you can create a Filter that performs the encoding and install it per WebService or Route. - -See the example https://github.com/emicklei/go-restful/blob/master/examples/restful-encoding-filter.go - -OPTIONS support - -By installing a pre-defined container filter, your Webservice(s) can respond to the OPTIONS Http request. - - Filter(OPTIONSFilter()) - -CORS - -By installing the filter of a CrossOriginResourceSharing (CORS), your WebService(s) can handle CORS requests. - - cors := CrossOriginResourceSharing{ExposeHeaders: []string{"X-My-Header"}, CookiesAllowed: false, Container: DefaultContainer} - Filter(cors.Filter) - -Error Handling - -Unexpected things happen. If a request cannot be processed because of a failure, your service needs to tell via the response what happened and why. -For this reason HTTP status codes exist and it is important to use the correct code in every exceptional situation. - - 400: Bad Request - -If path or query parameters are not valid (content or type) then use http.StatusBadRequest. - - 404: Not Found - -Despite a valid URI, the resource requested may not be available - - 500: Internal Server Error - -If the application logic could not process the request (or write the response) then use http.StatusInternalServerError. - - 405: Method Not Allowed - -The request has a valid URL but the method (GET,PUT,POST,...) is not allowed. - - 406: Not Acceptable - -The request does not have or has an unknown Accept Header set for this operation. - - 415: Unsupported Media Type - -The request does not have or has an unknown Content-Type Header set for this operation. - -ServiceError - -In addition to setting the correct (error) Http status code, you can choose to write a ServiceError message on the response. - -Performance options - -This package has several options that affect the performance of your service. It is important to understand them and how you can change it. - - restful.DefaultContainer.DoNotRecover(false) - -DoNotRecover controls whether panics will be caught to return HTTP 500. -If set to false, the container will recover from panics. -Default value is true - - restful.SetCompressorProvider(NewBoundedCachedCompressors(20, 20)) - -If content encoding is enabled then the default strategy for getting new gzip/zlib writers and readers is to use a sync.Pool. -Because writers are expensive structures, performance is even more improved when using a preloaded cache. You can also inject your own implementation. - -Trouble shooting - -This package has the means to produce detail logging of the complete Http request matching process and filter invocation. -Enabling this feature requires you to set an implementation of restful.StdLogger (e.g. log.Logger) instance such as: - - restful.TraceLogger(log.New(os.Stdout, "[restful] ", log.LstdFlags|log.Lshortfile)) - -Logging - -The restful.SetLogger() method allows you to override the logger used by the package. By default restful -uses the standard library `log` package and logs to stdout. Different logging packages are supported as -long as they conform to `StdLogger` interface defined in the `log` sub-package, writing an adapter for your -preferred package is simple. - -Resources - -[project]: https://github.com/emicklei/go-restful - -[examples]: https://github.com/emicklei/go-restful/blob/master/examples - -[design]: http://ernestmicklei.com/2012/11/11/go-restful-api-design/ - -[showcases]: https://github.com/emicklei/mora, https://github.com/emicklei/landskape - -(c) 2012-2015, http://ernestmicklei.com. MIT License -*/ -package restful diff --git a/cmd/vendor/github.com/emicklei/go-restful/entity_accessors.go b/cmd/vendor/github.com/emicklei/go-restful/entity_accessors.go deleted file mode 100644 index 6ecf6c7f89..0000000000 --- a/cmd/vendor/github.com/emicklei/go-restful/entity_accessors.go +++ /dev/null @@ -1,163 +0,0 @@ -package restful - -// Copyright 2015 Ernest Micklei. All rights reserved. -// Use of this source code is governed by a license -// that can be found in the LICENSE file. - -import ( - "encoding/json" - "encoding/xml" - "strings" - "sync" -) - -// EntityReaderWriter can read and write values using an encoding such as JSON,XML. -type EntityReaderWriter interface { - // Read a serialized version of the value from the request. - // The Request may have a decompressing reader. Depends on Content-Encoding. - Read(req *Request, v interface{}) error - - // Write a serialized version of the value on the response. - // The Response may have a compressing writer. Depends on Accept-Encoding. - // status should be a valid Http Status code - Write(resp *Response, status int, v interface{}) error -} - -// entityAccessRegistry is a singleton -var entityAccessRegistry = &entityReaderWriters{ - protection: new(sync.RWMutex), - accessors: map[string]EntityReaderWriter{}, -} - -// entityReaderWriters associates MIME to an EntityReaderWriter -type entityReaderWriters struct { - protection *sync.RWMutex - accessors map[string]EntityReaderWriter -} - -func init() { - RegisterEntityAccessor(MIME_JSON, NewEntityAccessorJSON(MIME_JSON)) - RegisterEntityAccessor(MIME_XML, NewEntityAccessorXML(MIME_XML)) -} - -// RegisterEntityAccessor add/overrides the ReaderWriter for encoding content with this MIME type. -func RegisterEntityAccessor(mime string, erw EntityReaderWriter) { - entityAccessRegistry.protection.Lock() - defer entityAccessRegistry.protection.Unlock() - entityAccessRegistry.accessors[mime] = erw -} - -// NewEntityAccessorJSON returns a new EntityReaderWriter for accessing JSON content. -// This package is already initialized with such an accessor using the MIME_JSON contentType. -func NewEntityAccessorJSON(contentType string) EntityReaderWriter { - return entityJSONAccess{ContentType: contentType} -} - -// NewEntityAccessorXML returns a new EntityReaderWriter for accessing XML content. -// This package is already initialized with such an accessor using the MIME_XML contentType. -func NewEntityAccessorXML(contentType string) EntityReaderWriter { - return entityXMLAccess{ContentType: contentType} -} - -// accessorAt returns the registered ReaderWriter for this MIME type. -func (r *entityReaderWriters) accessorAt(mime string) (EntityReaderWriter, bool) { - r.protection.RLock() - defer r.protection.RUnlock() - er, ok := r.accessors[mime] - if !ok { - // retry with reverse lookup - // more expensive but we are in an exceptional situation anyway - for k, v := range r.accessors { - if strings.Contains(mime, k) { - return v, true - } - } - } - return er, ok -} - -// entityXMLAccess is a EntityReaderWriter for XML encoding -type entityXMLAccess struct { - // This is used for setting the Content-Type header when writing - ContentType string -} - -// Read unmarshalls the value from XML -func (e entityXMLAccess) Read(req *Request, v interface{}) error { - return xml.NewDecoder(req.Request.Body).Decode(v) -} - -// Write marshalls the value to JSON and set the Content-Type Header. -func (e entityXMLAccess) Write(resp *Response, status int, v interface{}) error { - return writeXML(resp, status, e.ContentType, v) -} - -// writeXML marshalls the value to JSON and set the Content-Type Header. -func writeXML(resp *Response, status int, contentType string, v interface{}) error { - if v == nil { - resp.WriteHeader(status) - // do not write a nil representation - return nil - } - if resp.prettyPrint { - // pretty output must be created and written explicitly - output, err := xml.MarshalIndent(v, " ", " ") - if err != nil { - return err - } - resp.Header().Set(HEADER_ContentType, contentType) - resp.WriteHeader(status) - _, err = resp.Write([]byte(xml.Header)) - if err != nil { - return err - } - _, err = resp.Write(output) - return err - } - // not-so-pretty - resp.Header().Set(HEADER_ContentType, contentType) - resp.WriteHeader(status) - return xml.NewEncoder(resp).Encode(v) -} - -// entityJSONAccess is a EntityReaderWriter for JSON encoding -type entityJSONAccess struct { - // This is used for setting the Content-Type header when writing - ContentType string -} - -// Read unmarshalls the value from JSON -func (e entityJSONAccess) Read(req *Request, v interface{}) error { - decoder := json.NewDecoder(req.Request.Body) - decoder.UseNumber() - return decoder.Decode(v) -} - -// Write marshalls the value to JSON and set the Content-Type Header. -func (e entityJSONAccess) Write(resp *Response, status int, v interface{}) error { - return writeJSON(resp, status, e.ContentType, v) -} - -// write marshalls the value to JSON and set the Content-Type Header. -func writeJSON(resp *Response, status int, contentType string, v interface{}) error { - if v == nil { - resp.WriteHeader(status) - // do not write a nil representation - return nil - } - if resp.prettyPrint { - // pretty output must be created and written explicitly - output, err := json.MarshalIndent(v, " ", " ") - if err != nil { - return err - } - resp.Header().Set(HEADER_ContentType, contentType) - resp.WriteHeader(status) - _, err = resp.Write(output) - return err - } - // not-so-pretty - resp.Header().Set(HEADER_ContentType, contentType) - resp.WriteHeader(status) - return json.NewEncoder(resp).Encode(v) -} diff --git a/cmd/vendor/github.com/emicklei/go-restful/examples/google_app_engine/datastore/main.go b/cmd/vendor/github.com/emicklei/go-restful/examples/google_app_engine/datastore/main.go deleted file mode 100644 index 20fd15ac3d..0000000000 --- a/cmd/vendor/github.com/emicklei/go-restful/examples/google_app_engine/datastore/main.go +++ /dev/null @@ -1,267 +0,0 @@ -package main - -import ( - "net/http" - "time" - - "github.com/emicklei/go-restful" - "github.com/emicklei/go-restful-swagger12" - "google.golang.org/appengine" - "google.golang.org/appengine/datastore" - "google.golang.org/appengine/user" -) - -// This example demonstrates a reasonably complete suite of RESTful operations backed -// by DataStore on Google App Engine. - -// Our simple example struct. -type Profile struct { - LastModified time.Time `json:"-" xml:"-"` - Email string `json:"-" xml:"-"` - FirstName string `json:"first_name" xml:"first-name"` - NickName string `json:"nick_name" xml:"nick-name"` - LastName string `json:"last_name" xml:"last-name"` -} - -type ProfileApi struct { - Path string -} - -func gaeUrl() string { - if appengine.IsDevAppServer() { - return "http://localhost:8080" - } else { - // Include your URL on App Engine here. - // I found no way to get AppID without appengine.Context and this always - // based on a http.Request. - return "http://federatedservices.appspot.com" - } -} - -func init() { - u := ProfileApi{Path: "/profiles"} - u.register() - - // Optionally, you can install the Swagger Service which provides a nice Web UI on your REST API - // You need to download the Swagger HTML5 assets and change the FilePath location in the config below. - // Open .appspot.com/apidocs and enter - // Place the Swagger UI files into a folder called static/swagger if you wish to use Swagger - // http://.appspot.com/apidocs.json in the api input field. - // For testing, you can use http://localhost:8080/apidocs.json - config := swagger.Config{ - // You control what services are visible - WebServices: restful.RegisteredWebServices(), - WebServicesUrl: gaeUrl(), - ApiPath: "/apidocs.json", - - // Optionally, specifiy where the UI is located - SwaggerPath: "/apidocs/", - - // GAE support static content which is configured in your app.yaml. - // This example expect the swagger-ui in static/swagger so you should place it there :) - SwaggerFilePath: "static/swagger"} - swagger.InstallSwaggerService(config) -} - -func (u ProfileApi) register() { - ws := new(restful.WebService) - - ws. - Path(u.Path). - // You can specify consumes and produces per route as well. - Consumes(restful.MIME_JSON, restful.MIME_XML). - Produces(restful.MIME_JSON, restful.MIME_XML) - - ws.Route(ws.POST("").To(u.insert). - // Swagger documentation. - Doc("insert a new profile"). - Param(ws.BodyParameter("Profile", "representation of a profile").DataType("main.Profile")). - Reads(Profile{})) - - ws.Route(ws.GET("/{profile-id}").To(u.read). - // Swagger documentation. - Doc("read a profile"). - Param(ws.PathParameter("profile-id", "identifier for a profile").DataType("string")). - Writes(Profile{})) - - ws.Route(ws.PUT("/{profile-id}").To(u.update). - // Swagger documentation. - Doc("update an existing profile"). - Param(ws.PathParameter("profile-id", "identifier for a profile").DataType("string")). - Param(ws.BodyParameter("Profile", "representation of a profile").DataType("main.Profile")). - Reads(Profile{})) - - ws.Route(ws.DELETE("/{profile-id}").To(u.remove). - // Swagger documentation. - Doc("remove a profile"). - Param(ws.PathParameter("profile-id", "identifier for a profile").DataType("string"))) - - restful.Add(ws) -} - -// POST http://localhost:8080/profiles -// {"first_name": "Ivan", "nick_name": "Socks", "last_name": "Hawkes"} -// -func (u *ProfileApi) insert(r *restful.Request, w *restful.Response) { - c := appengine.NewContext(r.Request) - - // Marshall the entity from the request into a struct. - p := new(Profile) - err := r.ReadEntity(&p) - if err != nil { - w.WriteError(http.StatusNotAcceptable, err) - return - } - - // Ensure we start with a sensible value for this field. - p.LastModified = time.Now() - - // The profile belongs to this user. - p.Email = user.Current(c).String() - - k, err := datastore.Put(c, datastore.NewIncompleteKey(c, "profiles", nil), p) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - // Let them know the location of the newly created resource. - // TODO: Use a safe Url path append function. - w.AddHeader("Location", u.Path+"/"+k.Encode()) - - // Return the resultant entity. - w.WriteHeader(http.StatusCreated) - w.WriteEntity(p) -} - -// GET http://localhost:8080/profiles/ahdkZXZ-ZmVkZXJhdGlvbi1zZXJ2aWNlc3IVCxIIcHJvZmlsZXMYgICAgICAgAoM -// -func (u ProfileApi) read(r *restful.Request, w *restful.Response) { - c := appengine.NewContext(r.Request) - - // Decode the request parameter to determine the key for the entity. - k, err := datastore.DecodeKey(r.PathParameter("profile-id")) - if err != nil { - http.Error(w, err.Error(), http.StatusBadRequest) - return - } - - // Retrieve the entity from the datastore. - p := Profile{} - if err := datastore.Get(c, k, &p); err != nil { - if err.Error() == "datastore: no such entity" { - http.Error(w, err.Error(), http.StatusNotFound) - } else { - http.Error(w, err.Error(), http.StatusInternalServerError) - } - return - } - - // Check we own the profile before allowing them to view it. - // Optionally, return a 404 instead to help prevent guessing ids. - // TODO: Allow admins access. - if p.Email != user.Current(c).String() { - http.Error(w, "You do not have access to this resource", http.StatusForbidden) - return - } - - w.WriteEntity(p) -} - -// PUT http://localhost:8080/profiles/ahdkZXZ-ZmVkZXJhdGlvbi1zZXJ2aWNlc3IVCxIIcHJvZmlsZXMYgICAgICAgAoM -// {"first_name": "Ivan", "nick_name": "Socks", "last_name": "Hawkes"} -// -func (u *ProfileApi) update(r *restful.Request, w *restful.Response) { - c := appengine.NewContext(r.Request) - - // Decode the request parameter to determine the key for the entity. - k, err := datastore.DecodeKey(r.PathParameter("profile-id")) - if err != nil { - http.Error(w, err.Error(), http.StatusBadRequest) - return - } - - // Marshall the entity from the request into a struct. - p := new(Profile) - err = r.ReadEntity(&p) - if err != nil { - w.WriteError(http.StatusNotAcceptable, err) - return - } - - // Retrieve the old entity from the datastore. - old := Profile{} - if err := datastore.Get(c, k, &old); err != nil { - if err.Error() == "datastore: no such entity" { - http.Error(w, err.Error(), http.StatusNotFound) - } else { - http.Error(w, err.Error(), http.StatusInternalServerError) - } - return - } - - // Check we own the profile before allowing them to update it. - // Optionally, return a 404 instead to help prevent guessing ids. - // TODO: Allow admins access. - if old.Email != user.Current(c).String() { - http.Error(w, "You do not have access to this resource", http.StatusForbidden) - return - } - - // Since the whole entity is re-written, we need to assign any invariant fields again - // e.g. the owner of the entity. - p.Email = user.Current(c).String() - - // Keep track of the last modification date. - p.LastModified = time.Now() - - // Attempt to overwrite the old entity. - _, err = datastore.Put(c, k, p) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - // Let them know it succeeded. - w.WriteHeader(http.StatusNoContent) -} - -// DELETE http://localhost:8080/profiles/ahdkZXZ-ZmVkZXJhdGlvbi1zZXJ2aWNlc3IVCxIIcHJvZmlsZXMYgICAgICAgAoM -// -func (u *ProfileApi) remove(r *restful.Request, w *restful.Response) { - c := appengine.NewContext(r.Request) - - // Decode the request parameter to determine the key for the entity. - k, err := datastore.DecodeKey(r.PathParameter("profile-id")) - if err != nil { - http.Error(w, err.Error(), http.StatusBadRequest) - return - } - - // Retrieve the old entity from the datastore. - old := Profile{} - if err := datastore.Get(c, k, &old); err != nil { - if err.Error() == "datastore: no such entity" { - http.Error(w, err.Error(), http.StatusNotFound) - } else { - http.Error(w, err.Error(), http.StatusInternalServerError) - } - return - } - - // Check we own the profile before allowing them to delete it. - // Optionally, return a 404 instead to help prevent guessing ids. - // TODO: Allow admins access. - if old.Email != user.Current(c).String() { - http.Error(w, "You do not have access to this resource", http.StatusForbidden) - return - } - - // Delete the entity. - if err := datastore.Delete(c, k); err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - } - - // Success notification. - w.WriteHeader(http.StatusNoContent) -} diff --git a/cmd/vendor/github.com/emicklei/go-restful/examples/google_app_engine/restful-appstats-integration.go b/cmd/vendor/github.com/emicklei/go-restful/examples/google_app_engine/restful-appstats-integration.go deleted file mode 100644 index a871133b02..0000000000 --- a/cmd/vendor/github.com/emicklei/go-restful/examples/google_app_engine/restful-appstats-integration.go +++ /dev/null @@ -1,12 +0,0 @@ -package main - -import ( - "github.com/mjibson/appstats" -) - -func stats(req *restful.Request, resp *restful.Response, chain *restful.FilterChain) { - c := appstats.NewContext(req.Request) - chain.ProcessFilter(req, resp) - c.Stats.Status = resp.StatusCode() - c.Save() -} diff --git a/cmd/vendor/github.com/emicklei/go-restful/examples/google_app_engine/restful-user-service.go b/cmd/vendor/github.com/emicklei/go-restful/examples/google_app_engine/restful-user-service.go deleted file mode 100644 index 7286ba2fa2..0000000000 --- a/cmd/vendor/github.com/emicklei/go-restful/examples/google_app_engine/restful-user-service.go +++ /dev/null @@ -1,162 +0,0 @@ -package main - -import ( - "net/http" - - "github.com/emicklei/go-restful" - "github.com/emicklei/go-restful-swagger12" - "google.golang.org/appengine" - "google.golang.org/appengine/memcache" -) - -// This example is functionally the same as ../restful-user-service.go -// but it`s supposed to run on Goole App Engine (GAE) -// -// contributed by ivanhawkes - -type User struct { - Id, Name string -} - -type UserService struct { - // normally one would use DAO (data access object) - // but in this example we simple use memcache. -} - -func (u UserService) Register() { - ws := new(restful.WebService) - - ws. - Path("/users"). - Consumes(restful.MIME_XML, restful.MIME_JSON). - Produces(restful.MIME_JSON, restful.MIME_XML) // you can specify this per route as well - - ws.Route(ws.GET("/{user-id}").To(u.findUser). - // docs - Doc("get a user"). - Param(ws.PathParameter("user-id", "identifier of the user").DataType("string")). - Writes(User{})) // on the response - - ws.Route(ws.PATCH("").To(u.updateUser). - // docs - Doc("update a user"). - Reads(User{})) // from the request - - ws.Route(ws.PUT("/{user-id}").To(u.createUser). - // docs - Doc("create a user"). - Param(ws.PathParameter("user-id", "identifier of the user").DataType("string")). - Reads(User{})) // from the request - - ws.Route(ws.DELETE("/{user-id}").To(u.removeUser). - // docs - Doc("delete a user"). - Param(ws.PathParameter("user-id", "identifier of the user").DataType("string"))) - - restful.Add(ws) -} - -// GET http://localhost:8080/users/1 -// -func (u UserService) findUser(request *restful.Request, response *restful.Response) { - c := appengine.NewContext(request.Request) - id := request.PathParameter("user-id") - usr := new(User) - _, err := memcache.Gob.Get(c, id, &usr) - if err != nil || len(usr.Id) == 0 { - response.WriteErrorString(http.StatusNotFound, "User could not be found.") - } else { - response.WriteEntity(usr) - } -} - -// PATCH http://localhost:8080/users -// 1Melissa Raspberry -// -func (u *UserService) updateUser(request *restful.Request, response *restful.Response) { - c := appengine.NewContext(request.Request) - usr := new(User) - err := request.ReadEntity(&usr) - if err == nil { - item := &memcache.Item{ - Key: usr.Id, - Object: &usr, - } - err = memcache.Gob.Set(c, item) - if err != nil { - response.WriteError(http.StatusInternalServerError, err) - return - } - response.WriteEntity(usr) - } else { - response.WriteError(http.StatusInternalServerError, err) - } -} - -// PUT http://localhost:8080/users/1 -// 1Melissa -// -func (u *UserService) createUser(request *restful.Request, response *restful.Response) { - c := appengine.NewContext(request.Request) - usr := User{Id: request.PathParameter("user-id")} - err := request.ReadEntity(&usr) - if err == nil { - item := &memcache.Item{ - Key: usr.Id, - Object: &usr, - } - err = memcache.Gob.Add(c, item) - if err != nil { - response.WriteError(http.StatusInternalServerError, err) - return - } - response.WriteHeader(http.StatusCreated) - response.WriteEntity(usr) - } else { - response.WriteError(http.StatusInternalServerError, err) - } -} - -// DELETE http://localhost:8080/users/1 -// -func (u *UserService) removeUser(request *restful.Request, response *restful.Response) { - c := appengine.NewContext(request.Request) - id := request.PathParameter("user-id") - err := memcache.Delete(c, id) - if err != nil { - response.WriteError(http.StatusInternalServerError, err) - } -} - -func getGaeURL() string { - if appengine.IsDevAppServer() { - return "http://localhost:8080" - } else { - /** - * Include your URL on App Engine here. - * I found no way to get AppID without appengine.Context and this always - * based on a http.Request. - */ - return "http://.appspot.com" - } -} - -func init() { - u := UserService{} - u.Register() - - // Optionally, you can install the Swagger Service which provides a nice Web UI on your REST API - // You need to download the Swagger HTML5 assets and change the FilePath location in the config below. - // Open .appspot.com/apidocs and enter http://.appspot.com/apidocs.json in the api input field. - config := swagger.Config{ - WebServices: restful.RegisteredWebServices(), // you control what services are visible - WebServicesUrl: getGaeURL(), - ApiPath: "/apidocs.json", - - // Optionally, specifiy where the UI is located - SwaggerPath: "/apidocs/", - // GAE support static content which is configured in your app.yaml. - // This example expect the swagger-ui in static/swagger so you should place it there :) - SwaggerFilePath: "static/swagger"} - swagger.InstallSwaggerService(config) -} diff --git a/cmd/vendor/github.com/emicklei/go-restful/examples/msgpack/msgpack_entity.go b/cmd/vendor/github.com/emicklei/go-restful/examples/msgpack/msgpack_entity.go deleted file mode 100644 index 330e45896e..0000000000 --- a/cmd/vendor/github.com/emicklei/go-restful/examples/msgpack/msgpack_entity.go +++ /dev/null @@ -1,34 +0,0 @@ -package restPack - -import ( - restful "github.com/emicklei/go-restful" - "gopkg.in/vmihailenco/msgpack.v2" -) - -const MIME_MSGPACK = "application/x-msgpack" // Accept or Content-Type used in Consumes() and/or Produces() - -// NewEntityAccessorMPack returns a new EntityReaderWriter for accessing MessagePack content. -// This package is not initialized with such an accessor using the MIME_MSGPACK contentType. -func NewEntityAccessorMsgPack() restful.EntityReaderWriter { - return entityMsgPackAccess{} -} - -// entityOctetAccess is a EntityReaderWriter for Octet encoding -type entityMsgPackAccess struct { -} - -// Read unmarshalls the value from byte slice and using msgpack to unmarshal -func (e entityMsgPackAccess) Read(req *restful.Request, v interface{}) error { - return msgpack.NewDecoder(req.Request.Body).Decode(v) -} - -// Write marshals the value to byte slice and set the Content-Type Header. -func (e entityMsgPackAccess) Write(resp *restful.Response, status int, v interface{}) error { - if v == nil { - resp.WriteHeader(status) - // do not write a nil representation - return nil - } - resp.WriteHeader(status) - return msgpack.NewEncoder(resp).Encode(v) -} diff --git a/cmd/vendor/github.com/emicklei/go-restful/examples/restful-CORS-filter.go b/cmd/vendor/github.com/emicklei/go-restful/examples/restful-CORS-filter.go deleted file mode 100644 index 6419d25381..0000000000 --- a/cmd/vendor/github.com/emicklei/go-restful/examples/restful-CORS-filter.go +++ /dev/null @@ -1,68 +0,0 @@ -package main - -import ( - "io" - "log" - "net/http" - - "github.com/emicklei/go-restful" -) - -// Cross-origin resource sharing (CORS) is a mechanism that allows JavaScript on a web page -// to make XMLHttpRequests to another domain, not the domain the JavaScript originated from. -// -// http://en.wikipedia.org/wiki/Cross-origin_resource_sharing -// http://enable-cors.org/server.html -// -// GET http://localhost:8080/users -// -// GET http://localhost:8080/users/1 -// -// PUT http://localhost:8080/users/1 -// -// DELETE http://localhost:8080/users/1 -// -// OPTIONS http://localhost:8080/users/1 with Header "Origin" set to some domain and - -type UserResource struct{} - -func (u UserResource) RegisterTo(container *restful.Container) { - ws := new(restful.WebService) - ws. - Path("/users"). - Consumes("*/*"). - Produces("*/*") - - ws.Route(ws.GET("/{user-id}").To(u.nop)) - ws.Route(ws.POST("").To(u.nop)) - ws.Route(ws.PUT("/{user-id}").To(u.nop)) - ws.Route(ws.DELETE("/{user-id}").To(u.nop)) - - container.Add(ws) -} - -func (u UserResource) nop(request *restful.Request, response *restful.Response) { - io.WriteString(response.ResponseWriter, "this would be a normal response") -} - -func main() { - wsContainer := restful.NewContainer() - u := UserResource{} - u.RegisterTo(wsContainer) - - // Add container filter to enable CORS - cors := restful.CrossOriginResourceSharing{ - ExposeHeaders: []string{"X-My-Header"}, - AllowedHeaders: []string{"Content-Type", "Accept"}, - AllowedMethods: []string{"GET", "POST"}, - CookiesAllowed: false, - Container: wsContainer} - wsContainer.Filter(cors.Filter) - - // Add container filter to respond to OPTIONS - wsContainer.Filter(wsContainer.OPTIONSFilter) - - log.Printf("start listening on localhost:8080") - server := &http.Server{Addr: ":8080", Handler: wsContainer} - log.Fatal(server.ListenAndServe()) -} diff --git a/cmd/vendor/github.com/emicklei/go-restful/examples/restful-NCSA-logging.go b/cmd/vendor/github.com/emicklei/go-restful/examples/restful-NCSA-logging.go deleted file mode 100644 index 0cda50d342..0000000000 --- a/cmd/vendor/github.com/emicklei/go-restful/examples/restful-NCSA-logging.go +++ /dev/null @@ -1,54 +0,0 @@ -package main - -import ( - "github.com/emicklei/go-restful" - "io" - "log" - "net/http" - "os" - "strings" - "time" -) - -// This example shows how to create a filter that produces log lines -// according to the Common Log Format, also known as the NCSA standard. -// -// kindly contributed by leehambley -// -// GET http://localhost:8080/ping - -var logger *log.Logger = log.New(os.Stdout, "", 0) - -func NCSACommonLogFormatLogger() restful.FilterFunction { - return func(req *restful.Request, resp *restful.Response, chain *restful.FilterChain) { - var username = "-" - if req.Request.URL.User != nil { - if name := req.Request.URL.User.Username(); name != "" { - username = name - } - } - chain.ProcessFilter(req, resp) - logger.Printf("%s - %s [%s] \"%s %s %s\" %d %d", - strings.Split(req.Request.RemoteAddr, ":")[0], - username, - time.Now().Format("02/Jan/2006:15:04:05 -0700"), - req.Request.Method, - req.Request.URL.RequestURI(), - req.Request.Proto, - resp.StatusCode(), - resp.ContentLength(), - ) - } -} - -func main() { - ws := new(restful.WebService) - ws.Filter(NCSACommonLogFormatLogger()) - ws.Route(ws.GET("/ping").To(hello)) - restful.Add(ws) - http.ListenAndServe(":8080", nil) -} - -func hello(req *restful.Request, resp *restful.Response) { - io.WriteString(resp, "pong") -} diff --git a/cmd/vendor/github.com/emicklei/go-restful/examples/restful-basic-authentication.go b/cmd/vendor/github.com/emicklei/go-restful/examples/restful-basic-authentication.go deleted file mode 100644 index 5dd3067e95..0000000000 --- a/cmd/vendor/github.com/emicklei/go-restful/examples/restful-basic-authentication.go +++ /dev/null @@ -1,35 +0,0 @@ -package main - -import ( - "github.com/emicklei/go-restful" - "io" - "net/http" -) - -// This example shows how to create a (Route) Filter that performs Basic Authentication on the Http request. -// -// GET http://localhost:8080/secret -// and use admin,admin for the credentials - -func main() { - ws := new(restful.WebService) - ws.Route(ws.GET("/secret").Filter(basicAuthenticate).To(secret)) - restful.Add(ws) - http.ListenAndServe(":8080", nil) -} - -func basicAuthenticate(req *restful.Request, resp *restful.Response, chain *restful.FilterChain) { - encoded := req.Request.Header.Get("Authorization") - // usr/pwd = admin/admin - // real code does some decoding - if len(encoded) == 0 || "Basic YWRtaW46YWRtaW4=" != encoded { - resp.AddHeader("WWW-Authenticate", "Basic realm=Protected Area") - resp.WriteErrorString(401, "401: Not Authorized") - return - } - chain.ProcessFilter(req, resp) -} - -func secret(req *restful.Request, resp *restful.Response) { - io.WriteString(resp, "42") -} diff --git a/cmd/vendor/github.com/emicklei/go-restful/examples/restful-cpuprofiler-service.go b/cmd/vendor/github.com/emicklei/go-restful/examples/restful-cpuprofiler-service.go deleted file mode 100644 index 9148213cf0..0000000000 --- a/cmd/vendor/github.com/emicklei/go-restful/examples/restful-cpuprofiler-service.go +++ /dev/null @@ -1,65 +0,0 @@ -package main - -import ( - "github.com/emicklei/go-restful" - "io" - "log" - "os" - "runtime/pprof" -) - -// ProfilingService is a WebService that can start/stop a CPU profile and write results to a file -// GET /{rootPath}/start will activate CPU profiling -// GET /{rootPath}/stop will stop profiling -// -// NewProfileService("/profiler", "ace.prof").AddWebServiceTo(restful.DefaultContainer) -// -type ProfilingService struct { - rootPath string // the base (root) of the service, e.g. /profiler - cpuprofile string // the output filename to write profile results, e.g. myservice.prof - cpufile *os.File // if not nil, then profiling is active -} - -func NewProfileService(rootPath string, outputFilename string) *ProfilingService { - ps := new(ProfilingService) - ps.rootPath = rootPath - ps.cpuprofile = outputFilename - return ps -} - -// Add this ProfileService to a restful Container -func (p ProfilingService) AddWebServiceTo(container *restful.Container) { - ws := new(restful.WebService) - ws.Path(p.rootPath).Consumes("*/*").Produces(restful.MIME_JSON) - ws.Route(ws.GET("/start").To(p.startProfiler)) - ws.Route(ws.GET("/stop").To(p.stopProfiler)) - container.Add(ws) -} - -func (p *ProfilingService) startProfiler(req *restful.Request, resp *restful.Response) { - if p.cpufile != nil { - io.WriteString(resp.ResponseWriter, "[restful] CPU profiling already running") - return // error? - } - cpufile, err := os.Create(p.cpuprofile) - if err != nil { - log.Fatal(err) - } - // remember for close - p.cpufile = cpufile - pprof.StartCPUProfile(cpufile) - io.WriteString(resp.ResponseWriter, "[restful] CPU profiling started, writing on:"+p.cpuprofile) -} - -func (p *ProfilingService) stopProfiler(req *restful.Request, resp *restful.Response) { - if p.cpufile == nil { - io.WriteString(resp.ResponseWriter, "[restful] CPU profiling not active") - return // error? - } - pprof.StopCPUProfile() - p.cpufile.Close() - p.cpufile = nil - io.WriteString(resp.ResponseWriter, "[restful] CPU profiling stopped, closing:"+p.cpuprofile) -} - -func main() {} // exists for example compilation only diff --git a/cmd/vendor/github.com/emicklei/go-restful/examples/restful-curly-router.go b/cmd/vendor/github.com/emicklei/go-restful/examples/restful-curly-router.go deleted file mode 100644 index 26da2f1c7f..0000000000 --- a/cmd/vendor/github.com/emicklei/go-restful/examples/restful-curly-router.go +++ /dev/null @@ -1,107 +0,0 @@ -package main - -import ( - "log" - "net/http" - - "github.com/emicklei/go-restful" -) - -// This example has the same service definition as restful-user-resource -// but uses a different router (CurlyRouter) that does not use regular expressions -// -// POST http://localhost:8080/users -// 1Melissa Raspberry -// -// GET http://localhost:8080/users/1 -// -// PUT http://localhost:8080/users/1 -// 1Melissa -// -// DELETE http://localhost:8080/users/1 -// - -type User struct { - Id, Name string -} - -type UserResource struct { - // normally one would use DAO (data access object) - users map[string]User -} - -func (u UserResource) Register(container *restful.Container) { - ws := new(restful.WebService) - ws. - Path("/users"). - Consumes(restful.MIME_XML, restful.MIME_JSON). - Produces(restful.MIME_JSON, restful.MIME_XML) // you can specify this per route as well - - ws.Route(ws.GET("/{user-id}").To(u.findUser)) - ws.Route(ws.POST("").To(u.updateUser)) - ws.Route(ws.PUT("/{user-id}").To(u.createUser)) - ws.Route(ws.DELETE("/{user-id}").To(u.removeUser)) - - container.Add(ws) -} - -// GET http://localhost:8080/users/1 -// -func (u UserResource) findUser(request *restful.Request, response *restful.Response) { - id := request.PathParameter("user-id") - usr := u.users[id] - if len(usr.Id) == 0 { - response.AddHeader("Content-Type", "text/plain") - response.WriteErrorString(http.StatusNotFound, "User could not be found.") - } else { - response.WriteEntity(usr) - } -} - -// POST http://localhost:8080/users -// 1Melissa Raspberry -// -func (u *UserResource) updateUser(request *restful.Request, response *restful.Response) { - usr := new(User) - err := request.ReadEntity(&usr) - if err == nil { - u.users[usr.Id] = *usr - response.WriteEntity(usr) - } else { - response.AddHeader("Content-Type", "text/plain") - response.WriteErrorString(http.StatusInternalServerError, err.Error()) - } -} - -// PUT http://localhost:8080/users/1 -// 1Melissa -// -func (u *UserResource) createUser(request *restful.Request, response *restful.Response) { - usr := User{Id: request.PathParameter("user-id")} - err := request.ReadEntity(&usr) - if err == nil { - u.users[usr.Id] = usr - response.WriteHeaderAndEntity(http.StatusCreated, usr) - } else { - response.AddHeader("Content-Type", "text/plain") - response.WriteErrorString(http.StatusInternalServerError, err.Error()) - } -} - -// DELETE http://localhost:8080/users/1 -// -func (u *UserResource) removeUser(request *restful.Request, response *restful.Response) { - id := request.PathParameter("user-id") - delete(u.users, id) -} - -func main() { - wsContainer := restful.NewContainer() - wsContainer.Router(restful.CurlyRouter{}) - u := UserResource{map[string]User{}} - u.Register(wsContainer) - - log.Printf("start listening on localhost:8080") - server := &http.Server{Addr: ":8080", Handler: wsContainer} - log.Fatal(server.ListenAndServe()) -} diff --git a/cmd/vendor/github.com/emicklei/go-restful/examples/restful-encoding-filter.go b/cmd/vendor/github.com/emicklei/go-restful/examples/restful-encoding-filter.go deleted file mode 100644 index 6094c49092..0000000000 --- a/cmd/vendor/github.com/emicklei/go-restful/examples/restful-encoding-filter.go +++ /dev/null @@ -1,61 +0,0 @@ -package main - -import ( - "github.com/emicklei/go-restful" - "log" - "net/http" -) - -type User struct { - Id, Name string -} - -type UserList struct { - Users []User -} - -// -// This example shows how to use the CompressingResponseWriter by a Filter -// such that encoding can be enabled per WebService or per Route (instead of per container) -// Using restful.DefaultContainer.EnableContentEncoding(true) will encode all responses served by WebServices in the DefaultContainer. -// -// Set Accept-Encoding to gzip or deflate -// GET http://localhost:8080/users/42 -// and look at the response headers - -func main() { - restful.Add(NewUserService()) - log.Printf("start listening on localhost:8080") - log.Fatal(http.ListenAndServe(":8080", nil)) -} - -func NewUserService() *restful.WebService { - ws := new(restful.WebService) - ws. - Path("/users"). - Consumes(restful.MIME_XML, restful.MIME_JSON). - Produces(restful.MIME_JSON, restful.MIME_XML) - - // install a response encoding filter - ws.Route(ws.GET("/{user-id}").Filter(encodingFilter).To(findUser)) - return ws -} - -// Route Filter (defines FilterFunction) -func encodingFilter(req *restful.Request, resp *restful.Response, chain *restful.FilterChain) { - log.Printf("[encoding-filter] %s,%s\n", req.Request.Method, req.Request.URL) - // wrap responseWriter into a compressing one - compress, _ := restful.NewCompressingResponseWriter(resp.ResponseWriter, restful.ENCODING_GZIP) - resp.ResponseWriter = compress - defer func() { - compress.Close() - }() - chain.ProcessFilter(req, resp) -} - -// GET http://localhost:8080/users/42 -// -func findUser(request *restful.Request, response *restful.Response) { - log.Printf("findUser") - response.WriteEntity(User{"42", "Gandalf"}) -} diff --git a/cmd/vendor/github.com/emicklei/go-restful/examples/restful-filters.go b/cmd/vendor/github.com/emicklei/go-restful/examples/restful-filters.go deleted file mode 100644 index 478aceacef..0000000000 --- a/cmd/vendor/github.com/emicklei/go-restful/examples/restful-filters.go +++ /dev/null @@ -1,114 +0,0 @@ -package main - -import ( - "github.com/emicklei/go-restful" - "log" - "net/http" - "time" -) - -type User struct { - Id, Name string -} - -type UserList struct { - Users []User -} - -// This example show how to create and use the three different Filters (Container,WebService and Route) -// When applied to the restful.DefaultContainer, we refer to them as a global filter. -// -// GET http://locahost:8080/users/42 -// and see the logging per filter (try repeating this request) - -func main() { - // install a global (=DefaultContainer) filter (processed before any webservice in the DefaultContainer) - restful.Filter(globalLogging) - - restful.Add(NewUserService()) - log.Printf("start listening on localhost:8080") - log.Fatal(http.ListenAndServe(":8080", nil)) -} - -func NewUserService() *restful.WebService { - ws := new(restful.WebService) - ws. - Path("/users"). - Consumes(restful.MIME_XML, restful.MIME_JSON). - Produces(restful.MIME_JSON, restful.MIME_XML) - - // install a webservice filter (processed before any route) - ws.Filter(webserviceLogging).Filter(measureTime) - - // install a counter filter - ws.Route(ws.GET("").Filter(NewCountFilter().routeCounter).To(getAllUsers)) - - // install 2 chained route filters (processed before calling findUser) - ws.Route(ws.GET("/{user-id}").Filter(routeLogging).Filter(NewCountFilter().routeCounter).To(findUser)) - return ws -} - -// Global Filter -func globalLogging(req *restful.Request, resp *restful.Response, chain *restful.FilterChain) { - log.Printf("[global-filter (logger)] %s,%s\n", req.Request.Method, req.Request.URL) - chain.ProcessFilter(req, resp) -} - -// WebService Filter -func webserviceLogging(req *restful.Request, resp *restful.Response, chain *restful.FilterChain) { - log.Printf("[webservice-filter (logger)] %s,%s\n", req.Request.Method, req.Request.URL) - chain.ProcessFilter(req, resp) -} - -// WebService (post-process) Filter (as a struct that defines a FilterFunction) -func measureTime(req *restful.Request, resp *restful.Response, chain *restful.FilterChain) { - now := time.Now() - chain.ProcessFilter(req, resp) - log.Printf("[webservice-filter (timer)] %v\n", time.Now().Sub(now)) -} - -// Route Filter (defines FilterFunction) -func routeLogging(req *restful.Request, resp *restful.Response, chain *restful.FilterChain) { - log.Printf("[route-filter (logger)] %s,%s\n", req.Request.Method, req.Request.URL) - chain.ProcessFilter(req, resp) -} - -// Route Filter (as a struct that defines a FilterFunction) -// CountFilter implements a FilterFunction for counting requests. -type CountFilter struct { - count int - counter chan int // for go-routine safe count increments -} - -// NewCountFilter creates and initializes a new CountFilter. -func NewCountFilter() *CountFilter { - c := new(CountFilter) - c.counter = make(chan int) - go func() { - for { - c.count += <-c.counter - } - }() - return c -} - -// routeCounter increments the count of the filter (through a channel) -func (c *CountFilter) routeCounter(req *restful.Request, resp *restful.Response, chain *restful.FilterChain) { - c.counter <- 1 - log.Printf("[route-filter (counter)] count:%d", c.count) - chain.ProcessFilter(req, resp) -} - -// GET http://localhost:8080/users -// -func getAllUsers(request *restful.Request, response *restful.Response) { - log.Printf("getAllUsers") - response.WriteEntity(UserList{[]User{{"42", "Gandalf"}, {"3.14", "Pi"}}}) -} - -// GET http://localhost:8080/users/42 -// -func findUser(request *restful.Request, response *restful.Response) { - log.Printf("findUser") - response.WriteEntity(User{"42", "Gandalf"}) -} diff --git a/cmd/vendor/github.com/emicklei/go-restful/examples/restful-form-handling.go b/cmd/vendor/github.com/emicklei/go-restful/examples/restful-form-handling.go deleted file mode 100644 index a83db4492a..0000000000 --- a/cmd/vendor/github.com/emicklei/go-restful/examples/restful-form-handling.go +++ /dev/null @@ -1,62 +0,0 @@ -package main - -import ( - "fmt" - "github.com/emicklei/go-restful" - "github.com/gorilla/schema" - "io" - "net/http" -) - -// This example shows how to handle a POST of a HTML form that uses the standard x-www-form-urlencoded content-type. -// It uses the gorilla web tool kit schema package to decode the form data into a struct. -// -// GET http://localhost:8080/profiles -// - -type Profile struct { - Name string - Age int -} - -var decoder *schema.Decoder - -func main() { - decoder = schema.NewDecoder() - ws := new(restful.WebService) - ws.Route(ws.POST("/profiles").Consumes("application/x-www-form-urlencoded").To(postAdddress)) - ws.Route(ws.GET("/profiles").To(addresssForm)) - restful.Add(ws) - http.ListenAndServe(":8080", nil) -} - -func postAdddress(req *restful.Request, resp *restful.Response) { - err := req.Request.ParseForm() - if err != nil { - resp.WriteErrorString(http.StatusBadRequest, err.Error()) - return - } - p := new(Profile) - err = decoder.Decode(p, req.Request.PostForm) - if err != nil { - resp.WriteErrorString(http.StatusBadRequest, err.Error()) - return - } - io.WriteString(resp.ResponseWriter, fmt.Sprintf("Name=%s, Age=%d", p.Name, p.Age)) -} - -func addresssForm(req *restful.Request, resp *restful.Response) { - io.WriteString(resp.ResponseWriter, - ` - -

Enter Profile

-
- - - - - -
- - `) -} diff --git a/cmd/vendor/github.com/emicklei/go-restful/examples/restful-hello-world.go b/cmd/vendor/github.com/emicklei/go-restful/examples/restful-hello-world.go deleted file mode 100644 index a21c2a69c1..0000000000 --- a/cmd/vendor/github.com/emicklei/go-restful/examples/restful-hello-world.go +++ /dev/null @@ -1,22 +0,0 @@ -package main - -import ( - "github.com/emicklei/go-restful" - "io" - "net/http" -) - -// This example shows the minimal code needed to get a restful.WebService working. -// -// GET http://localhost:8080/hello - -func main() { - ws := new(restful.WebService) - ws.Route(ws.GET("/hello").To(hello)) - restful.Add(ws) - http.ListenAndServe(":8080", nil) -} - -func hello(req *restful.Request, resp *restful.Response) { - io.WriteString(resp, "world") -} diff --git a/cmd/vendor/github.com/emicklei/go-restful/examples/restful-html-template.go b/cmd/vendor/github.com/emicklei/go-restful/examples/restful-html-template.go deleted file mode 100644 index de51c5919f..0000000000 --- a/cmd/vendor/github.com/emicklei/go-restful/examples/restful-html-template.go +++ /dev/null @@ -1,35 +0,0 @@ -package main - -import ( - "log" - "net/http" - "text/template" - - "github.com/emicklei/go-restful" -) - -// This example shows how to serve a HTML page using the standard Go template engine. -// -// GET http://localhost:8080/ - -func main() { - ws := new(restful.WebService) - ws.Route(ws.GET("/").To(home)) - restful.Add(ws) - print("open browser on http://localhost:8080/\n") - http.ListenAndServe(":8080", nil) -} - -type Message struct { - Text string -} - -func home(req *restful.Request, resp *restful.Response) { - p := &Message{"restful-html-template demo"} - // you might want to cache compiled templates - t, err := template.ParseFiles("home.html") - if err != nil { - log.Fatalf("Template gave: %s", err) - } - t.Execute(resp.ResponseWriter, p) -} diff --git a/cmd/vendor/github.com/emicklei/go-restful/examples/restful-multi-containers.go b/cmd/vendor/github.com/emicklei/go-restful/examples/restful-multi-containers.go deleted file mode 100644 index 3f1650b36f..0000000000 --- a/cmd/vendor/github.com/emicklei/go-restful/examples/restful-multi-containers.go +++ /dev/null @@ -1,43 +0,0 @@ -package main - -import ( - "github.com/emicklei/go-restful" - "io" - "log" - "net/http" -) - -// This example shows how to have a program with 2 WebServices containers -// each having a http server listening on its own port. -// -// The first "hello" is added to the restful.DefaultContainer (and uses DefaultServeMux) -// For the second "hello", a new container and ServeMux is created -// and requires a new http.Server with the container being the Handler. -// This first server is spawn in its own go-routine such that the program proceeds to create the second. -// -// GET http://localhost:8080/hello -// GET http://localhost:8081/hello - -func main() { - ws := new(restful.WebService) - ws.Route(ws.GET("/hello").To(hello)) - restful.Add(ws) - go func() { - http.ListenAndServe(":8080", nil) - }() - - container2 := restful.NewContainer() - ws2 := new(restful.WebService) - ws2.Route(ws2.GET("/hello").To(hello2)) - container2.Add(ws2) - server := &http.Server{Addr: ":8081", Handler: container2} - log.Fatal(server.ListenAndServe()) -} - -func hello(req *restful.Request, resp *restful.Response) { - io.WriteString(resp, "default world") -} - -func hello2(req *restful.Request, resp *restful.Response) { - io.WriteString(resp, "second world") -} diff --git a/cmd/vendor/github.com/emicklei/go-restful/examples/restful-no-cache-filter.go b/cmd/vendor/github.com/emicklei/go-restful/examples/restful-no-cache-filter.go deleted file mode 100644 index 2af932a167..0000000000 --- a/cmd/vendor/github.com/emicklei/go-restful/examples/restful-no-cache-filter.go +++ /dev/null @@ -1,24 +0,0 @@ -package main - -import ( - "io" - "net/http" - - "github.com/emicklei/go-restful" -) - -// This example shows how to use a WebService filter that passed the Http headers to disable browser cacheing. -// -// GET http://localhost:8080/hello - -func main() { - ws := new(restful.WebService) - ws.Filter(restful.NoBrowserCacheFilter) - ws.Route(ws.GET("/hello").To(hello)) - restful.Add(ws) - http.ListenAndServe(":8080", nil) -} - -func hello(req *restful.Request, resp *restful.Response) { - io.WriteString(resp, "world") -} diff --git a/cmd/vendor/github.com/emicklei/go-restful/examples/restful-options-filter.go b/cmd/vendor/github.com/emicklei/go-restful/examples/restful-options-filter.go deleted file mode 100644 index 73dc3cfe5a..0000000000 --- a/cmd/vendor/github.com/emicklei/go-restful/examples/restful-options-filter.go +++ /dev/null @@ -1,51 +0,0 @@ -package main - -import ( - "github.com/emicklei/go-restful" - "io" - "log" - "net/http" -) - -// This example shows how to use the OPTIONSFilter on a Container -// -// OPTIONS http://localhost:8080/users -// -// OPTIONS http://localhost:8080/users/1 - -type UserResource struct{} - -func (u UserResource) RegisterTo(container *restful.Container) { - ws := new(restful.WebService) - ws. - Path("/users"). - Consumes("*/*"). - Produces("*/*") - - ws.Route(ws.GET("/{user-id}").To(u.nop)) - ws.Route(ws.POST("").To(u.nop)) - ws.Route(ws.PUT("/{user-id}").To(u.nop)) - ws.Route(ws.DELETE("/{user-id}").To(u.nop)) - - container.Add(ws) -} - -func (u UserResource) nop(request *restful.Request, response *restful.Response) { - io.WriteString(response.ResponseWriter, "this would be a normal response") -} - -func main() { - wsContainer := restful.NewContainer() - u := UserResource{} - u.RegisterTo(wsContainer) - - // Add container filter to respond to OPTIONS - wsContainer.Filter(wsContainer.OPTIONSFilter) - - // For use on the default container, you can write - // restful.Filter(restful.OPTIONSFilter()) - - log.Printf("start listening on localhost:8080") - server := &http.Server{Addr: ":8080", Handler: wsContainer} - log.Fatal(server.ListenAndServe()) -} diff --git a/cmd/vendor/github.com/emicklei/go-restful/examples/restful-path-tail.go b/cmd/vendor/github.com/emicklei/go-restful/examples/restful-path-tail.go deleted file mode 100644 index e1f163297f..0000000000 --- a/cmd/vendor/github.com/emicklei/go-restful/examples/restful-path-tail.go +++ /dev/null @@ -1,26 +0,0 @@ -package main - -import ( - . "github.com/emicklei/go-restful" - "io" - "net/http" -) - -// This example shows how to a Route that matches the "tail" of a path. -// Requires the use of a CurlyRouter and the star "*" path parameter pattern. -// -// GET http://localhost:8080/basepath/some/other/location/test.xml - -func main() { - DefaultContainer.Router(CurlyRouter{}) - ws := new(WebService) - ws.Route(ws.GET("/basepath/{resource:*}").To(staticFromPathParam)) - Add(ws) - - println("[go-restful] serve path tails from http://localhost:8080/basepath") - http.ListenAndServe(":8080", nil) -} - -func staticFromPathParam(req *Request, resp *Response) { - io.WriteString(resp, "Tail="+req.PathParameter("resource")) -} diff --git a/cmd/vendor/github.com/emicklei/go-restful/examples/restful-pre-post-filters.go b/cmd/vendor/github.com/emicklei/go-restful/examples/restful-pre-post-filters.go deleted file mode 100644 index 0b55f14930..0000000000 --- a/cmd/vendor/github.com/emicklei/go-restful/examples/restful-pre-post-filters.go +++ /dev/null @@ -1,98 +0,0 @@ -package main - -import ( - "github.com/emicklei/go-restful" - "io" - "log" - "net/http" -) - -// This example shows how the different types of filters are called in the request-response flow. -// The call chain is logged on the console when sending an http request. -// -// GET http://localhost:8080/1 -// GET http://localhost:8080/2 - -var indentLevel int - -func container_filter_A(req *restful.Request, resp *restful.Response, chain *restful.FilterChain) { - log.Printf("url path:%v\n", req.Request.URL) - trace("container_filter_A: before", 1) - chain.ProcessFilter(req, resp) - trace("container_filter_A: after", -1) -} - -func container_filter_B(req *restful.Request, resp *restful.Response, chain *restful.FilterChain) { - trace("container_filter_B: before", 1) - chain.ProcessFilter(req, resp) - trace("container_filter_B: after", -1) -} - -func service_filter_A(req *restful.Request, resp *restful.Response, chain *restful.FilterChain) { - trace("service_filter_A: before", 1) - chain.ProcessFilter(req, resp) - trace("service_filter_A: after", -1) -} - -func service_filter_B(req *restful.Request, resp *restful.Response, chain *restful.FilterChain) { - trace("service_filter_B: before", 1) - chain.ProcessFilter(req, resp) - trace("service_filter_B: after", -1) -} - -func route_filter_A(req *restful.Request, resp *restful.Response, chain *restful.FilterChain) { - trace("route_filter_A: before", 1) - chain.ProcessFilter(req, resp) - trace("route_filter_A: after", -1) -} - -func route_filter_B(req *restful.Request, resp *restful.Response, chain *restful.FilterChain) { - trace("route_filter_B: before", 1) - chain.ProcessFilter(req, resp) - trace("route_filter_B: after", -1) -} - -func trace(what string, delta int) { - indented := what - if delta < 0 { - indentLevel += delta - } - for t := 0; t < indentLevel; t++ { - indented = "." + indented - } - log.Printf("%s", indented) - if delta > 0 { - indentLevel += delta - } -} - -func main() { - restful.Filter(container_filter_A) - restful.Filter(container_filter_B) - - ws1 := new(restful.WebService) - ws1.Path("/1") - ws1.Filter(service_filter_A) - ws1.Filter(service_filter_B) - ws1.Route(ws1.GET("").To(doit1).Filter(route_filter_A).Filter(route_filter_B)) - - ws2 := new(restful.WebService) - ws2.Path("/2") - ws2.Filter(service_filter_A) - ws2.Filter(service_filter_B) - ws2.Route(ws2.GET("").To(doit2).Filter(route_filter_A).Filter(route_filter_B)) - - restful.Add(ws1) - restful.Add(ws2) - - log.Print("go-restful example listing on http://localhost:8080/1 and http://localhost:8080/2") - log.Fatal(http.ListenAndServe(":8080", nil)) -} - -func doit1(req *restful.Request, resp *restful.Response) { - io.WriteString(resp, "nothing to see in 1") -} - -func doit2(req *restful.Request, resp *restful.Response) { - io.WriteString(resp, "nothing to see in 2") -} diff --git a/cmd/vendor/github.com/emicklei/go-restful/examples/restful-resource-functions.go b/cmd/vendor/github.com/emicklei/go-restful/examples/restful-resource-functions.go deleted file mode 100644 index fb1012a028..0000000000 --- a/cmd/vendor/github.com/emicklei/go-restful/examples/restful-resource-functions.go +++ /dev/null @@ -1,63 +0,0 @@ -package main - -import ( - "github.com/emicklei/go-restful" - "log" - "net/http" -) - -// This example shows how to use methods as RouteFunctions for WebServices. -// The ProductResource has a Register() method that creates and initializes -// a WebService to expose its methods as REST operations. -// The WebService is added to the restful.DefaultContainer. -// A ProductResource is typically created using some data access object. -// -// GET http://localhost:8080/products/1 -// POST http://localhost:8080/products -// 1The First - -type Product struct { - Id, Title string -} - -type ProductResource struct { - // typically reference a DAO (data-access-object) -} - -func (p ProductResource) getOne(req *restful.Request, resp *restful.Response) { - id := req.PathParameter("id") - log.Println("getting product with id:" + id) - resp.WriteEntity(Product{Id: id, Title: "test"}) -} - -func (p ProductResource) postOne(req *restful.Request, resp *restful.Response) { - updatedProduct := new(Product) - err := req.ReadEntity(updatedProduct) - if err != nil { // bad request - resp.WriteErrorString(http.StatusBadRequest, err.Error()) - return - } - log.Println("updating product with id:" + updatedProduct.Id) -} - -func (p ProductResource) Register() { - ws := new(restful.WebService) - ws.Path("/products") - ws.Consumes(restful.MIME_XML) - ws.Produces(restful.MIME_XML) - - ws.Route(ws.GET("/{id}").To(p.getOne). - Doc("get the product by its id"). - Param(ws.PathParameter("id", "identifier of the product").DataType("string"))) - - ws.Route(ws.POST("").To(p.postOne). - Doc("update or create a product"). - Param(ws.BodyParameter("Product", "a Product (XML)").DataType("main.Product"))) - - restful.Add(ws) -} - -func main() { - ProductResource{}.Register() - http.ListenAndServe(":8080", nil) -} diff --git a/cmd/vendor/github.com/emicklei/go-restful/examples/restful-serve-static.go b/cmd/vendor/github.com/emicklei/go-restful/examples/restful-serve-static.go deleted file mode 100644 index 8cb7848c1d..0000000000 --- a/cmd/vendor/github.com/emicklei/go-restful/examples/restful-serve-static.go +++ /dev/null @@ -1,47 +0,0 @@ -package main - -import ( - "fmt" - "net/http" - "path" - - "github.com/emicklei/go-restful" -) - -// This example shows how to define methods that serve static files -// It uses the standard http.ServeFile method -// -// GET http://localhost:8080/static/test.xml -// GET http://localhost:8080/static/ -// -// GET http://localhost:8080/static?resource=subdir/test.xml - -var rootdir = "/tmp" - -func main() { - restful.DefaultContainer.Router(restful.CurlyRouter{}) - - ws := new(restful.WebService) - ws.Route(ws.GET("/static/{subpath:*}").To(staticFromPathParam)) - ws.Route(ws.GET("/static").To(staticFromQueryParam)) - restful.Add(ws) - - println("[go-restful] serving files on http://localhost:8080/static from local /tmp") - http.ListenAndServe(":8080", nil) -} - -func staticFromPathParam(req *restful.Request, resp *restful.Response) { - actual := path.Join(rootdir, req.PathParameter("subpath")) - fmt.Printf("serving %s ... (from %s)\n", actual, req.PathParameter("subpath")) - http.ServeFile( - resp.ResponseWriter, - req.Request, - actual) -} - -func staticFromQueryParam(req *restful.Request, resp *restful.Response) { - http.ServeFile( - resp.ResponseWriter, - req.Request, - path.Join(rootdir, req.QueryParameter("resource"))) -} diff --git a/cmd/vendor/github.com/emicklei/go-restful/examples/restful-swagger.go b/cmd/vendor/github.com/emicklei/go-restful/examples/restful-swagger.go deleted file mode 100644 index 261f29d2b7..0000000000 --- a/cmd/vendor/github.com/emicklei/go-restful/examples/restful-swagger.go +++ /dev/null @@ -1,61 +0,0 @@ -package main - -import ( - "log" - "net/http" - - "github.com/emicklei/go-restful" - "github.com/emicklei/go-restful-swagger12" -) - -type Book struct { - Title string - Author string -} - -func main() { - ws := new(restful.WebService) - ws.Path("/books") - ws.Consumes(restful.MIME_JSON, restful.MIME_XML) - ws.Produces(restful.MIME_JSON, restful.MIME_XML) - restful.Add(ws) - - ws.Route(ws.GET("/{medium}").To(noop). - Doc("Search all books"). - Param(ws.PathParameter("medium", "digital or paperback").DataType("string")). - Param(ws.QueryParameter("language", "en,nl,de").DataType("string")). - Param(ws.HeaderParameter("If-Modified-Since", "last known timestamp").DataType("datetime")). - Do(returns200, returns500)) - - ws.Route(ws.PUT("/{medium}").To(noop). - Doc("Add a new book"). - Param(ws.PathParameter("medium", "digital or paperback").DataType("string")). - Reads(Book{})) - - // You can install the Swagger Service which provides a nice Web UI on your REST API - // You need to download the Swagger HTML5 assets and change the FilePath location in the config below. - // Open http://localhost:8080/apidocs and enter http://localhost:8080/apidocs.json in the api input field. - config := swagger.Config{ - WebServices: restful.DefaultContainer.RegisteredWebServices(), // you control what services are visible - WebServicesUrl: "http://localhost:8080", - ApiPath: "/apidocs.json", - - // Optionally, specifiy where the UI is located - SwaggerPath: "/apidocs/", - SwaggerFilePath: "/Users/emicklei/xProjects/swagger-ui/dist"} - swagger.RegisterSwaggerService(config, restful.DefaultContainer) - - log.Printf("start listening on localhost:8080") - server := &http.Server{Addr: ":8080", Handler: restful.DefaultContainer} - log.Fatal(server.ListenAndServe()) -} - -func noop(req *restful.Request, resp *restful.Response) {} - -func returns200(b *restful.RouteBuilder) { - b.Returns(http.StatusOK, "OK", Book{}) -} - -func returns500(b *restful.RouteBuilder) { - b.Returns(http.StatusInternalServerError, "Bummer, something went wrong", nil) -} diff --git a/cmd/vendor/github.com/emicklei/go-restful/examples/restful-user-resource.go b/cmd/vendor/github.com/emicklei/go-restful/examples/restful-user-resource.go deleted file mode 100644 index 4c18dad186..0000000000 --- a/cmd/vendor/github.com/emicklei/go-restful/examples/restful-user-resource.go +++ /dev/null @@ -1,152 +0,0 @@ -package main - -import ( - "log" - "net/http" - "strconv" - - "github.com/emicklei/go-restful" - "github.com/emicklei/go-restful-swagger12" -) - -// This example show a complete (GET,PUT,POST,DELETE) conventional example of -// a REST Resource including documentation to be served by e.g. a Swagger UI -// It is recommended to create a Resource struct (UserResource) that can encapsulate -// an object that provide domain access (a DAO) -// It has a Register method including the complete Route mapping to methods together -// with all the appropriate documentation -// -// POST http://localhost:8080/users -// 1Melissa Raspberry -// -// GET http://localhost:8080/users/1 -// -// PUT http://localhost:8080/users/1 -// 1Melissa -// -// DELETE http://localhost:8080/users/1 -// - -type User struct { - Id, Name string -} - -type UserResource struct { - // normally one would use DAO (data access object) - users map[string]User -} - -func (u UserResource) Register(container *restful.Container) { - ws := new(restful.WebService) - ws. - Path("/users"). - Doc("Manage Users"). - Consumes(restful.MIME_XML, restful.MIME_JSON). - Produces(restful.MIME_JSON, restful.MIME_XML) // you can specify this per route as well - - ws.Route(ws.GET("/{user-id}").To(u.findUser). - // docs - Doc("get a user"). - Operation("findUser"). - Param(ws.PathParameter("user-id", "identifier of the user").DataType("string")). - Writes(User{})) // on the response - - ws.Route(ws.PUT("/{user-id}").To(u.updateUser). - // docs - Doc("update a user"). - Operation("updateUser"). - Param(ws.PathParameter("user-id", "identifier of the user").DataType("string")). - ReturnsError(409, "duplicate user-id", nil). - Reads(User{})) // from the request - - ws.Route(ws.POST("").To(u.createUser). - // docs - Doc("create a user"). - Operation("createUser"). - Reads(User{})) // from the request - - ws.Route(ws.DELETE("/{user-id}").To(u.removeUser). - // docs - Doc("delete a user"). - Operation("removeUser"). - Param(ws.PathParameter("user-id", "identifier of the user").DataType("string"))) - - container.Add(ws) -} - -// GET http://localhost:8080/users/1 -// -func (u UserResource) findUser(request *restful.Request, response *restful.Response) { - id := request.PathParameter("user-id") - usr := u.users[id] - if len(usr.Id) == 0 { - response.AddHeader("Content-Type", "text/plain") - response.WriteErrorString(http.StatusNotFound, "404: User could not be found.") - return - } - response.WriteEntity(usr) -} - -// POST http://localhost:8080/users -// Melissa -// -func (u *UserResource) createUser(request *restful.Request, response *restful.Response) { - usr := new(User) - err := request.ReadEntity(usr) - if err != nil { - response.AddHeader("Content-Type", "text/plain") - response.WriteErrorString(http.StatusInternalServerError, err.Error()) - return - } - usr.Id = strconv.Itoa(len(u.users) + 1) // simple id generation - u.users[usr.Id] = *usr - response.WriteHeaderAndEntity(http.StatusCreated, usr) -} - -// PUT http://localhost:8080/users/1 -// 1Melissa Raspberry -// -func (u *UserResource) updateUser(request *restful.Request, response *restful.Response) { - usr := new(User) - err := request.ReadEntity(&usr) - if err != nil { - response.AddHeader("Content-Type", "text/plain") - response.WriteErrorString(http.StatusInternalServerError, err.Error()) - return - } - u.users[usr.Id] = *usr - response.WriteEntity(usr) -} - -// DELETE http://localhost:8080/users/1 -// -func (u *UserResource) removeUser(request *restful.Request, response *restful.Response) { - id := request.PathParameter("user-id") - delete(u.users, id) -} - -func main() { - // to see what happens in the package, uncomment the following - //restful.TraceLogger(log.New(os.Stdout, "[restful] ", log.LstdFlags|log.Lshortfile)) - - wsContainer := restful.NewContainer() - u := UserResource{map[string]User{}} - u.Register(wsContainer) - - // Optionally, you can install the Swagger Service which provides a nice Web UI on your REST API - // You need to download the Swagger HTML5 assets and change the FilePath location in the config below. - // Open http://localhost:8080/apidocs and enter http://localhost:8080/apidocs.json in the api input field. - config := swagger.Config{ - WebServices: wsContainer.RegisteredWebServices(), // you control what services are visible - WebServicesUrl: "http://localhost:8080", - ApiPath: "/apidocs.json", - - // Optionally, specifiy where the UI is located - SwaggerPath: "/apidocs/", - SwaggerFilePath: "/Users/emicklei/xProjects/swagger-ui/dist"} - swagger.RegisterSwaggerService(config, wsContainer) - - log.Printf("start listening on localhost:8080") - server := &http.Server{Addr: ":8080", Handler: wsContainer} - log.Fatal(server.ListenAndServe()) -} diff --git a/cmd/vendor/github.com/emicklei/go-restful/examples/restful-user-service.go b/cmd/vendor/github.com/emicklei/go-restful/examples/restful-user-service.go deleted file mode 100644 index 83297fc710..0000000000 --- a/cmd/vendor/github.com/emicklei/go-restful/examples/restful-user-service.go +++ /dev/null @@ -1,143 +0,0 @@ -package main - -import ( - "log" - "net/http" - - "github.com/emicklei/go-restful" - "github.com/emicklei/go-restful-swagger12" -) - -// This example is functionally the same as the example in restful-user-resource.go -// with the only difference that is served using the restful.DefaultContainer - -type User struct { - Id, Name string -} - -type UserService struct { - // normally one would use DAO (data access object) - users map[string]User -} - -func (u UserService) Register() { - ws := new(restful.WebService) - ws. - Path("/users"). - Consumes(restful.MIME_XML, restful.MIME_JSON). - Produces(restful.MIME_JSON, restful.MIME_XML) // you can specify this per route as well - - ws.Route(ws.GET("/").To(u.findAllUsers). - // docs - Doc("get all users"). - Operation("findAllUsers"). - Writes([]User{}). - Returns(200, "OK", nil)) - - ws.Route(ws.GET("/{user-id}").To(u.findUser). - // docs - Doc("get a user"). - Operation("findUser"). - Param(ws.PathParameter("user-id", "identifier of the user").DataType("string")). - Writes(User{}). // on the response - Returns(404, "Not Found", nil)) - - ws.Route(ws.PUT("/{user-id}").To(u.updateUser). - // docs - Doc("update a user"). - Operation("updateUser"). - Param(ws.PathParameter("user-id", "identifier of the user").DataType("string")). - Reads(User{})) // from the request - - ws.Route(ws.PUT("").To(u.createUser). - // docs - Doc("create a user"). - Operation("createUser"). - Reads(User{})) // from the request - - ws.Route(ws.DELETE("/{user-id}").To(u.removeUser). - // docs - Doc("delete a user"). - Operation("removeUser"). - Param(ws.PathParameter("user-id", "identifier of the user").DataType("string"))) - - restful.Add(ws) -} - -// GET http://localhost:8080/users -// -func (u UserService) findAllUsers(request *restful.Request, response *restful.Response) { - list := []User{} - for _, each := range u.users { - list = append(list, each) - } - response.WriteEntity(list) -} - -// GET http://localhost:8080/users/1 -// -func (u UserService) findUser(request *restful.Request, response *restful.Response) { - id := request.PathParameter("user-id") - usr := u.users[id] - if len(usr.Id) == 0 { - response.WriteErrorString(http.StatusNotFound, "User could not be found.") - } else { - response.WriteEntity(usr) - } -} - -// PUT http://localhost:8080/users/1 -// 1Melissa Raspberry -// -func (u *UserService) updateUser(request *restful.Request, response *restful.Response) { - usr := new(User) - err := request.ReadEntity(&usr) - if err == nil { - u.users[usr.Id] = *usr - response.WriteEntity(usr) - } else { - response.WriteError(http.StatusInternalServerError, err) - } -} - -// PUT http://localhost:8080/users/1 -// 1Melissa -// -func (u *UserService) createUser(request *restful.Request, response *restful.Response) { - usr := User{Id: request.PathParameter("user-id")} - err := request.ReadEntity(&usr) - if err == nil { - u.users[usr.Id] = usr - response.WriteHeaderAndEntity(http.StatusCreated, usr) - } else { - response.WriteError(http.StatusInternalServerError, err) - } -} - -// DELETE http://localhost:8080/users/1 -// -func (u *UserService) removeUser(request *restful.Request, response *restful.Response) { - id := request.PathParameter("user-id") - delete(u.users, id) -} - -func main() { - u := UserService{map[string]User{}} - u.Register() - - // Optionally, you can install the Swagger Service which provides a nice Web UI on your REST API - // You need to download the Swagger HTML5 assets and change the FilePath location in the config below. - // Open http://localhost:8080/apidocs and enter http://localhost:8080/apidocs.json in the api input field. - config := swagger.Config{ - WebServices: restful.RegisteredWebServices(), // you control what services are visible - WebServicesUrl: "http://localhost:8080", - ApiPath: "/apidocs.json", - - // Optionally, specifiy where the UI is located - SwaggerPath: "/apidocs/", - SwaggerFilePath: "/Users/emicklei/Projects/swagger-ui/dist"} - swagger.InstallSwaggerService(config) - - log.Printf("start listening on localhost:8080") - log.Fatal(http.ListenAndServe(":8080", nil)) -} diff --git a/cmd/vendor/github.com/emicklei/go-restful/filter.go b/cmd/vendor/github.com/emicklei/go-restful/filter.go deleted file mode 100644 index c23bfb591a..0000000000 --- a/cmd/vendor/github.com/emicklei/go-restful/filter.go +++ /dev/null @@ -1,35 +0,0 @@ -package restful - -// Copyright 2013 Ernest Micklei. All rights reserved. -// Use of this source code is governed by a license -// that can be found in the LICENSE file. - -// FilterChain is a request scoped object to process one or more filters before calling the target RouteFunction. -type FilterChain struct { - Filters []FilterFunction // ordered list of FilterFunction - Index int // index into filters that is currently in progress - Target RouteFunction // function to call after passing all filters -} - -// ProcessFilter passes the request,response pair through the next of Filters. -// Each filter can decide to proceed to the next Filter or handle the Response itself. -func (f *FilterChain) ProcessFilter(request *Request, response *Response) { - if f.Index < len(f.Filters) { - f.Index++ - f.Filters[f.Index-1](request, response, f) - } else { - f.Target(request, response) - } -} - -// FilterFunction definitions must call ProcessFilter on the FilterChain to pass on the control and eventually call the RouteFunction -type FilterFunction func(*Request, *Response, *FilterChain) - -// NoBrowserCacheFilter is a filter function to set HTTP headers that disable browser caching -// See examples/restful-no-cache-filter.go for usage -func NoBrowserCacheFilter(req *Request, resp *Response, chain *FilterChain) { - resp.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate") // HTTP 1.1. - resp.Header().Set("Pragma", "no-cache") // HTTP 1.0. - resp.Header().Set("Expires", "0") // Proxies. - chain.ProcessFilter(req, resp) -} diff --git a/cmd/vendor/github.com/emicklei/go-restful/jsr311.go b/cmd/vendor/github.com/emicklei/go-restful/jsr311.go deleted file mode 100644 index 511444ac68..0000000000 --- a/cmd/vendor/github.com/emicklei/go-restful/jsr311.go +++ /dev/null @@ -1,248 +0,0 @@ -package restful - -// Copyright 2013 Ernest Micklei. All rights reserved. -// Use of this source code is governed by a license -// that can be found in the LICENSE file. - -import ( - "errors" - "fmt" - "net/http" - "sort" -) - -// RouterJSR311 implements the flow for matching Requests to Routes (and consequently Resource Functions) -// as specified by the JSR311 http://jsr311.java.net/nonav/releases/1.1/spec/spec.html. -// RouterJSR311 implements the Router interface. -// Concept of locators is not implemented. -type RouterJSR311 struct{} - -// SelectRoute is part of the Router interface and returns the best match -// for the WebService and its Route for the given Request. -func (r RouterJSR311) SelectRoute( - webServices []*WebService, - httpRequest *http.Request) (selectedService *WebService, selectedRoute *Route, err error) { - - // Identify the root resource class (WebService) - dispatcher, finalMatch, err := r.detectDispatcher(httpRequest.URL.Path, webServices) - if err != nil { - return nil, nil, NewError(http.StatusNotFound, "") - } - // Obtain the set of candidate methods (Routes) - routes := r.selectRoutes(dispatcher, finalMatch) - if len(routes) == 0 { - return dispatcher, nil, NewError(http.StatusNotFound, "404: Page Not Found") - } - - // Identify the method (Route) that will handle the request - route, ok := r.detectRoute(routes, httpRequest) - return dispatcher, route, ok -} - -// http://jsr311.java.net/nonav/releases/1.1/spec/spec3.html#x3-360003.7.2 -func (r RouterJSR311) detectRoute(routes []Route, httpRequest *http.Request) (*Route, error) { - // http method - methodOk := []Route{} - for _, each := range routes { - if httpRequest.Method == each.Method { - methodOk = append(methodOk, each) - } - } - if len(methodOk) == 0 { - if trace { - traceLogger.Printf("no Route found (in %d routes) that matches HTTP method %s\n", len(routes), httpRequest.Method) - } - return nil, NewError(http.StatusMethodNotAllowed, "405: Method Not Allowed") - } - inputMediaOk := methodOk - - // content-type - contentType := httpRequest.Header.Get(HEADER_ContentType) - inputMediaOk = []Route{} - for _, each := range methodOk { - if each.matchesContentType(contentType) { - inputMediaOk = append(inputMediaOk, each) - } - } - if len(inputMediaOk) == 0 { - if trace { - traceLogger.Printf("no Route found (from %d) that matches HTTP Content-Type: %s\n", len(methodOk), contentType) - } - return nil, NewError(http.StatusUnsupportedMediaType, "415: Unsupported Media Type") - } - - // accept - outputMediaOk := []Route{} - accept := httpRequest.Header.Get(HEADER_Accept) - if len(accept) == 0 { - accept = "*/*" - } - for _, each := range inputMediaOk { - if each.matchesAccept(accept) { - outputMediaOk = append(outputMediaOk, each) - } - } - if len(outputMediaOk) == 0 { - if trace { - traceLogger.Printf("no Route found (from %d) that matches HTTP Accept: %s\n", len(inputMediaOk), accept) - } - return nil, NewError(http.StatusNotAcceptable, "406: Not Acceptable") - } - // return r.bestMatchByMedia(outputMediaOk, contentType, accept), nil - return &outputMediaOk[0], nil -} - -// http://jsr311.java.net/nonav/releases/1.1/spec/spec3.html#x3-360003.7.2 -// n/m > n/* > */* -func (r RouterJSR311) bestMatchByMedia(routes []Route, contentType string, accept string) *Route { - // TODO - return &routes[0] -} - -// http://jsr311.java.net/nonav/releases/1.1/spec/spec3.html#x3-360003.7.2 (step 2) -func (r RouterJSR311) selectRoutes(dispatcher *WebService, pathRemainder string) []Route { - filtered := &sortableRouteCandidates{} - for _, each := range dispatcher.Routes() { - pathExpr := each.pathExpr - matches := pathExpr.Matcher.FindStringSubmatch(pathRemainder) - if matches != nil { - lastMatch := matches[len(matches)-1] - if len(lastMatch) == 0 || lastMatch == "/" { // do not include if value is neither empty nor ‘/’. - filtered.candidates = append(filtered.candidates, - routeCandidate{each, len(matches) - 1, pathExpr.LiteralCount, pathExpr.VarCount}) - } - } - } - if len(filtered.candidates) == 0 { - if trace { - traceLogger.Printf("WebService on path %s has no routes that match URL path remainder:%s\n", dispatcher.rootPath, pathRemainder) - } - return []Route{} - } - sort.Sort(sort.Reverse(filtered)) - - // select other routes from candidates whoes expression matches rmatch - matchingRoutes := []Route{filtered.candidates[0].route} - for c := 1; c < len(filtered.candidates); c++ { - each := filtered.candidates[c] - if each.route.pathExpr.Matcher.MatchString(pathRemainder) { - matchingRoutes = append(matchingRoutes, each.route) - } - } - return matchingRoutes -} - -// http://jsr311.java.net/nonav/releases/1.1/spec/spec3.html#x3-360003.7.2 (step 1) -func (r RouterJSR311) detectDispatcher(requestPath string, dispatchers []*WebService) (*WebService, string, error) { - filtered := &sortableDispatcherCandidates{} - for _, each := range dispatchers { - matches := each.pathExpr.Matcher.FindStringSubmatch(requestPath) - if matches != nil { - filtered.candidates = append(filtered.candidates, - dispatcherCandidate{each, matches[len(matches)-1], len(matches), each.pathExpr.LiteralCount, each.pathExpr.VarCount}) - } - } - if len(filtered.candidates) == 0 { - if trace { - traceLogger.Printf("no WebService was found to match URL path:%s\n", requestPath) - } - return nil, "", errors.New("not found") - } - sort.Sort(sort.Reverse(filtered)) - return filtered.candidates[0].dispatcher, filtered.candidates[0].finalMatch, nil -} - -// Types and functions to support the sorting of Routes - -type routeCandidate struct { - route Route - matchesCount int // the number of capturing groups - literalCount int // the number of literal characters (means those not resulting from template variable substitution) - nonDefaultCount int // the number of capturing groups with non-default regular expressions (i.e. not ‘([^ /]+?)’) -} - -func (r routeCandidate) expressionToMatch() string { - return r.route.pathExpr.Source -} - -func (r routeCandidate) String() string { - return fmt.Sprintf("(m=%d,l=%d,n=%d)", r.matchesCount, r.literalCount, r.nonDefaultCount) -} - -type sortableRouteCandidates struct { - candidates []routeCandidate -} - -func (rcs *sortableRouteCandidates) Len() int { - return len(rcs.candidates) -} -func (rcs *sortableRouteCandidates) Swap(i, j int) { - rcs.candidates[i], rcs.candidates[j] = rcs.candidates[j], rcs.candidates[i] -} -func (rcs *sortableRouteCandidates) Less(i, j int) bool { - ci := rcs.candidates[i] - cj := rcs.candidates[j] - // primary key - if ci.literalCount < cj.literalCount { - return true - } - if ci.literalCount > cj.literalCount { - return false - } - // secundary key - if ci.matchesCount < cj.matchesCount { - return true - } - if ci.matchesCount > cj.matchesCount { - return false - } - // tertiary key - if ci.nonDefaultCount < cj.nonDefaultCount { - return true - } - if ci.nonDefaultCount > cj.nonDefaultCount { - return false - } - // quaternary key ("source" is interpreted as Path) - return ci.route.Path < cj.route.Path -} - -// Types and functions to support the sorting of Dispatchers - -type dispatcherCandidate struct { - dispatcher *WebService - finalMatch string - matchesCount int // the number of capturing groups - literalCount int // the number of literal characters (means those not resulting from template variable substitution) - nonDefaultCount int // the number of capturing groups with non-default regular expressions (i.e. not ‘([^ /]+?)’) -} -type sortableDispatcherCandidates struct { - candidates []dispatcherCandidate -} - -func (dc *sortableDispatcherCandidates) Len() int { - return len(dc.candidates) -} -func (dc *sortableDispatcherCandidates) Swap(i, j int) { - dc.candidates[i], dc.candidates[j] = dc.candidates[j], dc.candidates[i] -} -func (dc *sortableDispatcherCandidates) Less(i, j int) bool { - ci := dc.candidates[i] - cj := dc.candidates[j] - // primary key - if ci.matchesCount < cj.matchesCount { - return true - } - if ci.matchesCount > cj.matchesCount { - return false - } - // secundary key - if ci.literalCount < cj.literalCount { - return true - } - if ci.literalCount > cj.literalCount { - return false - } - // tertiary key - return ci.nonDefaultCount < cj.nonDefaultCount -} diff --git a/cmd/vendor/github.com/emicklei/go-restful/log/log.go b/cmd/vendor/github.com/emicklei/go-restful/log/log.go deleted file mode 100644 index 6cd44c7a5d..0000000000 --- a/cmd/vendor/github.com/emicklei/go-restful/log/log.go +++ /dev/null @@ -1,34 +0,0 @@ -package log - -import ( - stdlog "log" - "os" -) - -// StdLogger corresponds to a minimal subset of the interface satisfied by stdlib log.Logger -type StdLogger interface { - Print(v ...interface{}) - Printf(format string, v ...interface{}) -} - -var Logger StdLogger - -func init() { - // default Logger - SetLogger(stdlog.New(os.Stderr, "[restful] ", stdlog.LstdFlags|stdlog.Lshortfile)) -} - -// SetLogger sets the logger for this package -func SetLogger(customLogger StdLogger) { - Logger = customLogger -} - -// Print delegates to the Logger -func Print(v ...interface{}) { - Logger.Print(v...) -} - -// Printf delegates to the Logger -func Printf(format string, v ...interface{}) { - Logger.Printf(format, v...) -} diff --git a/cmd/vendor/github.com/emicklei/go-restful/logger.go b/cmd/vendor/github.com/emicklei/go-restful/logger.go deleted file mode 100644 index 3f1c4db86b..0000000000 --- a/cmd/vendor/github.com/emicklei/go-restful/logger.go +++ /dev/null @@ -1,32 +0,0 @@ -package restful - -// Copyright 2014 Ernest Micklei. All rights reserved. -// Use of this source code is governed by a license -// that can be found in the LICENSE file. -import ( - "github.com/emicklei/go-restful/log" -) - -var trace bool = false -var traceLogger log.StdLogger - -func init() { - traceLogger = log.Logger // use the package logger by default -} - -// TraceLogger enables detailed logging of Http request matching and filter invocation. Default no logger is set. -// You may call EnableTracing() directly to enable trace logging to the package-wide logger. -func TraceLogger(logger log.StdLogger) { - traceLogger = logger - EnableTracing(logger != nil) -} - -// expose the setter for the global logger on the top-level package -func SetLogger(customLogger log.StdLogger) { - log.SetLogger(customLogger) -} - -// EnableTracing can be used to Trace logging on and off. -func EnableTracing(enabled bool) { - trace = enabled -} diff --git a/cmd/vendor/github.com/emicklei/go-restful/mime.go b/cmd/vendor/github.com/emicklei/go-restful/mime.go deleted file mode 100644 index d7ea2b6157..0000000000 --- a/cmd/vendor/github.com/emicklei/go-restful/mime.go +++ /dev/null @@ -1,45 +0,0 @@ -package restful - -import ( - "strconv" - "strings" -) - -type mime struct { - media string - quality float64 -} - -// insertMime adds a mime to a list and keeps it sorted by quality. -func insertMime(l []mime, e mime) []mime { - for i, each := range l { - // if current mime has lower quality then insert before - if e.quality > each.quality { - left := append([]mime{}, l[0:i]...) - return append(append(left, e), l[i:]...) - } - } - return append(l, e) -} - -// sortedMimes returns a list of mime sorted (desc) by its specified quality. -func sortedMimes(accept string) (sorted []mime) { - for _, each := range strings.Split(accept, ",") { - typeAndQuality := strings.Split(strings.Trim(each, " "), ";") - if len(typeAndQuality) == 1 { - sorted = insertMime(sorted, mime{typeAndQuality[0], 1.0}) - } else { - // take factor - parts := strings.Split(typeAndQuality[1], "=") - if len(parts) == 2 { - f, err := strconv.ParseFloat(parts[1], 64) - if err != nil { - traceLogger.Printf("unable to parse quality in %s, %v", each, err) - } else { - sorted = insertMime(sorted, mime{typeAndQuality[0], f}) - } - } - } - } - return -} diff --git a/cmd/vendor/github.com/emicklei/go-restful/options_filter.go b/cmd/vendor/github.com/emicklei/go-restful/options_filter.go deleted file mode 100644 index 4514eadcfa..0000000000 --- a/cmd/vendor/github.com/emicklei/go-restful/options_filter.go +++ /dev/null @@ -1,26 +0,0 @@ -package restful - -import "strings" - -// Copyright 2013 Ernest Micklei. All rights reserved. -// Use of this source code is governed by a license -// that can be found in the LICENSE file. - -// OPTIONSFilter is a filter function that inspects the Http Request for the OPTIONS method -// and provides the response with a set of allowed methods for the request URL Path. -// As for any filter, you can also install it for a particular WebService within a Container. -// Note: this filter is not needed when using CrossOriginResourceSharing (for CORS). -func (c *Container) OPTIONSFilter(req *Request, resp *Response, chain *FilterChain) { - if "OPTIONS" != req.Request.Method { - chain.ProcessFilter(req, resp) - return - } - resp.AddHeader(HEADER_Allow, strings.Join(c.computeAllowedMethods(req), ",")) -} - -// OPTIONSFilter is a filter function that inspects the Http Request for the OPTIONS method -// and provides the response with a set of allowed methods for the request URL Path. -// Note: this filter is not needed when using CrossOriginResourceSharing (for CORS). -func OPTIONSFilter() FilterFunction { - return DefaultContainer.OPTIONSFilter -} diff --git a/cmd/vendor/github.com/emicklei/go-restful/parameter.go b/cmd/vendor/github.com/emicklei/go-restful/parameter.go deleted file mode 100644 index e11c8162a7..0000000000 --- a/cmd/vendor/github.com/emicklei/go-restful/parameter.go +++ /dev/null @@ -1,114 +0,0 @@ -package restful - -// Copyright 2013 Ernest Micklei. All rights reserved. -// Use of this source code is governed by a license -// that can be found in the LICENSE file. - -const ( - // PathParameterKind = indicator of Request parameter type "path" - PathParameterKind = iota - - // QueryParameterKind = indicator of Request parameter type "query" - QueryParameterKind - - // BodyParameterKind = indicator of Request parameter type "body" - BodyParameterKind - - // HeaderParameterKind = indicator of Request parameter type "header" - HeaderParameterKind - - // FormParameterKind = indicator of Request parameter type "form" - FormParameterKind -) - -// Parameter is for documententing the parameter used in a Http Request -// ParameterData kinds are Path,Query and Body -type Parameter struct { - data *ParameterData -} - -// ParameterData represents the state of a Parameter. -// It is made public to make it accessible to e.g. the Swagger package. -type ParameterData struct { - Name, Description, DataType, DataFormat string - Kind int - Required bool - AllowableValues map[string]string - AllowMultiple bool - DefaultValue string -} - -// Data returns the state of the Parameter -func (p *Parameter) Data() ParameterData { - return *p.data -} - -// Kind returns the parameter type indicator (see const for valid values) -func (p *Parameter) Kind() int { - return p.data.Kind -} - -func (p *Parameter) bePath() *Parameter { - p.data.Kind = PathParameterKind - return p -} -func (p *Parameter) beQuery() *Parameter { - p.data.Kind = QueryParameterKind - return p -} -func (p *Parameter) beBody() *Parameter { - p.data.Kind = BodyParameterKind - return p -} - -func (p *Parameter) beHeader() *Parameter { - p.data.Kind = HeaderParameterKind - return p -} - -func (p *Parameter) beForm() *Parameter { - p.data.Kind = FormParameterKind - return p -} - -// Required sets the required field and returns the receiver -func (p *Parameter) Required(required bool) *Parameter { - p.data.Required = required - return p -} - -// AllowMultiple sets the allowMultiple field and returns the receiver -func (p *Parameter) AllowMultiple(multiple bool) *Parameter { - p.data.AllowMultiple = multiple - return p -} - -// AllowableValues sets the allowableValues field and returns the receiver -func (p *Parameter) AllowableValues(values map[string]string) *Parameter { - p.data.AllowableValues = values - return p -} - -// DataType sets the dataType field and returns the receiver -func (p *Parameter) DataType(typeName string) *Parameter { - p.data.DataType = typeName - return p -} - -// DataFormat sets the dataFormat field for Swagger UI -func (p *Parameter) DataFormat(formatName string) *Parameter { - p.data.DataFormat = formatName - return p -} - -// DefaultValue sets the default value field and returns the receiver -func (p *Parameter) DefaultValue(stringRepresentation string) *Parameter { - p.data.DefaultValue = stringRepresentation - return p -} - -// Description sets the description value field and returns the receiver -func (p *Parameter) Description(doc string) *Parameter { - p.data.Description = doc - return p -} diff --git a/cmd/vendor/github.com/emicklei/go-restful/path_expression.go b/cmd/vendor/github.com/emicklei/go-restful/path_expression.go deleted file mode 100644 index a921e6f224..0000000000 --- a/cmd/vendor/github.com/emicklei/go-restful/path_expression.go +++ /dev/null @@ -1,69 +0,0 @@ -package restful - -// Copyright 2013 Ernest Micklei. All rights reserved. -// Use of this source code is governed by a license -// that can be found in the LICENSE file. - -import ( - "bytes" - "fmt" - "regexp" - "strings" -) - -// PathExpression holds a compiled path expression (RegExp) needed to match against -// Http request paths and to extract path parameter values. -type pathExpression struct { - LiteralCount int // the number of literal characters (means those not resulting from template variable substitution) - VarCount int // the number of named parameters (enclosed by {}) in the path - Matcher *regexp.Regexp - Source string // Path as defined by the RouteBuilder - tokens []string -} - -// NewPathExpression creates a PathExpression from the input URL path. -// Returns an error if the path is invalid. -func newPathExpression(path string) (*pathExpression, error) { - expression, literalCount, varCount, tokens := templateToRegularExpression(path) - compiled, err := regexp.Compile(expression) - if err != nil { - return nil, err - } - return &pathExpression{literalCount, varCount, compiled, expression, tokens}, nil -} - -// http://jsr311.java.net/nonav/releases/1.1/spec/spec3.html#x3-370003.7.3 -func templateToRegularExpression(template string) (expression string, literalCount int, varCount int, tokens []string) { - var buffer bytes.Buffer - buffer.WriteString("^") - //tokens = strings.Split(template, "/") - tokens = tokenizePath(template) - for _, each := range tokens { - if each == "" { - continue - } - buffer.WriteString("/") - if strings.HasPrefix(each, "{") { - // check for regular expression in variable - colon := strings.Index(each, ":") - if colon != -1 { - // extract expression - paramExpr := strings.TrimSpace(each[colon+1 : len(each)-1]) - if paramExpr == "*" { // special case - buffer.WriteString("(.*)") - } else { - buffer.WriteString(fmt.Sprintf("(%s)", paramExpr)) // between colon and closing moustache - } - } else { - // plain var - buffer.WriteString("([^/]+?)") - } - varCount += 1 - } else { - literalCount += len(each) - encoded := each // TODO URI encode - buffer.WriteString(regexp.QuoteMeta(encoded)) - } - } - return strings.TrimRight(buffer.String(), "/") + "(/.*)?$", literalCount, varCount, tokens -} diff --git a/cmd/vendor/github.com/emicklei/go-restful/request.go b/cmd/vendor/github.com/emicklei/go-restful/request.go deleted file mode 100644 index 8c23af12c0..0000000000 --- a/cmd/vendor/github.com/emicklei/go-restful/request.go +++ /dev/null @@ -1,113 +0,0 @@ -package restful - -// Copyright 2013 Ernest Micklei. All rights reserved. -// Use of this source code is governed by a license -// that can be found in the LICENSE file. - -import ( - "compress/zlib" - "net/http" -) - -var defaultRequestContentType string - -// Request is a wrapper for a http Request that provides convenience methods -type Request struct { - Request *http.Request - pathParameters map[string]string - attributes map[string]interface{} // for storing request-scoped values - selectedRoutePath string // root path + route path that matched the request, e.g. /meetings/{id}/attendees -} - -func NewRequest(httpRequest *http.Request) *Request { - return &Request{ - Request: httpRequest, - pathParameters: map[string]string{}, - attributes: map[string]interface{}{}, - } // empty parameters, attributes -} - -// If ContentType is missing or */* is given then fall back to this type, otherwise -// a "Unable to unmarshal content of type:" response is returned. -// Valid values are restful.MIME_JSON and restful.MIME_XML -// Example: -// restful.DefaultRequestContentType(restful.MIME_JSON) -func DefaultRequestContentType(mime string) { - defaultRequestContentType = mime -} - -// PathParameter accesses the Path parameter value by its name -func (r *Request) PathParameter(name string) string { - return r.pathParameters[name] -} - -// PathParameters accesses the Path parameter values -func (r *Request) PathParameters() map[string]string { - return r.pathParameters -} - -// QueryParameter returns the (first) Query parameter value by its name -func (r *Request) QueryParameter(name string) string { - return r.Request.FormValue(name) -} - -// BodyParameter parses the body of the request (once for typically a POST or a PUT) and returns the value of the given name or an error. -func (r *Request) BodyParameter(name string) (string, error) { - err := r.Request.ParseForm() - if err != nil { - return "", err - } - return r.Request.PostFormValue(name), nil -} - -// HeaderParameter returns the HTTP Header value of a Header name or empty if missing -func (r *Request) HeaderParameter(name string) string { - return r.Request.Header.Get(name) -} - -// ReadEntity checks the Accept header and reads the content into the entityPointer. -func (r *Request) ReadEntity(entityPointer interface{}) (err error) { - contentType := r.Request.Header.Get(HEADER_ContentType) - contentEncoding := r.Request.Header.Get(HEADER_ContentEncoding) - - // check if the request body needs decompression - if ENCODING_GZIP == contentEncoding { - gzipReader := currentCompressorProvider.AcquireGzipReader() - defer currentCompressorProvider.ReleaseGzipReader(gzipReader) - gzipReader.Reset(r.Request.Body) - r.Request.Body = gzipReader - } else if ENCODING_DEFLATE == contentEncoding { - zlibReader, err := zlib.NewReader(r.Request.Body) - if err != nil { - return err - } - r.Request.Body = zlibReader - } - - // lookup the EntityReader, use defaultRequestContentType if needed and provided - entityReader, ok := entityAccessRegistry.accessorAt(contentType) - if !ok { - if len(defaultRequestContentType) != 0 { - entityReader, ok = entityAccessRegistry.accessorAt(defaultRequestContentType) - } - if !ok { - return NewError(http.StatusBadRequest, "Unable to unmarshal content of type:"+contentType) - } - } - return entityReader.Read(r, entityPointer) -} - -// SetAttribute adds or replaces the attribute with the given value. -func (r *Request) SetAttribute(name string, value interface{}) { - r.attributes[name] = value -} - -// Attribute returns the value associated to the given name. Returns nil if absent. -func (r Request) Attribute(name string) interface{} { - return r.attributes[name] -} - -// SelectedRoutePath root path + route path that matched the request, e.g. /meetings/{id}/attendees -func (r Request) SelectedRoutePath() string { - return r.selectedRoutePath -} diff --git a/cmd/vendor/github.com/emicklei/go-restful/response.go b/cmd/vendor/github.com/emicklei/go-restful/response.go deleted file mode 100644 index 3b33ab220a..0000000000 --- a/cmd/vendor/github.com/emicklei/go-restful/response.go +++ /dev/null @@ -1,236 +0,0 @@ -package restful - -// Copyright 2013 Ernest Micklei. All rights reserved. -// Use of this source code is governed by a license -// that can be found in the LICENSE file. - -import ( - "errors" - "net/http" -) - -// DefaultResponseMimeType is DEPRECATED, use DefaultResponseContentType(mime) -var DefaultResponseMimeType string - -//PrettyPrintResponses controls the indentation feature of XML and JSON serialization -var PrettyPrintResponses = true - -// Response is a wrapper on the actual http ResponseWriter -// It provides several convenience methods to prepare and write response content. -type Response struct { - http.ResponseWriter - requestAccept string // mime-type what the Http Request says it wants to receive - routeProduces []string // mime-types what the Route says it can produce - statusCode int // HTTP status code that has been written explicity (if zero then net/http has written 200) - contentLength int // number of bytes written for the response body - prettyPrint bool // controls the indentation feature of XML and JSON serialization. It is initialized using var PrettyPrintResponses. - err error // err property is kept when WriteError is called -} - -// NewResponse creates a new response based on a http ResponseWriter. -func NewResponse(httpWriter http.ResponseWriter) *Response { - return &Response{httpWriter, "", []string{}, http.StatusOK, 0, PrettyPrintResponses, nil} // empty content-types -} - -// DefaultResponseContentType set a default. -// If Accept header matching fails, fall back to this type. -// Valid values are restful.MIME_JSON and restful.MIME_XML -// Example: -// restful.DefaultResponseContentType(restful.MIME_JSON) -func DefaultResponseContentType(mime string) { - DefaultResponseMimeType = mime -} - -// InternalServerError writes the StatusInternalServerError header. -// DEPRECATED, use WriteErrorString(http.StatusInternalServerError,reason) -func (r Response) InternalServerError() Response { - r.WriteHeader(http.StatusInternalServerError) - return r -} - -// PrettyPrint changes whether this response must produce pretty (line-by-line, indented) JSON or XML output. -func (r *Response) PrettyPrint(bePretty bool) { - r.prettyPrint = bePretty -} - -// AddHeader is a shortcut for .Header().Add(header,value) -func (r Response) AddHeader(header string, value string) Response { - r.Header().Add(header, value) - return r -} - -// SetRequestAccepts tells the response what Mime-type(s) the HTTP request said it wants to accept. Exposed for testing. -func (r *Response) SetRequestAccepts(mime string) { - r.requestAccept = mime -} - -// EntityWriter returns the registered EntityWriter that the entity (requested resource) -// can write according to what the request wants (Accept) and what the Route can produce or what the restful defaults say. -// If called before WriteEntity and WriteHeader then a false return value can be used to write a 406: Not Acceptable. -func (r *Response) EntityWriter() (EntityReaderWriter, bool) { - sorted := sortedMimes(r.requestAccept) - for _, eachAccept := range sorted { - for _, eachProduce := range r.routeProduces { - if eachProduce == eachAccept.media { - if w, ok := entityAccessRegistry.accessorAt(eachAccept.media); ok { - return w, true - } - } - } - if eachAccept.media == "*/*" { - for _, each := range r.routeProduces { - if w, ok := entityAccessRegistry.accessorAt(each); ok { - return w, true - } - } - } - } - // if requestAccept is empty - writer, ok := entityAccessRegistry.accessorAt(r.requestAccept) - if !ok { - // if not registered then fallback to the defaults (if set) - if DefaultResponseMimeType == MIME_JSON { - return entityAccessRegistry.accessorAt(MIME_JSON) - } - if DefaultResponseMimeType == MIME_XML { - return entityAccessRegistry.accessorAt(MIME_XML) - } - // Fallback to whatever the route says it can produce. - // https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html - for _, each := range r.routeProduces { - if w, ok := entityAccessRegistry.accessorAt(each); ok { - return w, true - } - } - if trace { - traceLogger.Printf("no registered EntityReaderWriter found for %s", r.requestAccept) - } - } - return writer, ok -} - -// WriteEntity calls WriteHeaderAndEntity with Http Status OK (200) -func (r *Response) WriteEntity(value interface{}) error { - return r.WriteHeaderAndEntity(http.StatusOK, value) -} - -// WriteHeaderAndEntity marshals the value using the representation denoted by the Accept Header and the registered EntityWriters. -// If no Accept header is specified (or */*) then respond with the Content-Type as specified by the first in the Route.Produces. -// If an Accept header is specified then respond with the Content-Type as specified by the first in the Route.Produces that is matched with the Accept header. -// If the value is nil then no response is send except for the Http status. You may want to call WriteHeader(http.StatusNotFound) instead. -// If there is no writer available that can represent the value in the requested MIME type then Http Status NotAcceptable is written. -// Current implementation ignores any q-parameters in the Accept Header. -// Returns an error if the value could not be written on the response. -func (r *Response) WriteHeaderAndEntity(status int, value interface{}) error { - writer, ok := r.EntityWriter() - if !ok { - r.WriteHeader(http.StatusNotAcceptable) - return nil - } - return writer.Write(r, status, value) -} - -// WriteAsXml is a convenience method for writing a value in xml (requires Xml tags on the value) -// It uses the standard encoding/xml package for marshalling the value ; not using a registered EntityReaderWriter. -func (r *Response) WriteAsXml(value interface{}) error { - return writeXML(r, http.StatusOK, MIME_XML, value) -} - -// WriteHeaderAndXml is a convenience method for writing a status and value in xml (requires Xml tags on the value) -// It uses the standard encoding/xml package for marshalling the value ; not using a registered EntityReaderWriter. -func (r *Response) WriteHeaderAndXml(status int, value interface{}) error { - return writeXML(r, status, MIME_XML, value) -} - -// WriteAsJson is a convenience method for writing a value in json. -// It uses the standard encoding/json package for marshalling the value ; not using a registered EntityReaderWriter. -func (r *Response) WriteAsJson(value interface{}) error { - return writeJSON(r, http.StatusOK, MIME_JSON, value) -} - -// WriteJson is a convenience method for writing a value in Json with a given Content-Type. -// It uses the standard encoding/json package for marshalling the value ; not using a registered EntityReaderWriter. -func (r *Response) WriteJson(value interface{}, contentType string) error { - return writeJSON(r, http.StatusOK, contentType, value) -} - -// WriteHeaderAndJson is a convenience method for writing the status and a value in Json with a given Content-Type. -// It uses the standard encoding/json package for marshalling the value ; not using a registered EntityReaderWriter. -func (r *Response) WriteHeaderAndJson(status int, value interface{}, contentType string) error { - return writeJSON(r, status, contentType, value) -} - -// WriteError write the http status and the error string on the response. -func (r *Response) WriteError(httpStatus int, err error) error { - r.err = err - return r.WriteErrorString(httpStatus, err.Error()) -} - -// WriteServiceError is a convenience method for a responding with a status and a ServiceError -func (r *Response) WriteServiceError(httpStatus int, err ServiceError) error { - r.err = err - return r.WriteHeaderAndEntity(httpStatus, err) -} - -// WriteErrorString is a convenience method for an error status with the actual error -func (r *Response) WriteErrorString(httpStatus int, errorReason string) error { - if r.err == nil { - // if not called from WriteError - r.err = errors.New(errorReason) - } - r.WriteHeader(httpStatus) - if _, err := r.Write([]byte(errorReason)); err != nil { - return err - } - return nil -} - -// Flush implements http.Flusher interface, which sends any buffered data to the client. -func (r *Response) Flush() { - if f, ok := r.ResponseWriter.(http.Flusher); ok { - f.Flush() - } else if trace { - traceLogger.Printf("ResponseWriter %v doesn't support Flush", r) - } -} - -// WriteHeader is overridden to remember the Status Code that has been written. -// Changes to the Header of the response have no effect after this. -func (r *Response) WriteHeader(httpStatus int) { - r.statusCode = httpStatus - r.ResponseWriter.WriteHeader(httpStatus) -} - -// StatusCode returns the code that has been written using WriteHeader. -func (r Response) StatusCode() int { - if 0 == r.statusCode { - // no status code has been written yet; assume OK - return http.StatusOK - } - return r.statusCode -} - -// Write writes the data to the connection as part of an HTTP reply. -// Write is part of http.ResponseWriter interface. -func (r *Response) Write(bytes []byte) (int, error) { - written, err := r.ResponseWriter.Write(bytes) - r.contentLength += written - return written, err -} - -// ContentLength returns the number of bytes written for the response content. -// Note that this value is only correct if all data is written through the Response using its Write* methods. -// Data written directly using the underlying http.ResponseWriter is not accounted for. -func (r Response) ContentLength() int { - return r.contentLength -} - -// CloseNotify is part of http.CloseNotifier interface -func (r Response) CloseNotify() <-chan bool { - return r.ResponseWriter.(http.CloseNotifier).CloseNotify() -} - -// Error returns the err created by WriteError -func (r Response) Error() error { - return r.err -} diff --git a/cmd/vendor/github.com/emicklei/go-restful/route.go b/cmd/vendor/github.com/emicklei/go-restful/route.go deleted file mode 100644 index 3dd520eec8..0000000000 --- a/cmd/vendor/github.com/emicklei/go-restful/route.go +++ /dev/null @@ -1,186 +0,0 @@ -package restful - -// Copyright 2013 Ernest Micklei. All rights reserved. -// Use of this source code is governed by a license -// that can be found in the LICENSE file. - -import ( - "bytes" - "net/http" - "strings" -) - -// RouteFunction declares the signature of a function that can be bound to a Route. -type RouteFunction func(*Request, *Response) - -// Route binds a HTTP Method,Path,Consumes combination to a RouteFunction. -type Route struct { - Method string - Produces []string - Consumes []string - Path string // webservice root path + described path - Function RouteFunction - Filters []FilterFunction - - // cached values for dispatching - relativePath string - pathParts []string - pathExpr *pathExpression // cached compilation of relativePath as RegExp - - // documentation - Doc string - Notes string - Operation string - ParameterDocs []*Parameter - ResponseErrors map[int]ResponseError - ReadSample, WriteSample interface{} // structs that model an example request or response payload - - // Extra information used to store custom information about the route. - Metadata map[string]interface{} -} - -// Initialize for Route -func (r *Route) postBuild() { - r.pathParts = tokenizePath(r.Path) -} - -// Create Request and Response from their http versions -func (r *Route) wrapRequestResponse(httpWriter http.ResponseWriter, httpRequest *http.Request) (*Request, *Response) { - params := r.extractParameters(httpRequest.URL.Path) - wrappedRequest := NewRequest(httpRequest) - wrappedRequest.pathParameters = params - wrappedRequest.selectedRoutePath = r.Path - wrappedResponse := NewResponse(httpWriter) - wrappedResponse.requestAccept = httpRequest.Header.Get(HEADER_Accept) - wrappedResponse.routeProduces = r.Produces - return wrappedRequest, wrappedResponse -} - -// dispatchWithFilters call the function after passing through its own filters -func (r *Route) dispatchWithFilters(wrappedRequest *Request, wrappedResponse *Response) { - if len(r.Filters) > 0 { - chain := FilterChain{Filters: r.Filters, Target: r.Function} - chain.ProcessFilter(wrappedRequest, wrappedResponse) - } else { - // unfiltered - r.Function(wrappedRequest, wrappedResponse) - } -} - -// Return whether the mimeType matches to what this Route can produce. -func (r Route) matchesAccept(mimeTypesWithQuality string) bool { - parts := strings.Split(mimeTypesWithQuality, ",") - for _, each := range parts { - var withoutQuality string - if strings.Contains(each, ";") { - withoutQuality = strings.Split(each, ";")[0] - } else { - withoutQuality = each - } - // trim before compare - withoutQuality = strings.Trim(withoutQuality, " ") - if withoutQuality == "*/*" { - return true - } - for _, producibleType := range r.Produces { - if producibleType == "*/*" || producibleType == withoutQuality { - return true - } - } - } - return false -} - -// Return whether this Route can consume content with a type specified by mimeTypes (can be empty). -func (r Route) matchesContentType(mimeTypes string) bool { - - if len(r.Consumes) == 0 { - // did not specify what it can consume ; any media type (“*/*”) is assumed - return true - } - - if len(mimeTypes) == 0 { - // idempotent methods with (most-likely or garanteed) empty content match missing Content-Type - m := r.Method - if m == "GET" || m == "HEAD" || m == "OPTIONS" || m == "DELETE" || m == "TRACE" { - return true - } - // proceed with default - mimeTypes = MIME_OCTET - } - - parts := strings.Split(mimeTypes, ",") - for _, each := range parts { - var contentType string - if strings.Contains(each, ";") { - contentType = strings.Split(each, ";")[0] - } else { - contentType = each - } - // trim before compare - contentType = strings.Trim(contentType, " ") - for _, consumeableType := range r.Consumes { - if consumeableType == "*/*" || consumeableType == contentType { - return true - } - } - } - return false -} - -// Extract the parameters from the request url path -func (r Route) extractParameters(urlPath string) map[string]string { - urlParts := tokenizePath(urlPath) - pathParameters := map[string]string{} - for i, key := range r.pathParts { - var value string - if i >= len(urlParts) { - value = "" - } else { - value = urlParts[i] - } - if strings.HasPrefix(key, "{") { // path-parameter - if colon := strings.Index(key, ":"); colon != -1 { - // extract by regex - regPart := key[colon+1 : len(key)-1] - keyPart := key[1:colon] - if regPart == "*" { - pathParameters[keyPart] = untokenizePath(i, urlParts) - break - } else { - pathParameters[keyPart] = value - } - } else { - // without enclosing {} - pathParameters[key[1:len(key)-1]] = value - } - } - } - return pathParameters -} - -// Untokenize back into an URL path using the slash separator -func untokenizePath(offset int, parts []string) string { - var buffer bytes.Buffer - for p := offset; p < len(parts); p++ { - buffer.WriteString(parts[p]) - // do not end - if p < len(parts)-1 { - buffer.WriteString("/") - } - } - return buffer.String() -} - -// Tokenize an URL path using the slash separator ; the result does not have empty tokens -func tokenizePath(path string) []string { - if "/" == path { - return []string{} - } - return strings.Split(strings.Trim(path, "/"), "/") -} - -// for debugging -func (r Route) String() string { - return r.Method + " " + r.Path -} diff --git a/cmd/vendor/github.com/emicklei/go-restful/route_builder.go b/cmd/vendor/github.com/emicklei/go-restful/route_builder.go deleted file mode 100644 index 5ad4a3a7cf..0000000000 --- a/cmd/vendor/github.com/emicklei/go-restful/route_builder.go +++ /dev/null @@ -1,293 +0,0 @@ -package restful - -// Copyright 2013 Ernest Micklei. All rights reserved. -// Use of this source code is governed by a license -// that can be found in the LICENSE file. - -import ( - "fmt" - "os" - "reflect" - "runtime" - "strings" - "sync/atomic" - - "github.com/emicklei/go-restful/log" -) - -// RouteBuilder is a helper to construct Routes. -type RouteBuilder struct { - rootPath string - currentPath string - produces []string - consumes []string - httpMethod string // required - function RouteFunction // required - filters []FilterFunction - - typeNameHandleFunc TypeNameHandleFunction // required - - // documentation - doc string - notes string - operation string - readSample, writeSample interface{} - parameters []*Parameter - errorMap map[int]ResponseError - metadata map[string]interface{} -} - -// Do evaluates each argument with the RouteBuilder itself. -// This allows you to follow DRY principles without breaking the fluent programming style. -// Example: -// ws.Route(ws.DELETE("/{name}").To(t.deletePerson).Do(Returns200, Returns500)) -// -// func Returns500(b *RouteBuilder) { -// b.Returns(500, "Internal Server Error", restful.ServiceError{}) -// } -func (b *RouteBuilder) Do(oneArgBlocks ...func(*RouteBuilder)) *RouteBuilder { - for _, each := range oneArgBlocks { - each(b) - } - return b -} - -// To bind the route to a function. -// If this route is matched with the incoming Http Request then call this function with the *Request,*Response pair. Required. -func (b *RouteBuilder) To(function RouteFunction) *RouteBuilder { - b.function = function - return b -} - -// Method specifies what HTTP method to match. Required. -func (b *RouteBuilder) Method(method string) *RouteBuilder { - b.httpMethod = method - return b -} - -// Produces specifies what MIME types can be produced ; the matched one will appear in the Content-Type Http header. -func (b *RouteBuilder) Produces(mimeTypes ...string) *RouteBuilder { - b.produces = mimeTypes - return b -} - -// Consumes specifies what MIME types can be consumes ; the Accept Http header must matched any of these -func (b *RouteBuilder) Consumes(mimeTypes ...string) *RouteBuilder { - b.consumes = mimeTypes - return b -} - -// Path specifies the relative (w.r.t WebService root path) URL path to match. Default is "/". -func (b *RouteBuilder) Path(subPath string) *RouteBuilder { - b.currentPath = subPath - return b -} - -// Doc tells what this route is all about. Optional. -func (b *RouteBuilder) Doc(documentation string) *RouteBuilder { - b.doc = documentation - return b -} - -// A verbose explanation of the operation behavior. Optional. -func (b *RouteBuilder) Notes(notes string) *RouteBuilder { - b.notes = notes - return b -} - -// Reads tells what resource type will be read from the request payload. Optional. -// A parameter of type "body" is added ,required is set to true and the dataType is set to the qualified name of the sample's type. -func (b *RouteBuilder) Reads(sample interface{}) *RouteBuilder { - fn := b.typeNameHandleFunc - if fn == nil { - fn = reflectTypeName - } - typeAsName := fn(sample) - - b.readSample = sample - bodyParameter := &Parameter{&ParameterData{Name: "body"}} - bodyParameter.beBody() - bodyParameter.Required(true) - bodyParameter.DataType(typeAsName) - b.Param(bodyParameter) - return b -} - -// ParameterNamed returns a Parameter already known to the RouteBuilder. Returns nil if not. -// Use this to modify or extend information for the Parameter (through its Data()). -func (b RouteBuilder) ParameterNamed(name string) (p *Parameter) { - for _, each := range b.parameters { - if each.Data().Name == name { - return each - } - } - return p -} - -// Writes tells what resource type will be written as the response payload. Optional. -func (b *RouteBuilder) Writes(sample interface{}) *RouteBuilder { - b.writeSample = sample - return b -} - -// Param allows you to document the parameters of the Route. It adds a new Parameter (does not check for duplicates). -func (b *RouteBuilder) Param(parameter *Parameter) *RouteBuilder { - if b.parameters == nil { - b.parameters = []*Parameter{} - } - b.parameters = append(b.parameters, parameter) - return b -} - -// Operation allows you to document what the actual method/function call is of the Route. -// Unless called, the operation name is derived from the RouteFunction set using To(..). -func (b *RouteBuilder) Operation(name string) *RouteBuilder { - b.operation = name - return b -} - -// ReturnsError is deprecated, use Returns instead. -func (b *RouteBuilder) ReturnsError(code int, message string, model interface{}) *RouteBuilder { - log.Print("ReturnsError is deprecated, use Returns instead.") - return b.Returns(code, message, model) -} - -// Returns allows you to document what responses (errors or regular) can be expected. -// The model parameter is optional ; either pass a struct instance or use nil if not applicable. -func (b *RouteBuilder) Returns(code int, message string, model interface{}) *RouteBuilder { - err := ResponseError{ - Code: code, - Message: message, - Model: model, - IsDefault: false, - } - // lazy init because there is no NewRouteBuilder (yet) - if b.errorMap == nil { - b.errorMap = map[int]ResponseError{} - } - b.errorMap[code] = err - return b -} - -// DefaultReturns is a special Returns call that sets the default of the response ; the code is zero. -func (b *RouteBuilder) DefaultReturns(message string, model interface{}) *RouteBuilder { - b.Returns(0, message, model) - // Modify the ResponseError just added/updated - re := b.errorMap[0] - // errorMap is initialized - b.errorMap[0] = ResponseError{ - Code: re.Code, - Message: re.Message, - Model: re.Model, - IsDefault: true, - } - return b -} - -// Metadata adds or updates a key=value pair to the metadata map. -func (b *RouteBuilder) Metadata(key string, value interface{}) *RouteBuilder { - if b.metadata == nil { - b.metadata = map[string]interface{}{} - } - b.metadata[key] = value - return b -} - -// ResponseError represents a response; not necessarily an error. -type ResponseError struct { - Code int - Message string - Model interface{} - IsDefault bool -} - -func (b *RouteBuilder) servicePath(path string) *RouteBuilder { - b.rootPath = path - return b -} - -// Filter appends a FilterFunction to the end of filters for this Route to build. -func (b *RouteBuilder) Filter(filter FilterFunction) *RouteBuilder { - b.filters = append(b.filters, filter) - return b -} - -// If no specific Route path then set to rootPath -// If no specific Produces then set to rootProduces -// If no specific Consumes then set to rootConsumes -func (b *RouteBuilder) copyDefaults(rootProduces, rootConsumes []string) { - if len(b.produces) == 0 { - b.produces = rootProduces - } - if len(b.consumes) == 0 { - b.consumes = rootConsumes - } -} - -// typeNameHandler sets the function that will convert types to strings in the parameter -// and model definitions. -func (b *RouteBuilder) typeNameHandler(handler TypeNameHandleFunction) *RouteBuilder { - b.typeNameHandleFunc = handler - return b -} - -// Build creates a new Route using the specification details collected by the RouteBuilder -func (b *RouteBuilder) Build() Route { - pathExpr, err := newPathExpression(b.currentPath) - if err != nil { - log.Printf("[restful] Invalid path:%s because:%v", b.currentPath, err) - os.Exit(1) - } - if b.function == nil { - log.Printf("[restful] No function specified for route:" + b.currentPath) - os.Exit(1) - } - operationName := b.operation - if len(operationName) == 0 && b.function != nil { - // extract from definition - operationName = nameOfFunction(b.function) - } - route := Route{ - Method: b.httpMethod, - Path: concatPath(b.rootPath, b.currentPath), - Produces: b.produces, - Consumes: b.consumes, - Function: b.function, - Filters: b.filters, - relativePath: b.currentPath, - pathExpr: pathExpr, - Doc: b.doc, - Notes: b.notes, - Operation: operationName, - ParameterDocs: b.parameters, - ResponseErrors: b.errorMap, - ReadSample: b.readSample, - WriteSample: b.writeSample, - Metadata: b.metadata} - route.postBuild() - return route -} - -func concatPath(path1, path2 string) string { - return strings.TrimRight(path1, "/") + "/" + strings.TrimLeft(path2, "/") -} - -var anonymousFuncCount int32 - -// nameOfFunction returns the short name of the function f for documentation. -// It uses a runtime feature for debugging ; its value may change for later Go versions. -func nameOfFunction(f interface{}) string { - fun := runtime.FuncForPC(reflect.ValueOf(f).Pointer()) - tokenized := strings.Split(fun.Name(), ".") - last := tokenized[len(tokenized)-1] - last = strings.TrimSuffix(last, ")·fm") // < Go 1.5 - last = strings.TrimSuffix(last, ")-fm") // Go 1.5 - last = strings.TrimSuffix(last, "·fm") // < Go 1.5 - last = strings.TrimSuffix(last, "-fm") // Go 1.5 - if last == "func1" { // this could mean conflicts in API docs - val := atomic.AddInt32(&anonymousFuncCount, 1) - last = "func" + fmt.Sprintf("%d", val) - atomic.StoreInt32(&anonymousFuncCount, val) - } - return last -} diff --git a/cmd/vendor/github.com/emicklei/go-restful/router.go b/cmd/vendor/github.com/emicklei/go-restful/router.go deleted file mode 100644 index 9b32fb6753..0000000000 --- a/cmd/vendor/github.com/emicklei/go-restful/router.go +++ /dev/null @@ -1,18 +0,0 @@ -package restful - -// Copyright 2013 Ernest Micklei. All rights reserved. -// Use of this source code is governed by a license -// that can be found in the LICENSE file. - -import "net/http" - -// A RouteSelector finds the best matching Route given the input HTTP Request -type RouteSelector interface { - - // SelectRoute finds a Route given the input HTTP Request and a list of WebServices. - // It returns a selected Route and its containing WebService or an error indicating - // a problem. - SelectRoute( - webServices []*WebService, - httpRequest *http.Request) (selectedService *WebService, selected *Route, err error) -} diff --git a/cmd/vendor/github.com/emicklei/go-restful/service_error.go b/cmd/vendor/github.com/emicklei/go-restful/service_error.go deleted file mode 100644 index 62d1108bbd..0000000000 --- a/cmd/vendor/github.com/emicklei/go-restful/service_error.go +++ /dev/null @@ -1,23 +0,0 @@ -package restful - -// Copyright 2013 Ernest Micklei. All rights reserved. -// Use of this source code is governed by a license -// that can be found in the LICENSE file. - -import "fmt" - -// ServiceError is a transport object to pass information about a non-Http error occurred in a WebService while processing a request. -type ServiceError struct { - Code int - Message string -} - -// NewError returns a ServiceError using the code and reason -func NewError(code int, message string) ServiceError { - return ServiceError{Code: code, Message: message} -} - -// Error returns a text representation of the service error -func (s ServiceError) Error() string { - return fmt.Sprintf("[ServiceError:%v] %v", s.Code, s.Message) -} diff --git a/cmd/vendor/github.com/emicklei/go-restful/web_service.go b/cmd/vendor/github.com/emicklei/go-restful/web_service.go deleted file mode 100644 index 7af60233a0..0000000000 --- a/cmd/vendor/github.com/emicklei/go-restful/web_service.go +++ /dev/null @@ -1,290 +0,0 @@ -package restful - -import ( - "errors" - "os" - "reflect" - "sync" - - "github.com/emicklei/go-restful/log" -) - -// Copyright 2013 Ernest Micklei. All rights reserved. -// Use of this source code is governed by a license -// that can be found in the LICENSE file. - -// WebService holds a collection of Route values that bind a Http Method + URL Path to a function. -type WebService struct { - rootPath string - pathExpr *pathExpression // cached compilation of rootPath as RegExp - routes []Route - produces []string - consumes []string - pathParameters []*Parameter - filters []FilterFunction - documentation string - apiVersion string - - typeNameHandleFunc TypeNameHandleFunction - - dynamicRoutes bool - - // protects 'routes' if dynamic routes are enabled - routesLock sync.RWMutex -} - -func (w *WebService) SetDynamicRoutes(enable bool) { - w.dynamicRoutes = enable -} - -// TypeNameHandleFunction declares functions that can handle translating the name of a sample object -// into the restful documentation for the service. -type TypeNameHandleFunction func(sample interface{}) string - -// TypeNameHandler sets the function that will convert types to strings in the parameter -// and model definitions. If not set, the web service will invoke -// reflect.TypeOf(object).String(). -func (w *WebService) TypeNameHandler(handler TypeNameHandleFunction) *WebService { - w.typeNameHandleFunc = handler - return w -} - -// reflectTypeName is the default TypeNameHandleFunction and for a given object -// returns the name that Go identifies it with (e.g. "string" or "v1.Object") via -// the reflection API. -func reflectTypeName(sample interface{}) string { - return reflect.TypeOf(sample).String() -} - -// compilePathExpression ensures that the path is compiled into a RegEx for those routers that need it. -func (w *WebService) compilePathExpression() { - compiled, err := newPathExpression(w.rootPath) - if err != nil { - log.Printf("[restful] invalid path:%s because:%v", w.rootPath, err) - os.Exit(1) - } - w.pathExpr = compiled -} - -// ApiVersion sets the API version for documentation purposes. -func (w *WebService) ApiVersion(apiVersion string) *WebService { - w.apiVersion = apiVersion - return w -} - -// Version returns the API version for documentation purposes. -func (w *WebService) Version() string { return w.apiVersion } - -// Path specifies the root URL template path of the WebService. -// All Routes will be relative to this path. -func (w *WebService) Path(root string) *WebService { - w.rootPath = root - if len(w.rootPath) == 0 { - w.rootPath = "/" - } - w.compilePathExpression() - return w -} - -// Param adds a PathParameter to document parameters used in the root path. -func (w *WebService) Param(parameter *Parameter) *WebService { - if w.pathParameters == nil { - w.pathParameters = []*Parameter{} - } - w.pathParameters = append(w.pathParameters, parameter) - return w -} - -// PathParameter creates a new Parameter of kind Path for documentation purposes. -// It is initialized as required with string as its DataType. -func (w *WebService) PathParameter(name, description string) *Parameter { - return PathParameter(name, description) -} - -// PathParameter creates a new Parameter of kind Path for documentation purposes. -// It is initialized as required with string as its DataType. -func PathParameter(name, description string) *Parameter { - p := &Parameter{&ParameterData{Name: name, Description: description, Required: true, DataType: "string"}} - p.bePath() - return p -} - -// QueryParameter creates a new Parameter of kind Query for documentation purposes. -// It is initialized as not required with string as its DataType. -func (w *WebService) QueryParameter(name, description string) *Parameter { - return QueryParameter(name, description) -} - -// QueryParameter creates a new Parameter of kind Query for documentation purposes. -// It is initialized as not required with string as its DataType. -func QueryParameter(name, description string) *Parameter { - p := &Parameter{&ParameterData{Name: name, Description: description, Required: false, DataType: "string"}} - p.beQuery() - return p -} - -// BodyParameter creates a new Parameter of kind Body for documentation purposes. -// It is initialized as required without a DataType. -func (w *WebService) BodyParameter(name, description string) *Parameter { - return BodyParameter(name, description) -} - -// BodyParameter creates a new Parameter of kind Body for documentation purposes. -// It is initialized as required without a DataType. -func BodyParameter(name, description string) *Parameter { - p := &Parameter{&ParameterData{Name: name, Description: description, Required: true}} - p.beBody() - return p -} - -// HeaderParameter creates a new Parameter of kind (Http) Header for documentation purposes. -// It is initialized as not required with string as its DataType. -func (w *WebService) HeaderParameter(name, description string) *Parameter { - return HeaderParameter(name, description) -} - -// HeaderParameter creates a new Parameter of kind (Http) Header for documentation purposes. -// It is initialized as not required with string as its DataType. -func HeaderParameter(name, description string) *Parameter { - p := &Parameter{&ParameterData{Name: name, Description: description, Required: false, DataType: "string"}} - p.beHeader() - return p -} - -// FormParameter creates a new Parameter of kind Form (using application/x-www-form-urlencoded) for documentation purposes. -// It is initialized as required with string as its DataType. -func (w *WebService) FormParameter(name, description string) *Parameter { - return FormParameter(name, description) -} - -// FormParameter creates a new Parameter of kind Form (using application/x-www-form-urlencoded) for documentation purposes. -// It is initialized as required with string as its DataType. -func FormParameter(name, description string) *Parameter { - p := &Parameter{&ParameterData{Name: name, Description: description, Required: false, DataType: "string"}} - p.beForm() - return p -} - -// Route creates a new Route using the RouteBuilder and add to the ordered list of Routes. -func (w *WebService) Route(builder *RouteBuilder) *WebService { - w.routesLock.Lock() - defer w.routesLock.Unlock() - builder.copyDefaults(w.produces, w.consumes) - w.routes = append(w.routes, builder.Build()) - return w -} - -// RemoveRoute removes the specified route, looks for something that matches 'path' and 'method' -func (w *WebService) RemoveRoute(path, method string) error { - if !w.dynamicRoutes { - return errors.New("dynamic routes are not enabled.") - } - w.routesLock.Lock() - defer w.routesLock.Unlock() - newRoutes := make([]Route, (len(w.routes) - 1)) - current := 0 - for ix := range w.routes { - if w.routes[ix].Method == method && w.routes[ix].Path == path { - continue - } - newRoutes[current] = w.routes[ix] - current = current + 1 - } - w.routes = newRoutes - return nil -} - -// Method creates a new RouteBuilder and initialize its http method -func (w *WebService) Method(httpMethod string) *RouteBuilder { - return new(RouteBuilder).typeNameHandler(w.typeNameHandleFunc).servicePath(w.rootPath).Method(httpMethod) -} - -// Produces specifies that this WebService can produce one or more MIME types. -// Http requests must have one of these values set for the Accept header. -func (w *WebService) Produces(contentTypes ...string) *WebService { - w.produces = contentTypes - return w -} - -// Consumes specifies that this WebService can consume one or more MIME types. -// Http requests must have one of these values set for the Content-Type header. -func (w *WebService) Consumes(accepts ...string) *WebService { - w.consumes = accepts - return w -} - -// Routes returns the Routes associated with this WebService -func (w *WebService) Routes() []Route { - if !w.dynamicRoutes { - return w.routes - } - // Make a copy of the array to prevent concurrency problems - w.routesLock.RLock() - defer w.routesLock.RUnlock() - result := make([]Route, len(w.routes)) - for ix := range w.routes { - result[ix] = w.routes[ix] - } - return result -} - -// RootPath returns the RootPath associated with this WebService. Default "/" -func (w *WebService) RootPath() string { - return w.rootPath -} - -// PathParameters return the path parameter names for (shared amoung its Routes) -func (w *WebService) PathParameters() []*Parameter { - return w.pathParameters -} - -// Filter adds a filter function to the chain of filters applicable to all its Routes -func (w *WebService) Filter(filter FilterFunction) *WebService { - w.filters = append(w.filters, filter) - return w -} - -// Doc is used to set the documentation of this service. -func (w *WebService) Doc(plainText string) *WebService { - w.documentation = plainText - return w -} - -// Documentation returns it. -func (w *WebService) Documentation() string { - return w.documentation -} - -/* - Convenience methods -*/ - -// HEAD is a shortcut for .Method("HEAD").Path(subPath) -func (w *WebService) HEAD(subPath string) *RouteBuilder { - return new(RouteBuilder).typeNameHandler(w.typeNameHandleFunc).servicePath(w.rootPath).Method("HEAD").Path(subPath) -} - -// GET is a shortcut for .Method("GET").Path(subPath) -func (w *WebService) GET(subPath string) *RouteBuilder { - return new(RouteBuilder).typeNameHandler(w.typeNameHandleFunc).servicePath(w.rootPath).Method("GET").Path(subPath) -} - -// POST is a shortcut for .Method("POST").Path(subPath) -func (w *WebService) POST(subPath string) *RouteBuilder { - return new(RouteBuilder).typeNameHandler(w.typeNameHandleFunc).servicePath(w.rootPath).Method("POST").Path(subPath) -} - -// PUT is a shortcut for .Method("PUT").Path(subPath) -func (w *WebService) PUT(subPath string) *RouteBuilder { - return new(RouteBuilder).typeNameHandler(w.typeNameHandleFunc).servicePath(w.rootPath).Method("PUT").Path(subPath) -} - -// PATCH is a shortcut for .Method("PATCH").Path(subPath) -func (w *WebService) PATCH(subPath string) *RouteBuilder { - return new(RouteBuilder).typeNameHandler(w.typeNameHandleFunc).servicePath(w.rootPath).Method("PATCH").Path(subPath) -} - -// DELETE is a shortcut for .Method("DELETE").Path(subPath) -func (w *WebService) DELETE(subPath string) *RouteBuilder { - return new(RouteBuilder).typeNameHandler(w.typeNameHandleFunc).servicePath(w.rootPath).Method("DELETE").Path(subPath) -} diff --git a/cmd/vendor/github.com/emicklei/go-restful/web_service_container.go b/cmd/vendor/github.com/emicklei/go-restful/web_service_container.go deleted file mode 100644 index c9d31b06c4..0000000000 --- a/cmd/vendor/github.com/emicklei/go-restful/web_service_container.go +++ /dev/null @@ -1,39 +0,0 @@ -package restful - -// Copyright 2013 Ernest Micklei. All rights reserved. -// Use of this source code is governed by a license -// that can be found in the LICENSE file. - -import ( - "net/http" -) - -// DefaultContainer is a restful.Container that uses http.DefaultServeMux -var DefaultContainer *Container - -func init() { - DefaultContainer = NewContainer() - DefaultContainer.ServeMux = http.DefaultServeMux -} - -// If set the true then panics will not be caught to return HTTP 500. -// In that case, Route functions are responsible for handling any error situation. -// Default value is false = recover from panics. This has performance implications. -// OBSOLETE ; use restful.DefaultContainer.DoNotRecover(true) -var DoNotRecover = false - -// Add registers a new WebService add it to the DefaultContainer. -func Add(service *WebService) { - DefaultContainer.Add(service) -} - -// Filter appends a container FilterFunction from the DefaultContainer. -// These are called before dispatching a http.Request to a WebService. -func Filter(filter FilterFunction) { - DefaultContainer.Filter(filter) -} - -// RegisteredWebServices returns the collections of WebServices from the DefaultContainer -func RegisteredWebServices() []*WebService { - return DefaultContainer.RegisteredWebServices() -} diff --git a/cmd/vendor/sigs.k8s.io/controller-tools/LICENSE b/cmd/vendor/sigs.k8s.io/controller-tools/LICENSE new file mode 100644 index 0000000000..8dada3edaf --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/controller-tools/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/cmd/vendor/sigs.k8s.io/controller-tools/cmd/controller-scaffold/cmd/api.go b/cmd/vendor/sigs.k8s.io/controller-tools/cmd/controller-scaffold/cmd/api.go new file mode 100644 index 0000000000..ae14b033b0 --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/controller-tools/cmd/controller-scaffold/cmd/api.go @@ -0,0 +1,163 @@ +// Copyright © 2018 NAME HERE +// +// 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 cmd + +import ( + "fmt" + "log" + "os" + "os/exec" + "path/filepath" + "strings" + + "github.com/spf13/cobra" + flag "github.com/spf13/pflag" + "sigs.k8s.io/controller-tools/pkg/scaffold" + "sigs.k8s.io/controller-tools/pkg/scaffold/controller" + "sigs.k8s.io/controller-tools/pkg/scaffold/input" + "sigs.k8s.io/controller-tools/pkg/scaffold/resource" +) + +var r *resource.Resource +var resourceFlag, controllerFlag *flag.Flag +var doResource, doController, doMake bool + +// APICmd represents the resource command +var APICmd = &cobra.Command{ + Use: "api", + Short: "Scaffold a Kubernetes API", + Long: `Scaffold a Kubernetes API by creating a Resource definition and / or a Controller. + +api will prompt the user for if it should scaffold the Resource and / or Controller. To only +scaffold a Controller for an existing Resource, select "n" for Resource. To only define +the schema for a Resource without writing a Controller, select "n" for Controller. + +After the scaffold is written, api will run make on the project. +`, + Example: ` # Create a frigates API with Group: ship, Version: v1beta1 and Kind: Frigate + controller-scaffold api --group ship --version v1beta1 --kind Frigate + + # Edit the API Scheme + nano pkg/apis/ship/v1beta1/frigate_types.go + + # Edit the Controller + nano pkg/controller/frigate/frigate_controller.go + + # Edit the Controller Test + nano pkg/controller/frigate/frigate_controller_test.go + + # Install CRDs into the Kubernetes cluster using kubectl apply + make install + + # Regenerate code and run against the Kubernetes cluster configured by ~/.kube/config + make run +`, + Run: func(cmd *cobra.Command, args []string) { + DieIfNoProject() + + if !resourceFlag.Changed { + fmt.Println("Create Resource under pkg/apis [y/n]?") + doResource = yesno() + } + if !controllerFlag.Changed { + fmt.Println("Create Controller under pkg/controller [y/n]?") + doController = yesno() + } + + fmt.Println("Writing scaffold for you to edit...") + + if doResource { + fmt.Println(filepath.Join("pkg", "apis", r.Group, r.Version, + fmt.Sprintf("%s_types.go", strings.ToLower(r.Kind)))) + fmt.Println(filepath.Join("pkg", "apis", r.Group, r.Version, + fmt.Sprintf("%s_types_test.go", strings.ToLower(r.Kind)))) + + err := (&scaffold.Scaffold{}).Execute(input.Options{}, + &resource.Register{Resource: r}, + &resource.Types{Resource: r}, + &resource.VersionSuiteTest{Resource: r}, + &resource.TypesTest{Resource: r}, + &resource.Doc{Resource: r}, + &resource.Group{Resource: r}, + &resource.AddToScheme{Resource: r}, + &resource.CRD{Resource: r}, + &resource.Role{Resource: r}, + &resource.RoleBinding{Resource: r}, + ) + if err != nil { + log.Fatal(err) + } + } + + if doController { + fmt.Println(filepath.Join("pkg", "controller", strings.ToLower(r.Kind), + fmt.Sprintf("%s_controller.go", strings.ToLower(r.Kind)))) + fmt.Println(filepath.Join("pkg", "apis", strings.ToLower(r.Kind), + fmt.Sprintf("%s_controller_test.go", strings.ToLower(r.Kind)))) + + err := (&scaffold.Scaffold{}).Execute(input.Options{}, + &controller.Controller{Resource: r}, + &controller.AddController{Resource: r}, + &controller.Test{Resource: r}, + &controller.SuiteTest{Resource: r}, + ) + if err != nil { + log.Fatal(err) + } + } + + if doMake { + fmt.Println("Running make...") + cm := exec.Command("make") // #nosec + cm.Stderr = os.Stderr + cm.Stdout = os.Stdout + if err := cm.Run(); err != nil { + log.Fatal(err) + } + } + }, +} + +func init() { + rootCmd.AddCommand(APICmd) + APICmd.Flags().BoolVar(&doMake, "make", true, + "if true, run make after generating files") + APICmd.Flags().BoolVar(&doResource, "resource", true, + "if set, generate the resource without prompting the user") + resourceFlag = APICmd.Flag("resource") + APICmd.Flags().BoolVar(&doController, "controller", true, + "if set, generate the controller without prompting the user") + controllerFlag = APICmd.Flag("controller") + r = ResourceForFlags(APICmd.Flags()) +} + +// DieIfNoProject checks to make sure the command is run from a directory containing a project file. +func DieIfNoProject() { + if _, err := os.Stat("PROJECT"); os.IsNotExist(err) { + log.Fatalf("Command must be run from a diretory containing %s", "PROJECT") + } +} + +// ResourceForFlags registers flags for Resource fields and returns the Resource +func ResourceForFlags(f *flag.FlagSet) *resource.Resource { + r := &resource.Resource{} + f.StringVar(&r.Kind, "kind", "", "resource Kind") + f.StringVar(&r.Group, "group", "", "resource Group") + f.StringVar(&r.Version, "version", "", "resource Version") + f.BoolVar(&r.Namespaced, "namespaced", true, "true if the resource is namespaced") + f.BoolVar(&r.CreateExampleReconcileBody, "example", true, + "true if an example reconcile body should be written") + return r +} diff --git a/cmd/vendor/sigs.k8s.io/controller-tools/cmd/controller-scaffold/cmd/project.go b/cmd/vendor/sigs.k8s.io/controller-tools/cmd/controller-scaffold/cmd/project.go new file mode 100644 index 0000000000..da41c8253d --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/controller-tools/cmd/controller-scaffold/cmd/project.go @@ -0,0 +1,140 @@ +// Copyright © 2018 NAME HERE +// +// 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 cmd + +import ( + "fmt" + "log" + "os" + "os/exec" + "strings" + + "github.com/spf13/cobra" + flag "github.com/spf13/pflag" + "sigs.k8s.io/controller-tools/pkg/scaffold" + "sigs.k8s.io/controller-tools/pkg/scaffold/input" + "sigs.k8s.io/controller-tools/pkg/scaffold/manager" + "sigs.k8s.io/controller-tools/pkg/scaffold/project" +) + +var prj *project.Project +var bp *project.Boilerplate +var gopkg *project.GopkgToml +var mrg *manager.Cmd +var dkr *manager.Dockerfile +var dep bool +var depFlag *flag.Flag + +// ProjectCmd represents the project command +var ProjectCmd = &cobra.Command{ + Use: "project", + Short: "Scaffold a new project.", + Long: `Scaffold a project. + +Writes the following files: +- a boilerplate license file +- a PROJECT file with the domain and repo +- a Makefile to build the project +- a Gopkg.toml with project dependencies +- a cmd/manager/main.go to run + +project will prompt the user to run 'dep ensure' after writing the project files. +`, + Example: `# Scaffold a project using the apache2 license with "The Kubernetes authors" as owners +controller-scaffold project --domain k8s.io --license apache2 --owner "The Kubernetes authors" +`, + Run: func(cmd *cobra.Command, args []string) { + // project and boilerplate must come before main so the boilerplate exists + s := &scaffold.Scaffold{ + BoilerplateOptional: true, + ProjectOptional: true, + } + + p, _ := prj.GetInput() + b, _ := bp.GetInput() + err := s.Execute(input.Options{ProjectPath: p.Path, BoilerplatePath: b.Path}, prj, bp) + if err != nil { + log.Fatal(err) + } + + s = &scaffold.Scaffold{} + err = s.Execute(input.Options{ProjectPath: p.Path, BoilerplatePath: b.Path}, + gopkg, mrg, &project.Makefile{}, dkr, &manager.APIs{}, &manager.Controller{}, &manager.Config{}, + &project.GitIgnore{}) + if err != nil { + log.Fatal(err) + } + + if !depFlag.Changed { + fmt.Println("Run `dep ensure` to fetch dependencies (Recommended) [y/n]?") + dep = yesno() + } + if dep { + c := exec.Command("dep", "ensure") // #nosec + c.Stderr = os.Stderr + c.Stdout = os.Stdout + fmt.Println(strings.Join(c.Args, " ")) + if err := c.Run(); err != nil { + log.Fatal(err) + } + + fmt.Println("Running make...") + c = exec.Command("make") // #nosec + c.Stderr = os.Stderr + c.Stdout = os.Stdout + fmt.Println(strings.Join(c.Args, " ")) + if err := c.Run(); err != nil { + log.Fatal(err) + } + } else { + fmt.Println("Skipping `dep ensure`. Dependencies will not be fetched.") + } + }, +} + +func init() { + rootCmd.AddCommand(ProjectCmd) + + ProjectCmd.Flags().BoolVar( + &dep, "dep", true, "if specified, determines whether dep will be used.") + depFlag = ProjectCmd.Flag("dep") + + prj = ProjectForFlags(ProjectCmd.Flags()) + bp = BoilerplateForFlags(ProjectCmd.Flags()) + gopkg = &project.GopkgToml{} + mrg = &manager.Cmd{} + dkr = &manager.Dockerfile{} +} + +// ProjectForFlags registers flags for Project fields and returns the Project +func ProjectForFlags(f *flag.FlagSet) *project.Project { + p := &project.Project{} + f.StringVar(&p.Domain, "domain", "k8s.io", "domain for groups") + f.StringVar(&p.Version, "project-version", "2", "project version") + f.StringVar(&p.Repo, "repo", "", "name of the github repo. "+ + "defaults to the go package of the current working directory.") + return p +} + +// BoilerplateForFlags registers flags for Boilerplate fields and returns the Boilerplate +func BoilerplateForFlags(f *flag.FlagSet) *project.Boilerplate { + b := &project.Boilerplate{} + f.StringVar(&b.Path, "path", "", "domain for groups") + f.StringVar(&b.License, "license", "apache2", + "license to use to boilerplate. Maybe one of apache2,none") + f.StringVar(&b.Owner, "owner", "", + "Owner to add to the copyright") + return b +} diff --git a/cmd/vendor/sigs.k8s.io/controller-tools/cmd/controller-scaffold/cmd/root.go b/cmd/vendor/sigs.k8s.io/controller-tools/cmd/controller-scaffold/cmd/root.go new file mode 100644 index 0000000000..f030534b96 --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/controller-tools/cmd/controller-scaffold/cmd/root.go @@ -0,0 +1,87 @@ +// Copyright © 2018 NAME HERE +// +// 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 cmd + +import ( + "fmt" + "os" + + homedir "github.com/mitchellh/go-homedir" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +var cfgFile string + +// rootCmd represents the base command when called without any subcommands +var rootCmd = &cobra.Command{ + Use: "controller-scaffold", + Short: "A reference implementation scaffolding tool for Kubernetes APIs.", + Long: `A reference implementation scaffolding tool for Kubernetes APIs.`, + Example: ` # Scaffold a new project + controller-scaffold project --domain k8s.io --license apache2 --owner "The Kubernetes authors" + + # Create a frigates resource with Group: ship, Version: v1beta1 and Kind: Frigate + controller-scaffold api --group ship --version v1beta1 --kind Frigate + + # Generate project code and build + make + + # Install CRDs into the Kubernetes cluster + kubectl apply -f config/crds + + # Run against the Kubernetes cluster + ./bin/manager +`, +} + +// Execute adds all child commands to the root command and sets flags appropriately. +// This is called by main.main(). It only needs to happen once to the rootCmd. +func Execute() { + if err := rootCmd.Execute(); err != nil { + fmt.Println(err) + os.Exit(1) + } +} + +func init() { + cobra.OnInitialize(initConfig) +} + +// initConfig reads in config file and ENV variables if set. +func initConfig() { + if cfgFile != "" { + // Use config file from the flag. + viper.SetConfigFile(cfgFile) + } else { + // Find home directory. + home, err := homedir.Dir() + if err != nil { + fmt.Println(err) + os.Exit(1) + } + + // Search config in home directory with name ".controller-tools" (without extension). + viper.AddConfigPath(home) + viper.SetConfigName(".controller-tools") + } + + viper.AutomaticEnv() // read in environment variables that match + + // If a config file is found, read it in. + if err := viper.ReadInConfig(); err == nil { + fmt.Println("Using config file:", viper.ConfigFileUsed()) + } +} diff --git a/cmd/vendor/sigs.k8s.io/controller-tools/cmd/controller-scaffold/cmd/stdin.go b/cmd/vendor/sigs.k8s.io/controller-tools/cmd/controller-scaffold/cmd/stdin.go new file mode 100644 index 0000000000..10f3dfd614 --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/controller-tools/cmd/controller-scaffold/cmd/stdin.go @@ -0,0 +1,48 @@ +/* +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 cmd + +import ( + "bufio" + "log" + "os" + "strings" +) + +// yesno reads from stdin looking for one of "y", "yes", "n", "no" and returns +// true for "y" and false for "n" +func yesno() bool { + reader := bufio.NewReader(os.Stdin) + for { + switch readstdin(reader) { + case "y", "yes": + return true + case "n", "no": + return false + } + } +} + +// readstdin reads a line from stdin trimming spaces, and returns the value. +// log.Fatal's if there is an error. +func readstdin(reader *bufio.Reader) string { + text, err := reader.ReadString('\n') + if err != nil { + log.Fatal(err) + } + return strings.TrimSpace(text) +} diff --git a/cmd/vendor/sigs.k8s.io/controller-tools/cmd/controller-scaffold/doc.go b/cmd/vendor/sigs.k8s.io/controller-tools/cmd/controller-scaffold/doc.go new file mode 100644 index 0000000000..dcb2fbd4cf --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/controller-tools/cmd/controller-scaffold/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 main is a reference implementation for writing sdk tools for scaffolding and generating code. +*/ +package main diff --git a/cmd/vendor/sigs.k8s.io/controller-tools/cmd/controller-scaffold/main.go b/cmd/vendor/sigs.k8s.io/controller-tools/cmd/controller-scaffold/main.go new file mode 100644 index 0000000000..1efa68a7e9 --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/controller-tools/cmd/controller-scaffold/main.go @@ -0,0 +1,21 @@ +// Copyright © 2018 NAME HERE +// +// 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 main + +import "sigs.k8s.io/controller-tools/cmd/controller-scaffold/cmd" + +func main() { + cmd.Execute() +} diff --git a/cmd/vendor/sigs.k8s.io/controller-tools/examples/godocbot/cmd/manager/main.go b/cmd/vendor/sigs.k8s.io/controller-tools/examples/godocbot/cmd/manager/main.go new file mode 100644 index 0000000000..2ce8ce0d76 --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/controller-tools/examples/godocbot/cmd/manager/main.go @@ -0,0 +1,71 @@ +/* +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 main + +import ( + "flag" + "log" + + _ "k8s.io/client-go/plugin/pkg/client/auth/gcp" + "sigs.k8s.io/controller-runtime/pkg/client/config" + "sigs.k8s.io/controller-runtime/pkg/manager" + logf "sigs.k8s.io/controller-runtime/pkg/runtime/log" + "sigs.k8s.io/controller-runtime/pkg/runtime/signals" + "sigs.k8s.io/controller-tools/examples/godocbot/pkg/apis" + "sigs.k8s.io/controller-tools/examples/godocbot/pkg/controller/pullrequest" +) + +var enablePRSync = flag.Bool("enable-pr-sync", false, "if set to true, periodically syncs pullrequest with Github") + +func main() { + flag.Parse() + logf.SetLogger(logf.ZapLogger(false)) + + // Get a config to talk to the apiserver + cfg, err := config.GetConfig() + if err != nil { + log.Fatal(err) + } + + // Create a new Cmd to provide shared dependencies and start components + mgr, err := manager.New(cfg, manager.Options{}) + if err != nil { + log.Fatal(err) + } + + log.Printf("Registering Components.") + + // Setup all Resources + apis.AddToScheme(mgr.GetScheme()) + + stop := signals.SetupSignalHandler() + + _, err = pullrequest.NewGodocDeployer(mgr) + if err != nil { + log.Fatalf("failed to create godoc deployer: %v", err) + } + + _, err = pullrequest.NewGithubSyncer(mgr, *enablePRSync, stop) + if err != nil { + log.Fatalf("failed to create the github pull request syncer %v", err) + } + + log.Printf("Starting the Cmd.") + + // Start the Cmd + log.Fatal(mgr.Start(stop)) +} diff --git a/cmd/vendor/sigs.k8s.io/controller-tools/examples/godocbot/pkg/apis/add_code_v1alpha1.go b/cmd/vendor/sigs.k8s.io/controller-tools/examples/godocbot/pkg/apis/add_code_v1alpha1.go new file mode 100644 index 0000000000..1f930e50f7 --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/controller-tools/examples/godocbot/pkg/apis/add_code_v1alpha1.go @@ -0,0 +1,26 @@ +/* +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 apis + +import ( + "sigs.k8s.io/controller-tools/examples/godocbot/pkg/apis/code/v1alpha1" +) + +func init() { + // Register the types with the Scheme so the components can map objects to GroupVersionKinds and back + AddToSchemes = append(AddToSchemes, v1alpha1.AddToScheme) +} diff --git a/cmd/vendor/sigs.k8s.io/controller-tools/examples/godocbot/pkg/apis/apis.go b/cmd/vendor/sigs.k8s.io/controller-tools/examples/godocbot/pkg/apis/apis.go new file mode 100644 index 0000000000..8115c3e8f4 --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/controller-tools/examples/godocbot/pkg/apis/apis.go @@ -0,0 +1,35 @@ +/* +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. +*/ + +// Generate deepcopy for apis +//go:generate go run ../../vendor/k8s.io/code-generator/cmd/deepcopy-gen/main.go -i ./... -h ../../hack/boilerplate.go.txt + +// Package apis contains Kubernetes API groups. +package apis + +import ( + "k8s.io/apimachinery/pkg/runtime" +) + +// AddToSchemes should be used to add new API groupversions to the Scheme +var AddToSchemes runtime.SchemeBuilder + +// AddToScheme adds all Resources to the Scheme +func AddToScheme(s *runtime.Scheme) { + for _, f := range AddToSchemes { + f(s) + } +} diff --git a/cmd/vendor/sigs.k8s.io/controller-tools/examples/godocbot/pkg/apis/code/group.go b/cmd/vendor/sigs.k8s.io/controller-tools/examples/godocbot/pkg/apis/code/group.go new file mode 100644 index 0000000000..d76b3dd031 --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/controller-tools/examples/godocbot/pkg/apis/code/group.go @@ -0,0 +1,18 @@ +/* +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 code contains code API versions +package code diff --git a/cmd/vendor/sigs.k8s.io/controller-tools/examples/godocbot/pkg/apis/code/v1alpha1/deepcopy_generated.go b/cmd/vendor/sigs.k8s.io/controller-tools/examples/godocbot/pkg/apis/code/v1alpha1/deepcopy_generated.go new file mode 100644 index 0000000000..e6036e60be --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/controller-tools/examples/godocbot/pkg/apis/code/v1alpha1/deepcopy_generated.go @@ -0,0 +1,117 @@ +// +build !ignore_autogenerated + +/* +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. +*/ +// Code generated by main. DO NOT EDIT. + +package v1alpha1 + +import ( + 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 *PullRequest) DeepCopyInto(out *PullRequest) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Spec = in.Spec + out.Status = in.Status + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PullRequest. +func (in *PullRequest) DeepCopy() *PullRequest { + if in == nil { + return nil + } + out := new(PullRequest) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *PullRequest) 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 *PullRequestList) DeepCopyInto(out *PullRequestList) { + *out = *in + out.TypeMeta = in.TypeMeta + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]PullRequest, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PullRequestList. +func (in *PullRequestList) DeepCopy() *PullRequestList { + if in == nil { + return nil + } + out := new(PullRequestList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *PullRequestList) 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 *PullRequestSpec) DeepCopyInto(out *PullRequestSpec) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PullRequestSpec. +func (in *PullRequestSpec) DeepCopy() *PullRequestSpec { + if in == nil { + return nil + } + out := new(PullRequestSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PullRequestStatus) DeepCopyInto(out *PullRequestStatus) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PullRequestStatus. +func (in *PullRequestStatus) DeepCopy() *PullRequestStatus { + if in == nil { + return nil + } + out := new(PullRequestStatus) + in.DeepCopyInto(out) + return out +} diff --git a/cmd/vendor/sigs.k8s.io/controller-tools/examples/godocbot/pkg/apis/code/v1alpha1/doc.go b/cmd/vendor/sigs.k8s.io/controller-tools/examples/godocbot/pkg/apis/code/v1alpha1/doc.go new file mode 100644 index 0000000000..dd5c784564 --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/controller-tools/examples/godocbot/pkg/apis/code/v1alpha1/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. +*/ + +// +k8s:openapi-gen=true +// +k8s:deepcopy-gen=package,register +// +k8s:conversion-gen=sigs.k8s.io/controller-tools/examples/godocbot/pkg/apis/code +// +k8s:defaulter-gen=TypeMeta +// +groupName=code.godocs.io +package v1alpha1 diff --git a/cmd/vendor/sigs.k8s.io/controller-tools/examples/godocbot/pkg/apis/code/v1alpha1/pullrequest_types.go b/cmd/vendor/sigs.k8s.io/controller-tools/examples/godocbot/pkg/apis/code/v1alpha1/pullrequest_types.go new file mode 100644 index 0000000000..1763adfa45 --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/controller-tools/examples/godocbot/pkg/apis/code/v1alpha1/pullrequest_types.go @@ -0,0 +1,67 @@ +/* +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" +) + +// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! +// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. + +// PullRequestSpec defines the desired state of PullRequest +type PullRequestSpec struct { + // URL of the PULL Request + URL string `json:"url"` + + // Latest commit ID on the PR. This is optional. + CommitID string `json:"commit_id, omitempty"` +} + +// PullRequestStatus defines the observed state of PullRequest +type PullRequestStatus struct { + // The URL which is serving the godoc for the PR. + GoDocLink string `json:"godoc_link"` + + // CommitID for which the godoc is being served + CommitID string `json:"commit_id"` +} + +// +genclient +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// PullRequest +// +k8s:openapi-gen=true +type PullRequest struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec PullRequestSpec `json:"spec,omitempty"` + Status PullRequestStatus `json:"status,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +type PullRequestList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []PullRequest `json:"items"` +} + +func init() { + KnownTypes = append(KnownTypes, &PullRequest{}, &PullRequestList{}) +} diff --git a/cmd/vendor/sigs.k8s.io/controller-tools/examples/godocbot/pkg/apis/code/v1alpha1/register.go b/cmd/vendor/sigs.k8s.io/controller-tools/examples/godocbot/pkg/apis/code/v1alpha1/register.go new file mode 100644 index 0000000000..c9935b1201 --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/controller-tools/examples/godocbot/pkg/apis/code/v1alpha1/register.go @@ -0,0 +1,57 @@ +/* +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. +*/ + +// NOTE: Boilerplate only. Ignore this file. + +// +k8s:openapi-gen=true +// +k8s:deepcopy-gen=package,register +// +k8s:conversion-gen=sigs.k8s.io/controller-tools/examples/godocbot/pkg/apis/code +// +k8s:defaulter-gen=TypeMeta +// +groupName=code.godocs.io +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +var KnownTypes = []runtime.Object{} + +// SchemeGroupVersion is group version used to register these objects +var SchemeGroupVersion = schema.GroupVersion{Group: "code.godocs.io", Version: "v1alpha1"} + +// Kind takes an unqualified kind and returns back a Group qualified GroupKind +func Kind(kind string) schema.GroupKind { + return SchemeGroupVersion.WithKind(kind).GroupKind() +} + +// Resource takes an unqualified resource and returns a Group qualified GroupResource +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} + +var ( + SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) + AddToScheme = SchemeBuilder.AddToScheme +) + +// Adds the list of known types to Scheme. +func addKnownTypes(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(SchemeGroupVersion, KnownTypes...) + metav1.AddToGroupVersion(scheme, SchemeGroupVersion) + return nil +} diff --git a/cmd/vendor/sigs.k8s.io/controller-tools/examples/godocbot/pkg/controller/add_pullrequest.go b/cmd/vendor/sigs.k8s.io/controller-tools/examples/godocbot/pkg/controller/add_pullrequest.go new file mode 100644 index 0000000000..04a3d7996d --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/controller-tools/examples/godocbot/pkg/controller/add_pullrequest.go @@ -0,0 +1,27 @@ +/* +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 ( + + "sigs.k8s.io/controller-tools/examples/godocbot/pkg/controller/pullrequest" +) + +func init() { + // Create the Controller and add it to the Manager. + AddToManagerFuncs = append(AddToManagerFuncs, pullrequest.Add) +} diff --git a/cmd/vendor/sigs.k8s.io/controller-tools/examples/godocbot/pkg/controller/controller.go b/cmd/vendor/sigs.k8s.io/controller-tools/examples/godocbot/pkg/controller/controller.go new file mode 100644 index 0000000000..8a5d6f4204 --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/controller-tools/examples/godocbot/pkg/controller/controller.go @@ -0,0 +1,34 @@ +/* +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 ( + "sigs.k8s.io/controller-runtime/pkg/manager" +) + +// Adds registers functions to add Controllers to the Cmd +var AddToManagerFuncs []func(manager.Manager) error + +// Add adds all Controllers to the Cmd +func AddToManager(m manager.Manager) error { + for _, f := range AddToManagerFuncs { + if err := f(m); err != nil { + return err + } + } + return nil +} diff --git a/cmd/vendor/sigs.k8s.io/controller-tools/examples/godocbot/pkg/controller/pullrequest/github_syncer.go b/cmd/vendor/sigs.k8s.io/controller-tools/examples/godocbot/pkg/controller/pullrequest/github_syncer.go new file mode 100644 index 0000000000..7b5e81ebdf --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/controller-tools/examples/godocbot/pkg/controller/pullrequest/github_syncer.go @@ -0,0 +1,236 @@ +package pullrequest + +import ( + "context" + "log" + "time" + + "github.com/google/go-github/github" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "k8s.io/apimachinery/pkg/api/errors" + "sigs.k8s.io/controller-runtime/pkg/client" + "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/reconcile" + "sigs.k8s.io/controller-runtime/pkg/source" + "sigs.k8s.io/controller-tools/examples/godocbot/pkg/apis/code/v1alpha1" +) + +// GithubSyncer implements following functionalities: +// - Watches newly created PRs in K8s and updates their commitID by calling +// Github +// - Periodically updates the PRs in K8s with their commitID in Github. +type GithubSyncer struct { + mgr manager.Manager + ctrl controller.Controller + // TODO(droot): take make GithubClient interface to make it easy to test the + // syncer + ghClient *github.Client + // TODO(droot): parameterize the sync duration + syncInterval time.Duration +} + +func NewGithubSyncer( + mgr manager.Manager, + enablePRSync bool, + stop <-chan struct{}) (*GithubSyncer, error) { + + ghClient := github.NewClient(nil) + + ctrl, err := controller.New( + "github-pullrequest-syncer", + mgr, + controller.Options{ + Reconcile: &pullRequestCommitIDReconciler{ + Client: mgr.GetClient(), + ghClient: ghClient, + }, + }) + if err != nil { + return nil, err + } + syncer := &GithubSyncer{ + mgr: mgr, + ctrl: ctrl, + ghClient: ghClient, + syncInterval: 30 * time.Second, + } + + // Watch PullRequests objects + if err := syncer.ctrl.Watch( + &source.Kind{Type: &v1alpha1.PullRequest{}}, + &handler.Enqueue{}); err != nil { + return nil, err + } + + if enablePRSync { + go syncer.Start(stop) + } + return syncer, nil +} + +// pullRequestCommitIDReconciler reconciles commitID of newly created +// pullrequests in K8s. +type pullRequestCommitIDReconciler struct { + Client client.Client + // TODO(droot): take GithubClient interface to improve testability + ghClient *github.Client +} + +func (r *pullRequestCommitIDReconciler) Reconcile(request reconcile.Request) (reconcile.Result, error) { + ctx := context.Background() + + // Fetch PullRequest object + pr := &v1alpha1.PullRequest{} + err := r.Client.Get(ctx, request.NamespacedName, pr) + if errors.IsNotFound(err) { + log.Printf("Could not find PullRequest %v.\n", request) + return reconcile.Result{}, nil + } + + if err != nil { + log.Printf("Could not fetch PullRequest %v for %+v\n", err, request) + return reconcile.Result{}, err + } + + if pr.Spec.CommitID != "" { + // We already know the commit-id for the PR, so no need to update the commitID + return reconcile.Result{}, nil + } + + // Looks like this is a fresh PR, so lets determine the latest commitID + prinfo, err := parsePullRequestURL(pr.Spec.URL) + if err != nil { + log.Printf("error in parsing the request, ignoring this pr %v err %v", request.NamespacedName, err) + return reconcile.Result{}, nil + } + + log.Printf("fetching commit id for the PR: %v", prinfo) + ghPR, _, err := r.ghClient.PullRequests.Get(context.Background(), prinfo.org, prinfo.repo, int(prinfo.pr)) + if err != nil { + log.Printf("error fetching PR details from github: %v", err) + return reconcile.Result{}, err + } + + pr.Spec.CommitID = ghPR.Head.GetSHA() + err = r.Client.Update(context.Background(), pr) + if err != nil { + log.Printf("error updating PR github: %v", err) + return reconcile.Result{}, err + } + return reconcile.Result{}, nil +} + +// Start periodically syncs PRs in k8s with their commitID in Github. +func (gs *GithubSyncer) Start(stop <-chan struct{}) { + ticker := time.NewTicker(gs.syncInterval) + for { + select { + case <-stop: + /* we got signalled */ + return + case <-ticker.C: + gs.updateAllPullRequestCommits() + } + } +} + +// updateAllPullRequestCommits performs the following: +// - fetches all the PRs registered in K8s +// - Organize them by orgs/repo so that batch calls can be made +// - Fetches details of PRs from Github and updates the commitID of the PRs in +// k8s if required. +// TODO(droot): delete the PRs from K8s if closed in Github. +func (gs *GithubSyncer) updateAllPullRequestCommits() { + + // get pull requests in all namespaces + prList := &v1alpha1.PullRequestList{} + err := gs.mgr.GetClient().List(context.Background(), client.InNamespace(metav1.NamespaceAll), prList) + if err != nil { + log.Printf("error fetching all the PRs from k8s: %v", err) + return + } + + orgs := pullRequestByOrgAndRepo(prList) + for org, repos := range orgs { + for repo, prs := range repos { + + ghPRs, err := githubPRsForRepo(gs.ghClient, org, repo) + if err != nil { + log.Printf("cannot get PRs for org '%s' and repo '%s' from GH: %v", org, repo, err) + continue + } + + for prNum, pr := range prs { + if ghPR, found := ghPRs[prNum]; found && + ghPR.Head.GetSHA() != pr.Spec.CommitID { + // PR has been updated in GitHub + pr.Spec.CommitID = ghPR.Head.GetSHA() + err = gs.mgr.GetClient().Update(context.Background(), pr) + if err != nil { + log.Printf("error updating PR github: %v", err) + continue + } + } + } + // TODO(droot): if a PR is not found in GH, it is closed, so we need to probably + // delete that PR from k8s cluster + } + } +} + +// githubPRsForRepo fetches PRs for a given org and repo and indexes them by +// their pull request number. +func githubPRsForRepo(ghc *github.Client, org, repo string) (map[int64]*github.PullRequest, error) { + m := map[int64]*github.PullRequest{} + + prs, _, err := ghc.PullRequests.List(context.Background(), org, repo, nil) + if err != nil { + return nil, err + } + + for _, pr := range prs { + m[int64(pr.GetNumber())] = pr + } + return m, nil +} + +// this function organizes all the PRs present in K8s by repo names and orgs, so that +// we can make batch calls to Github. It returns map organized as follows: +// { +// "org-1": { +// "repo-1": { +// pull-request-number-1: "commit-id-1", +// pull-request-number-2: "commit-id-2", +// ...other pull request to follow... +// }, +// "repo-2": { +// pull-request-number-1: "commit-id-1", +// pull-request-number-2: "commit-id-2", +// ...other pull request to follow... +// } +// ....other repos to follow.... +// } +// ....other orgs to follow.... +// } +// TODO(droot): explore if indexing available under pkg/cache can help us achive +// this organization. +func pullRequestByOrgAndRepo(prs *v1alpha1.PullRequestList) map[string]map[string]map[int64]*v1alpha1.PullRequest { + orgs := map[string]map[string]map[int64]*v1alpha1.PullRequest{} + for _, pr := range prs.Items { + prinfo, _ := parsePullRequestURL(pr.Spec.URL) + _, orgFound := orgs[prinfo.org] + if !orgFound { + orgs[prinfo.org] = map[string]map[int64]*v1alpha1.PullRequest{} + } + _, repoFound := orgs[prinfo.org][prinfo.repo] + if !repoFound { + orgs[prinfo.org][prinfo.repo] = map[int64]*v1alpha1.PullRequest{} + } + orgs[prinfo.org][prinfo.repo][prinfo.pr] = &pr + } + return orgs +} diff --git a/cmd/vendor/sigs.k8s.io/controller-tools/examples/godocbot/pkg/controller/pullrequest/godoc_deployer.go b/cmd/vendor/sigs.k8s.io/controller-tools/examples/godocbot/pkg/controller/pullrequest/godoc_deployer.go new file mode 100644 index 0000000000..f55fb2e694 --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/controller-tools/examples/godocbot/pkg/controller/pullrequest/godoc_deployer.go @@ -0,0 +1,260 @@ +/* +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 pullrequest + +import ( + "context" + "fmt" + "log" + "net/url" + "strconv" + "strings" + + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + "sigs.k8s.io/controller-runtime/pkg/handler" + "sigs.k8s.io/controller-runtime/pkg/manager" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + "sigs.k8s.io/controller-runtime/pkg/source" + "sigs.k8s.io/controller-tools/examples/godocbot/pkg/apis/code/v1alpha1" +) + +// GodocDeployer watches PullRequest object which have a commitID specified in +// their Spec and deploys a Godoc deployment which runs godoc server for the PR. +// It watches the PullRequest object for changes in commitID and reconciles the +// generated godoc deployment. CommitID for PRs is updated by GithubSyncer +// module. +type GodocDeployer struct { + controller.Controller +} + +func NewGodocDeployer(mgr manager.Manager) (*GodocDeployer, error) { + prReconciler := &pullRequestReconciler{ + Client: mgr.GetClient(), + scheme: mgr.GetScheme(), + } + + // Setup a new controller to Reconcile PullRequests + c, err := controller.New("pull-request-controller", mgr, controller.Options{Reconcile: prReconciler}) + if err != nil { + return nil, err + } + + // Watch PullRequest objects + err = c.Watch( + &source.Kind{Type: &v1alpha1.PullRequest{}}, + &handler.Enqueue{}) + if err != nil { + return nil, err + } + + // Watch deployments generated for PullRequests objects + err = c.Watch( + &source.Kind{Type: &appsv1.Deployment{}}, + &handler.EnqueueOwner{ + OwnerType: &v1alpha1.PullRequest{}, + IsController: true, + }, + ) + if err != nil { + return nil, err + } + + return &GodocDeployer{Controller: c}, nil +} + +// pullRequestReconciler ensures there is a godoc deployment is running with +// the commitID specified in the PullRequest object. +type pullRequestReconciler struct { + Client client.Client + scheme *runtime.Scheme +} + +func (r *pullRequestReconciler) Reconcile(request reconcile.Request) (reconcile.Result, error) { + ctx := context.Background() + + // Fetch PullRequest object + pr := &v1alpha1.PullRequest{} + err := r.Client.Get(ctx, request.NamespacedName, pr) + if errors.IsNotFound(err) { + log.Printf("Could not find PullRequest %v.\n", request) + return reconcile.Result{}, nil + } + + if err != nil { + log.Printf("Could not fetch PullRequest %v for %+v\n", err, request) + return reconcile.Result{}, err + } + + if pr.Spec.CommitID == "" { + log.Printf("Waiting for PR %s commitID to be updated", request.NamespacedName) + return reconcile.Result{}, nil + } + + dp := &appsv1.Deployment{} + err = r.Client.Get(ctx, request.NamespacedName, dp) + if err != nil { + if !errors.IsNotFound(err) { + return reconcile.Result{}, err + } + + log.Printf("Could not find deployment for PullRequest %v. creating deployment", request) + dp, err = deploymentForPullRequest(pr, r.scheme) + if err != nil { + log.Printf("error creating new deployment for PullRequest: %v %v", request, err) + return reconcile.Result{}, nil + } + if err = r.Client.Create(ctx, dp); err != nil { + log.Printf("error creating new deployment for PullRequest: %v %v", request, err) + return reconcile.Result{}, err + } + } + + prinfo, _ := parsePullRequestURL(pr.Spec.URL) + prinfo.commitID = pr.Spec.CommitID + + if len(dp.Spec.Template.Spec.Containers[0].Args) > 5 && (pr.Spec.CommitID != dp.Spec.Template.Spec.Containers[0].Args[5]) { + // TODO(droot): publish an event when commit is updated. + // deployment is not updated with latest commit-id + dp.Spec.Template.Spec.Containers[0].Args = prinfo.godocContainerArgs() + if err = r.Client.Update(ctx, dp); err != nil { + log.Printf("error updating the deployment for key %s", request.NamespacedName) + return reconcile.Result{}, err + } + } + + if pr.Status.GoDocLink == "" && dp.Status.AvailableReplicas > 0 { + log.Printf("deployment became available, updating the godoc link") + // update the status + pr.Status.GoDocLink = fmt.Sprintf("https://%s.serveo.net/pkg/%s/%s/%s", prinfo.subdomain(), prinfo.host, prinfo.org, prinfo.repo) + if err = r.Client.Update(ctx, pr); err != nil { + return reconcile.Result{}, err + } + log.Printf("godoc link updated successfully for pr %v", request.NamespacedName) + } + return reconcile.Result{}, nil +} + +// deploymentForPullRequest creates a deployment object for a given PullRequest. +func deploymentForPullRequest(pr *v1alpha1.PullRequest, scheme *runtime.Scheme) (*appsv1.Deployment, error) { + // we are good with running with one replica + var replicas int32 = 1 + + prinfo, err := parsePullRequestURL(pr.Spec.URL) + if err != nil { + return nil, err + } + prinfo.commitID = pr.Spec.CommitID + + labels := map[string]string{ + "org": prinfo.org, + "repo": prinfo.repo, + } + + tunnelArgs := "80:localhost:6060" + tunnelArgs = fmt.Sprintf("%s:%s", prinfo.subdomain(), tunnelArgs) + + dep := &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: pr.Name, + Namespace: pr.Namespace, + }, + Spec: appsv1.DeploymentSpec{ + Replicas: &replicas, + Selector: &metav1.LabelSelector{ + MatchLabels: labels, + }, + Template: corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Labels: labels, + }, + Spec: corev1.PodSpec{ + Containers: []corev1.Container{ + { + Image: "gcr.io/sunilarora-sandbox/godoc:0.0.1", + Name: "godoc", + ImagePullPolicy: "Always", + Command: []string{"/bin/bash"}, + Args: prinfo.godocContainerArgs(), + }, + { + Image: "gcr.io/sunilarora-sandbox/ssh-client:0.0.2", + Name: "ssh", + ImagePullPolicy: "Always", + Command: []string{"ssh"}, + Args: []string{"-tt", "-o", "StrictHostKeyChecking=no", "-R", tunnelArgs, "serveo.net"}, + }, + }, + }, + }, + }, + } + + controllerutil.SetControllerReference(pr, dep, scheme) + return dep, nil +} + +// prInfo is an structure to represent PullRequest info. It will be used +// internally to more as an convenience for passing it around. +type prInfo struct { + host string + org string + repo string + pr int64 + commitID string +} + +// parsePullRequestURL parses given PullRequest URL into prInfo instance. +// An example pull request URL looks like: +// https://github.com/kubernetes-sigs/controller-runtime/pull/15 +func parsePullRequestURL(prURL string) (*prInfo, error) { + u, err := url.Parse(prURL) + if err != nil { + return nil, err + } + parts := strings.Split(strings.TrimPrefix(u.Path, "/"), "/") + if len(parts) < 4 || parts[2] != "pull" { + return nil, fmt.Errorf("pr info missing in the URL") + } + + prNum, err := strconv.ParseInt(parts[3], 10, 64) + if err != nil { + return nil, err + } + + return &prInfo{ + host: u.Hostname(), + org: parts[0], + repo: parts[1], + pr: prNum, + }, nil +} + +// helper function to generate subdomain for the prinfo. +func (pr *prInfo) subdomain() string { + return fmt.Sprintf("%s-%s-pr-%d", pr.org, pr.repo, pr.pr) +} + +func (pr *prInfo) godocContainerArgs() []string { + return []string{"fetch_serve.sh", pr.host, pr.org, pr.repo, strconv.FormatInt(pr.pr, 10), pr.commitID} +} diff --git a/cmd/vendor/sigs.k8s.io/controller-tools/pkg/generate/doc.go b/cmd/vendor/sigs.k8s.io/controller-tools/pkg/generate/doc.go new file mode 100644 index 0000000000..94960f0310 --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/controller-tools/pkg/generate/doc.go @@ -0,0 +1,18 @@ +/* +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 generate contains libraries for generating code to use with controller-runtime +package generate diff --git a/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/controller/add.go b/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/controller/add.go new file mode 100644 index 0000000000..cdfac7f678 --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/controller/add.go @@ -0,0 +1,60 @@ +/* +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 ( + "fmt" + "path/filepath" + "strings" + + "sigs.k8s.io/controller-tools/pkg/scaffold/input" + "sigs.k8s.io/controller-tools/pkg/scaffold/resource" +) + +var _ input.File = &AddController{} + +// AddController scaffolds adds a new Controller. +type AddController struct { + input.Input + + // Resource is a resource in the API group + Resource *resource.Resource +} + +// GetInput implements input.File +func (a *AddController) GetInput() (input.Input, error) { + if a.Path == "" { + a.Path = filepath.Join("pkg", "controller", fmt.Sprintf( + "add_%s.go", strings.ToLower(a.Resource.Kind))) + } + a.TemplateBody = addControllerTemplate + return a.Input, nil +} + +var addControllerTemplate = `{{ .Boilerplate }} + +package controller + +import ( + "{{ .Repo }}/pkg/controller/{{ lower .Resource.Kind }}" +) + +func init() { + // AddToManagerFuncs is a list of functions to create controllers and add them to a manager. + AddToManagerFuncs = append(AddToManagerFuncs, {{ lower .Resource.Kind }}.Add) +} +` diff --git a/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/controller/controller.go b/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/controller/controller.go new file mode 100644 index 0000000000..bb9024a1bf --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/controller/controller.go @@ -0,0 +1,250 @@ +/* +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 ( + "path" + "path/filepath" + "strings" + + "sigs.k8s.io/controller-tools/pkg/scaffold/input" + "sigs.k8s.io/controller-tools/pkg/scaffold/resource" +) + +// Controller scaffolds a Controller for a Resource +type Controller struct { + input.Input + + // Resource is the Resource to make the Controller for + Resource *resource.Resource + + // ResourcePackage is the package of the Resource + ResourcePackage string + + // Is the Group + "." + Domain for the Resource + GroupDomain string +} + +// GetInput implements input.File +func (a *Controller) GetInput() (input.Input, error) { + // Use the k8s.io/api package for core resources + coreGroups := map[string]string{ + "apps": "", + "admissionregistration": "k8s.io", + "apiextensions": "k8s.io", + "authentication": "k8s.io", + "autoscaling": "", + "batch": "", + "certificates": "k8s.io", + "core": "", + "extensions": "", + "metrics": "k8s.io", + "policy": "", + "rbac.authorization": "k8s.io", + "storage": "k8s.io", + } + if domain, found := coreGroups[a.Resource.Group]; found { + a.ResourcePackage = path.Join("k8s.io", "api") + a.GroupDomain = a.Resource.Group + if domain != "" { + a.GroupDomain = a.Resource.Group + "." + domain + } + } else { + a.ResourcePackage = path.Join(a.Repo, "pkg", "apis") + a.GroupDomain = a.Resource.Group + "." + a.Domain + } + + if a.Path == "" { + a.Path = filepath.Join("pkg", "controller", + strings.ToLower(a.Resource.Kind), + strings.ToLower(a.Resource.Kind)+"_controller.go") + } + a.TemplateBody = controllerTemplate + a.Input.IfExistsAction = input.Error + return a.Input, nil +} + +var controllerTemplate = `{{ .Boilerplate }} + +package {{ lower .Resource.Kind }} + +import ( +{{ if .Resource.CreateExampleReconcileBody }} "context" + "log" + "reflect" + + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + "sigs.k8s.io/controller-runtime/pkg/handler" + "sigs.k8s.io/controller-runtime/pkg/manager" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + "sigs.k8s.io/controller-runtime/pkg/source" + {{ .Resource.Group}}{{ .Resource.Version }} "{{ .ResourcePackage }}/{{ .Resource.Group}}/{{ .Resource.Version }}" +{{ else }} "context" + + appsv1 "k8s.io/api/apps/v1" + "k8s.io/apimachinery/pkg/api/errors" + "sigs.k8s.io/controller-runtime/pkg/client" + "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/reconcile" + "sigs.k8s.io/controller-runtime/pkg/source" + {{ .Resource.Group}}{{ .Resource.Version }} "{{ .ResourcePackage }}/{{ .Resource.Group}}/{{ .Resource.Version }}" +{{ end -}} +) + +/** +* USER ACTION REQUIRED: This is a scaffold file intended for the user to modify with their own Controller +* business logic. Delete these comments after modifying this file.* + */ + +// Add creates a new {{ .Resource.Kind }} Controller and adds it to the Manager. The Manager will set fields on the Controller +// and Start it when the Manager is Started. +// USER ACTION REQUIRED: update cmd/manager/main.go to call this {{ .Resource.Group}}.Add(mgr) to install this Controller +func Add(mgr manager.Manager) error { + return add(mgr, newReconciler(mgr)) +} + +// newReconciler returns a new reconcile.Reconciler +func newReconciler(mgr manager.Manager) reconcile.Reconciler { + return &Reconcile{{ .Resource.Kind }}{Client: mgr.GetClient(), scheme: mgr.GetScheme()} +} + +// add adds a new Controller to mgr with r as the reconcile.Reconciler +func add(mgr manager.Manager, r reconcile.Reconciler) error { + // Create a new controller + c, err := controller.New("{{ lower .Resource.Kind }}-controller", mgr, controller.Options{Reconciler: r}) + if err != nil { + return err + } + + // Watch for changes to {{ .Resource.Kind }} + err = c.Watch(&source.Kind{Type: &{{ .Resource.Group}}{{ .Resource.Version }}.{{ .Resource.Kind }}{}}, &handler.EnqueueRequestForObject{}) + if err != nil { + return err + } + + // TODO(user): Modify this to be the types you create + // Uncomment watch a Deployment created by {{ .Resource.Kind }} - change this for objects you create + err = c.Watch(&source.Kind{Type: &appsv1.Deployment{}}, &handler.EnqueueRequestForOwner{ + IsController: true, + OwnerType: &{{ .Resource.Group}}{{ .Resource.Version }}.{{ .Resource.Kind }}{}, + }) + if err != nil { + return err + } + + return nil +} + +var _ reconcile.Reconciler = &Reconcile{{ .Resource.Kind }}{} + +// Reconcile{{ .Resource.Kind }} reconciles a {{ .Resource.Kind }} object +type Reconcile{{ .Resource.Kind }} struct { + client.Client + scheme *runtime.Scheme +} + +// Reconcile reads that state of the cluster for a {{ .Resource.Kind }} object and makes changes based on the state read +// and what is in the {{ .Resource.Kind }}.Spec +// TODO(user): Modify this Reconcile function to implement your Controller logic. The scaffolding writes +// a Deployment as an example +{{ if .Resource.CreateExampleReconcileBody -}} +// Automatically generate RBAC rules to allow the Controller to read and write Deployments +// +rbac:groups=apps,resources=deployments,verbs=get;list;watch;create;update;patch;delete +{{ end -}} +func (r *Reconcile{{ .Resource.Kind }}) Reconcile(request reconcile.Request) (reconcile.Result, error) { + // Fetch the {{ .Resource.Kind }} instance + instance := &{{ .Resource.Group}}{{ .Resource.Version }}.{{ .Resource.Kind }}{} + err := r.Get(context.TODO(), request.NamespacedName, instance) + if err != nil { + if errors.IsNotFound(err) { + // Object not found, return. Created objects are automatically garbage collected. + // For additional cleanup logic use finalizers. + return reconcile.Result{}, nil + } + // Error reading the object - requeue the request. + return reconcile.Result{}, err + } + + {{ if .Resource.CreateExampleReconcileBody -}} + // TODO(user): Change this to be the object type created by your controller + // Define the desired Deployment object + deploy := &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: instance.Name + "-deployment", + Namespace: {{ if .Resource.Namespaced}}instance.Namespace{{ else }}"default"{{ end }}, + }, + Spec: appsv1.DeploymentSpec{ + Selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{"deployment": instance.Name + "-deployment"}, + }, + Template: corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"deployment": instance.Name + "-deployment"}}, + Spec: corev1.PodSpec{ + Containers: []corev1.Container{ + { + Name: "nginx", + Image: "nginx", + }, + }, + }, + }, + }, + } + if err := controllerutil.SetControllerReference(instance, deploy, r.scheme); err != nil { + return reconcile.Result{}, err + } + + // TODO(user): Change this for the object type created by your controller + // Check if the Deployment already exists + found := &appsv1.Deployment{} + err = r.Get(context.TODO(), types.NamespacedName{Name: deploy.Name, Namespace: deploy.Namespace}, found) + if err != nil && errors.IsNotFound(err) { + log.Printf("Creating Deployment %s/%s\n", deploy.Namespace, deploy.Name) + err = r.Create(context.TODO(), deploy) + if err != nil { + return reconcile.Result{}, err + } + } else if err != nil { + return reconcile.Result{}, err + } + + // TODO(user): Change this for the object type created by your controller + // Update the found object and write the result back if there are any changes + if !reflect.DeepEqual(deploy.Spec, found.Spec) { + found.Spec = deploy.Spec + log.Printf("Updating Deployment %s/%s\n", deploy.Namespace, deploy.Name) + err = r.Update(context.TODO(), found) + if err != nil { + return reconcile.Result{}, err + } + } + {{ end -}} + + return reconcile.Result{}, nil +} +` diff --git a/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/controller/controllersuitetest.go b/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/controller/controllersuitetest.go new file mode 100644 index 0000000000..4aa9a9b6ed --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/controller/controllersuitetest.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 controller + +import ( + "path/filepath" + "strings" + + "sigs.k8s.io/controller-tools/pkg/scaffold/input" + "sigs.k8s.io/controller-tools/pkg/scaffold/resource" +) + +// SuiteTest scaffolds a SuiteTest +type SuiteTest struct { + input.Input + + // Resource is the Resource to make the Controller for + Resource *resource.Resource +} + +// GetInput implements input.File +func (a *SuiteTest) GetInput() (input.Input, error) { + if a.Path == "" { + a.Path = filepath.Join("pkg", "controller", + strings.ToLower(a.Resource.Kind), strings.ToLower(a.Resource.Kind)+"_controller_suite_test.go") + } + a.TemplateBody = controllerSuiteTestTemplate + return a.Input, nil +} + +var controllerSuiteTestTemplate = `{{ .Boilerplate }} + +package {{ lower .Resource.Kind }} + +import ( + "log" + "os" + "path/filepath" + "testing" + + "github.com/onsi/gomega" + "k8s.io/client-go/kubernetes/scheme" + "k8s.io/client-go/rest" + "sigs.k8s.io/controller-runtime/pkg/envtest" + "sigs.k8s.io/controller-runtime/pkg/manager" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + "{{ .Repo }}/pkg/apis" +) + +var cfg *rest.Config + +func TestMain(m *testing.M) { + t := &envtest.Environment{ + CRDDirectoryPaths: []string{filepath.Join("..", "..", "..", "config", "crds")}, + } + apis.AddToScheme(scheme.Scheme) + + var err error + if cfg, err = t.Start(); err != nil { + log.Fatal(err) + } + + code := m.Run() + t.Stop() + os.Exit(code) +} + +// SetupTestReconcile returns a reconcile.Reconcile implementation that delegates to inner and +// writes the request to requests after Reconcile is finished. +func SetupTestReconcile(inner reconcile.Reconciler) (reconcile.Reconciler, chan reconcile.Request) { + requests := make(chan reconcile.Request) + fn := reconcile.Func(func(req reconcile.Request) (reconcile.Result, error) { + result, err := inner.Reconcile(req) + requests <- req + return result, err + }) + return fn, requests +} + +// StartTestManager adds recFn +func StartTestManager(mgr manager.Manager, g *gomega.GomegaWithT) chan struct{} { + stop := make(chan struct{}) + go func() { + g.Expect(mgr.Start(stop)).NotTo(gomega.HaveOccurred()) + }() + return stop +} +` diff --git a/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/controller/controllertest.go b/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/controller/controllertest.go new file mode 100644 index 0000000000..04465f1798 --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/controller/controllertest.go @@ -0,0 +1,134 @@ +/* +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 ( + "path" + "path/filepath" + "strings" + + "sigs.k8s.io/controller-tools/pkg/scaffold/input" + "sigs.k8s.io/controller-tools/pkg/scaffold/resource" +) + +// Test scaffolds a Controller Test +type Test struct { + input.Input + + // Resource is the Resource to make the Controller for + Resource *resource.Resource + + // ResourcePackage is the package of the Resource + ResourcePackage string +} + +// GetInput implements input.File +func (a *Test) GetInput() (input.Input, error) { + if a.Path == "" { + a.Path = filepath.Join("pkg", "controller", + strings.ToLower(a.Resource.Kind), strings.ToLower(a.Resource.Kind)+"_controller_test.go") + } + + // Use the k8s.io/api package for core resources + coreGroups := map[string]string{ + "apps": "", + "admissionregistration": "k8s.io", + "apiextensions": "k8s.io", + "authentication": "k8s.io", + "autoscaling": "", + "batch": "", + "certificates": "k8s.io", + "core": "", + "extensions": "", + "metrics": "k8s.io", + "policy": "", + "rbac.authorization": "k8s.io", + "storage": "k8s.io", + } + if _, found := coreGroups[a.Resource.Group]; found { + a.ResourcePackage = path.Join("k8s.io", "api") + } else { + a.ResourcePackage = path.Join(a.Repo, "pkg", "apis") + } + + a.TemplateBody = controllerTestTemplate + a.Input.IfExistsAction = input.Error + return a.Input, nil +} + +var controllerTestTemplate = `{{ .Boilerplate }} + +package {{ lower .Resource.Kind }} + +import ( + "testing" + "time" + + "github.com/onsi/gomega" + "golang.org/x/net/context" + {{ if .Resource.CreateExampleReconcileBody -}} + appsv1 "k8s.io/api/apps/v1" + {{ end -}} + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/manager" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + {{ .Resource.Group}}{{ .Resource.Version }} "{{ .ResourcePackage }}/{{ .Resource.Group}}/{{ .Resource.Version }}" +) + +var c client.Client + +var expectedRequest = reconcile.Request{NamespacedName: types.NamespacedName{Name: "foo"{{ if .Resource.Namespaced }}, Namespace: "default"{{end}}}} +{{ if .Resource.CreateExampleReconcileBody }}var depKey = types.NamespacedName{Name: "foo-deployment"{{ if .Resource.Namespaced }}, Namespace: "default"{{end}}} +{{ end }} +const timeout = time.Second * 5 + +func TestReconcile(t *testing.T) { + g := gomega.NewGomegaWithT(t) + instance := &{{ .Resource.Group }}{{ .Resource.Version }}.{{ .Resource.Kind }}{ObjectMeta: metav1.ObjectMeta{Name: "foo"{{ if .Resource.Namespaced }}, Namespace: "default"{{end}}}} + + // Setup the Manager and Controller. Wrap the Controller Reconcile function so it writes each request to a + // channel when it is finished. + mgr, err := manager.New(cfg, manager.Options{}) + g.Expect(err).NotTo(gomega.HaveOccurred()) + c = mgr.GetClient() + + recFn, requests := SetupTestReconcile(newReconciler(mgr)) + g.Expect(add(mgr, recFn)).NotTo(gomega.HaveOccurred()) + defer close(StartTestManager(mgr, g)) + + // Create the {{ .Resource.Kind }} object and expect the Reconcile{{ if .Resource.CreateExampleReconcileBody }} and Deployment to be created{{ end }} + g.Expect(c.Create(context.TODO(), instance)).To(gomega.Succeed()) + defer c.Delete(context.TODO(), instance) + g.Eventually(requests, timeout).Should(gomega.Receive(gomega.Equal(expectedRequest))) +{{ if .Resource.CreateExampleReconcileBody }} + deploy := &appsv1.Deployment{} + g.Eventually(func() error { return c.Get(context.TODO(), depKey, deploy) }, timeout). + Should(gomega.Succeed()) + + // Delete the Deployment and expect Reconcile to be called for Deployment deletion + g.Expect(c.Delete(context.TODO(), deploy)).NotTo(gomega.HaveOccurred()) + g.Eventually(requests, timeout).Should(gomega.Receive(gomega.Equal(expectedRequest))) + g.Eventually(func() error { return c.Get(context.TODO(), depKey, deploy) }, timeout). + Should(gomega.Succeed()) + + // Manually delete Deployment since GC isn't enabled in the test control plane + g.Expect(c.Delete(context.TODO(), deploy)).To(gomega.Succeed()) +{{ end }} +} +` diff --git a/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/doc.go b/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/doc.go new file mode 100644 index 0000000000..583a19eb4e --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/doc.go @@ -0,0 +1,18 @@ +/* +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 scaffold contains libraries for scaffolding code to use with controller-runtime +package scaffold diff --git a/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/input/input.go b/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/input/input.go new file mode 100644 index 0000000000..3cb2f7e007 --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/input/input.go @@ -0,0 +1,172 @@ +/* +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 input + +// IfExistsAction determines what to do if the scaffold file already exists +type IfExistsAction int + +const ( + // Skip skips the file and moves to the next one + Skip IfExistsAction = iota + + // Error returns an error and stops processing + Error + + // Overwrite truncates and overwrites the existing file + Overwrite +) + +// Input is the input for scaffoldig a file +type Input struct { + // Path is the file to write + Path string + + // IfExistsAction determines what to do if the file exists + IfExistsAction IfExistsAction + + // TemplateBody is the template body to execute + TemplateBody string + + // Boilerplate is the contents of a Boilerplate go header file + Boilerplate string + + // BoilerplatePath is the path to a Boilerplate go header file + BoilerplatePath string + + // Version is the project version + Version string + + // Domain is the domain for the APIs + Domain string + + // Repo is the go project package + Repo string + + // ProjectPath is the relative path to the project root + ProjectPath string +} + +// Domain allows a domain to be set on an object +type Domain interface { + // SetDomain sets the domain + SetDomain(string) +} + +// SetDomain sets the domain +func (i *Input) SetDomain(d string) { + if i.Domain == "" { + i.Domain = d + } +} + +// Repo allows a repo to be set on an object +type Repo interface { + // SetRepo sets the repo + SetRepo(string) +} + +// SetRepo sets the repo +func (i *Input) SetRepo(r string) { + if i.Repo == "" { + i.Repo = r + } +} + +// Boilerplate allows boilerplate text to be set on an object +type Boilerplate interface { + // SetBoilerplate sets the boilerplate text + SetBoilerplate(string) +} + +// SetBoilerplate sets the boilerplate text +func (i *Input) SetBoilerplate(b string) { + if i.Boilerplate == "" { + i.Boilerplate = b + } +} + +// BoilerplatePath allows boilerplate file path to be set on an object +type BoilerplatePath interface { + // SetBoilerplatePath sets the boilerplate file path + SetBoilerplatePath(string) +} + +// SetBoilerplatePath sets the boilerplate file path +func (i *Input) SetBoilerplatePath(bp string) { + if i.BoilerplatePath == "" { + i.BoilerplatePath = bp + } +} + +// Version allows the project version to be set on an object +type Version interface { + // SetVersion sets the project version + SetVersion(string) +} + +// SetVersion sets the project version +func (i *Input) SetVersion(v string) { + if i.Version == "" { + i.Version = v + } +} + +// ProjecPath allows the project path to be set on an object +type ProjecPath interface { + // SetProjectPath sets the project file location + SetProjectPath(string) +} + +// SetProjectPath sets the project path +func (i *Input) SetProjectPath(p string) { + if i.ProjectPath == "" { + i.ProjectPath = p + } +} + +// File is a scaffoldable file +type File interface { + // GetInput returns the Input for creating a scaffold file + GetInput() (Input, error) +} + +// Validate validates input +type Validate interface { + // Validate returns true if the template has valid values + Validate() error +} + +// Options are the options for executing scaffold templates +type Options struct { + // BoilerplatePath is the path to the boilerplate file + BoilerplatePath string + + // Path is the path to the project + ProjectPath string +} + +// ProjectFile is deserialized into a PROJECT file +type ProjectFile struct { + // Version is the project version - defaults to "2" + Version string `yaml:"version,omitempty"` + + // Domain is the domain associated with the project and used for API groups + Domain string `yaml:"domain,omitempty"` + + // Repo is the go package name of the project root + Repo string `yaml:"repo,omitempty"` +} diff --git a/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/manager/apis.go b/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/manager/apis.go new file mode 100644 index 0000000000..2938f89404 --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/manager/apis.go @@ -0,0 +1,79 @@ +/* +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 ( + "fmt" + "path/filepath" + "strings" + + "sigs.k8s.io/controller-tools/pkg/scaffold/input" +) + +var _ input.File = &APIs{} + +// APIs scaffolds a apis.go to register types with a Scheme +type APIs struct { + input.Input + + // Comments is a list of comments to add to the apis.go + Comments []string +} + +var deepCopy = strings.Join([]string{ + "//go:generate go run", + "../../vendor/k8s.io/code-generator/cmd/deepcopy-gen/main.go", + "-O zz_generated.deepcopy", + "-i ./..."}, " ") + +// GetInput implements input.File +func (a *APIs) GetInput() (input.Input, error) { + if a.Path == "" { + a.Path = filepath.Join("pkg", "apis", "apis.go") + } + + b, err := filepath.Rel(filepath.Join(a.Input.ProjectPath, "pkg", "apis"), a.BoilerplatePath) + if err != nil { + return input.Input{}, err + } + if len(a.Comments) == 0 { + a.Comments = append(a.Comments, + "// Generate deepcopy for apis", fmt.Sprintf("%s -h %s", deepCopy, b)) + } + a.TemplateBody = apisTemplate + return a.Input, nil +} + +var apisTemplate = `{{ .Boilerplate }} + +{{ range $line := .Comments }}{{ $line }} +{{ end }} +// Package apis contains Kubernetes API groups. +package apis + +import ( + "k8s.io/apimachinery/pkg/runtime" +) + +// AddToSchemes may be used to add all resources defined in the project to a Scheme +var AddToSchemes runtime.SchemeBuilder + +// AddToScheme adds all Resources to the Scheme +func AddToScheme(s *runtime.Scheme) error { + return AddToSchemes.AddToScheme(s) +} +` diff --git a/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/manager/cmd.go b/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/manager/cmd.go new file mode 100644 index 0000000000..9c5998c010 --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/manager/cmd.go @@ -0,0 +1,86 @@ +/* +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 ( + "path/filepath" + + "sigs.k8s.io/controller-tools/pkg/scaffold/input" +) + +var _ input.File = &Cmd{} + +// Cmd scaffolds a manager.go to run Controllers +type Cmd struct { + input.Input +} + +// GetInput implements input.File +func (a *Cmd) GetInput() (input.Input, error) { + if a.Path == "" { + a.Path = filepath.Join("cmd", "manager", "main.go") + } + a.TemplateBody = cmdTemplate + return a.Input, nil +} + +var cmdTemplate = `{{ .Boilerplate }} + +package main + +import ( + "log" + + _ "k8s.io/client-go/plugin/pkg/client/auth/gcp" + "sigs.k8s.io/controller-runtime/pkg/client/config" + "sigs.k8s.io/controller-runtime/pkg/manager" + "sigs.k8s.io/controller-runtime/pkg/runtime/signals" + "{{ .Repo }}/pkg/apis" + "{{ .Repo }}/pkg/controller" +) + +func main() { + // Get a config to talk to the apiserver + cfg, err := config.GetConfig() + if err != nil { + log.Fatal(err) + } + + // Create a new Cmd to provide shared dependencies and start components + mgr, err := manager.New(cfg, manager.Options{}) + if err != nil { + log.Fatal(err) + } + + log.Printf("Registering Components.") + + // Setup Scheme for all resources + if err := apis.AddToScheme(mgr.GetScheme()); err != nil { + log.Fatal(err) + } + + // Setup all Controllers + if err := controller.AddToManager(mgr); err != nil { + log.Fatal(err) + } + + log.Printf("Starting the Cmd.") + + // Start the Cmd + log.Fatal(mgr.Start(signals.SetupSignalHandler())) +} +` diff --git a/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/manager/config.go b/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/manager/config.go new file mode 100644 index 0000000000..eaee68b779 --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/manager/config.go @@ -0,0 +1,105 @@ +/* +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 ( + "path/filepath" + + "sigs.k8s.io/controller-tools/pkg/scaffold/input" +) + +var _ input.File = &Config{} + +// Config scaffolds yaml config for the manager. +type Config struct { + input.Input +} + +// GetInput implements input.File +func (c *Config) GetInput() (input.Input, error) { + if c.Path == "" { + c.Path = filepath.Join("config", "manager", "manager.yaml") + } + c.TemplateBody = configTemplate + return c.Input, nil +} + +var configTemplate = `apiVersion: v1 +kind: Namespace +metadata: + labels: + controller-tools.k8s.io: "1.0" + name: system +--- +apiVersion: v1 +kind: Service +metadata: + name: controller-manager-service + labels: + control-plane: controller-manager + controller-tools.k8s.io: "1.0" +spec: + selector: + control-plane: controller-manager + controller-tools.k8s.io: "1.0" +--- +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: controller-manager + labels: + control-plane: controller-manager + controller-tools.k8s.io: "1.0" +spec: + selector: + matchLabels: + control-plane: controller-manager + controller-tools.k8s.io: "1.0" + serviceName: controller-manager-service + template: + metadata: + labels: + control-plane: controller-manager + controller-tools.k8s.io: "1.0" + spec: + containers: + command: + - /root/manager + name: manager + resources: + limits: + cpu: 100m + memory: 30Mi + requests: + cpu: 100m + memory: 20Mi + terminationGracePeriodSeconds: 10 +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + labels: + controller-tools.k8s.io: "1.0" + name: rolebinding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: role +subjects: +- kind: ServiceAccount + name: default +` diff --git a/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/manager/controller.go b/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/manager/controller.go new file mode 100644 index 0000000000..47da204be7 --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/manager/controller.go @@ -0,0 +1,61 @@ +/* +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 ( + "path/filepath" + + "sigs.k8s.io/controller-tools/pkg/scaffold/input" +) + +var _ input.File = &Controller{} + +// Controller scaffolds a controller.go to add Controllers to a manager.Cmd +type Controller struct { + input.Input +} + +// GetInput implements input.File +func (c *Controller) GetInput() (input.Input, error) { + if c.Path == "" { + c.Path = filepath.Join("pkg", "controller", "controller.go") + } + c.TemplateBody = controllerTemplate + return c.Input, nil +} + +var controllerTemplate = `{{ .Boilerplate }} + +package controller + +import ( + "sigs.k8s.io/controller-runtime/pkg/manager" +) + +// AddToManagerFuncs is a list of functions to add all Controllers to the Manager +var AddToManagerFuncs []func(manager.Manager) error + +// AddToManager adds all Controllers to the Manager +func AddToManager(m manager.Manager) error { + for _, f := range AddToManagerFuncs { + if err := f(m); err != nil { + return err + } + } + return nil +} +` diff --git a/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/manager/dockerfile.go b/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/manager/dockerfile.go new file mode 100644 index 0000000000..957dd3d69e --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/manager/dockerfile.go @@ -0,0 +1,70 @@ +/* +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 ( + "sigs.k8s.io/controller-tools/pkg/scaffold/input" +) + +var _ input.File = &Dockerfile{} + +// Dockerfile scaffolds a Dockerfile for building a main +type Dockerfile struct { + input.Input +} + +// GetInput implements input.File +func (c *Dockerfile) GetInput() (input.Input, error) { + if c.Path == "" { + c.Path = "Dockerfile" + } + c.TemplateBody = dockerfileTemplate + return c.Input, nil +} + +var dockerfileTemplate = `# Build and test the manager binary +FROM golang:1.9.3 as builder + +# Copy in the go src +WORKDIR /go/src/{{ .Repo }} +COPY pkg/ pkg/ +COPY cmd/ cmd/ +COPY vendor/ vendor/ + +# Run tests as a sanity check +ENV TEST_ASSET_DIR /usr/local/bin +ENV TEST_ASSET_KUBECTL $TEST_ASSET_DIR/kubectl +ENV TEST_ASSET_KUBE_APISERVER $TEST_ASSET_DIR/kube-apiserver +ENV TEST_ASSET_ETCD $TEST_ASSET_DIR/etcd +ENV TEST_ASSET_URL https://storage.googleapis.com/k8s-c10s-test-binaries +RUN curl ${TEST_ASSET_URL}/etcd-Linux-x86_64 --output $TEST_ASSET_ETCD +RUN curl ${TEST_ASSET_URL}/kube-apiserver-Linux-x86_64 --output $TEST_ASSET_KUBE_APISERVER +RUN curl https://storage.googleapis.com/kubernetes-release/release/v1.9.2/bin/linux/amd64/kubectl --output $TEST_ASSET_KUBECTL +RUN chmod +x $TEST_ASSET_ETCD +RUN chmod +x $TEST_ASSET_KUBE_APISERVER +RUN chmod +x $TEST_ASSET_KUBECTL +RUN go test ./pkg/... ./cmd/... + +# Build +RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -o manager {{ .Repo }}/cmd/manager + +# Copy the controller-manager into a thin image +FROM ubuntu:latest +WORKDIR /root/ +COPY --from=builder /go/src/{{ .Repo }}/manager . +ENTRYPOINT ["./manager"] +` diff --git a/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/project/boilerplate.go b/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/project/boilerplate.go new file mode 100644 index 0000000000..6a9222628f --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/project/boilerplate.go @@ -0,0 +1,86 @@ +/* +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 project + +import ( + "fmt" + "path/filepath" + "time" + + "sigs.k8s.io/controller-tools/pkg/scaffold/input" +) + +var _ input.File = &Boilerplate{} + +// Boilerplate scaffolds a boilerplate header file. +type Boilerplate struct { + input.Input + + // License is the License type to write + License string + + // Owner is the copyright owner - e.g. "The Kubernetes Authors" + Owner string + + // Year is the copyright year + Year string +} + +// GetInput implements input.File +func (c *Boilerplate) GetInput() (input.Input, error) { + if c.Path == "" { + c.Path = filepath.Join("hack", "boilerplate.go.txt") + } + + // Boilerplate given + if len(c.Boilerplate) > 0 { + c.TemplateBody = c.Boilerplate + return c.Input, nil + } + + // Pick a template boilerplate option + if c.Year == "" { + c.Year = fmt.Sprintf("%v", time.Now().Year()) + } + switch c.License { + case "", "apache2": + c.TemplateBody = apache + case "none": + c.TemplateBody = none + } + return c.Input, nil +} + +var apache = `/* +{{ if .Owner }}Copyright {{ .Year }} {{ .Owner }}. +{{ end }} +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. +*/` + +var none = `/* +{{ if .Owner }}Copyright {{ .Year }} {{ .Owner }}{{ end }}. +*/` diff --git a/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/project/gitignore.go b/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/project/gitignore.go new file mode 100644 index 0000000000..4018e34805 --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/project/gitignore.go @@ -0,0 +1,62 @@ +/* +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 project + +import ( + "sigs.k8s.io/controller-tools/pkg/scaffold/input" +) + +var _ input.File = &GitIgnore{} + +// GitIgnore scaffolds the .gitignore file +type GitIgnore struct { + input.Input +} + +// GetInput implements input.File +func (c *GitIgnore) GetInput() (input.Input, error) { + if c.Path == "" { + c.Path = ".gitignore" + } + c.TemplateBody = gitignoreTemplate + return c.Input, nil +} + +var gitignoreTemplate = ` +# 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 + +# Kubernetes Generated files + +zz_generated.* + +# editor and IDE paraphernalia +.idea +*.swp +*.swo +*~ +` diff --git a/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/project/gopkg.go b/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/project/gopkg.go new file mode 100644 index 0000000000..7d9da137b9 --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/project/gopkg.go @@ -0,0 +1,317 @@ +/* +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 project + +import ( + "bufio" + "bytes" + "fmt" + "io/ioutil" + "strings" + + "sigs.k8s.io/controller-tools/pkg/scaffold/input" +) + +var _ input.File = &GopkgToml{} + +// GopkgToml writes a templatefile for Gopkg.toml +type GopkgToml struct { + input.Input + + // ManagedHeader is the header to write after the user owned pieces and before the managed parts of the Gopkg.toml + ManagedHeader string + + // DefaultGopkgUserContent is the default content to use for the user owned pieces + DefaultUserContent string + + // UserContent is the content to use for the user owned pieces + UserContent string + + // Stanzas are additional managed stanzas to add after the ManagedHeader + Stanzas []Stanza +} + +// Stanza is a single Gopkg.toml entry +type Stanza struct { + // Type will be between the'[[]]' e.g. override + Type string + + // Name will appear after 'name=' and does not include quotes e.g. k8s.io/client-go + Name string + // Version will appear after 'version=' and does not include quotes + Version string + + // Revision will appear after 'revsion=' and does not include quotes + Revision string +} + +// GetInput implements input.File +func (g *GopkgToml) GetInput() (input.Input, error) { + if g.Path == "" { + g.Path = "Gopkg.toml" + } + if g.ManagedHeader == "" { + g.ManagedHeader = DefaultGopkgHeader + } + + // Set the user content to be used if the Gopkg.toml doesn't exist + if g.DefaultUserContent == "" { + g.DefaultUserContent = DefaultGopkgUserContent + } + + // Set the user owned content from the last Gopkg.toml file - e.g. everything before the header + lastBytes, err := ioutil.ReadFile(g.Path) + if err != nil { + g.UserContent = g.DefaultUserContent + } else if g.UserContent, err = g.getUserContent(lastBytes); err != nil { + return input.Input{}, err + } + + g.Input.IfExistsAction = input.Overwrite + g.TemplateBody = depTemplate + return g.Input, nil +} + +func (g *GopkgToml) getUserContent(b []byte) (string, error) { + // Keep the users lines + scanner := bufio.NewScanner(bytes.NewReader(b)) + userLines := []string{} + found := false + for scanner.Scan() { + l := scanner.Text() + if l == g.ManagedHeader { + found = true + break + } + userLines = append(userLines, l) + } + + if !found { + return "", fmt.Errorf( + "skipping modifying Gopkg.toml - file already exists and is unmanaged") + } + return strings.Join(userLines, "\n"), nil +} + +// DefaultGopkgHeader is the default header used to separate user managed lines and controller-manager managed lines +const DefaultGopkgHeader = "# STANZAS BELOW ARE GENERATED AND MAY BE WRITTEN - DO NOT MODIFY BELOW THIS LINE." + +// DefaultGopkgUserContent is the default user managed lines to provide. +const DefaultGopkgUserContent = `required = [ + "github.com/emicklei/go-restful", + "github.com/onsi/ginkgo", # for test framework + "github.com/onsi/gomega", # for test matchers + "k8s.io/client-go/plugin/pkg/client/auth/gcp", # for development against gcp + "k8s.io/code-generator/cmd/deepcopy-gen", # for go generate + "sigs.k8s.io/controller-runtime/pkg/client/config", + "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/runtime/signals", + "sigs.k8s.io/controller-runtime/pkg/source", + "sigs.k8s.io/testing_frameworks/integration", # for integration testing + "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1", + ] + +[prune] + go-tests = true + +` + +var depTemplate = `{{ .UserContent }} +# STANZAS BELOW ARE GENERATED AND MAY BE WRITTEN - DO NOT MODIFY BELOW THIS LINE. + +{{ range $element := .Stanzas -}} +[[{{ .Type }}]] +name="{{ .Name }}" +{{ if .Version }}version="{{.Version}}"{{ end }} +{{ if .Revision }}revision="{{.Revision}}"{{ end }} +{{ end -}} + +[[override]] +name="cloud.google.com/go" +version="v0.21.0" + +[[override]] +name="github.com/PuerkitoBio/purell" +version="v1.1.0" + +[[override]] +name="github.com/PuerkitoBio/urlesc" +revision="de5bf2ad457846296e2031421a34e2568e304e35" + +[[override]] +name="github.com/davecgh/go-spew" +version="v1.1.0" + +[[override]] +name="github.com/emicklei/go-restful" +version="v2.7.0" + +[[override]] +name="github.com/ghodss/yaml" +version="v1.0.0" + +[[override]] +name="github.com/go-openapi/jsonpointer" +revision="3a0015ad55fa9873f41605d3e8f28cd279c32ab2" + +[[override]] +name="github.com/go-openapi/jsonreference" +revision="3fb327e6747da3043567ee86abd02bb6376b6be2" + +[[override]] +name="github.com/go-openapi/spec" +revision="bcff419492eeeb01f76e77d2ebc714dc97b607f5" + +[[override]] +name="github.com/go-openapi/swag" +revision="811b1089cde9dad18d4d0c2d09fbdbf28dbd27a5" + +[[override]] +name="github.com/gogo/protobuf" +version="v1.0.0" + +[[override]] +name="github.com/golang/glog" +revision="23def4e6c14b4da8ac2ed8007337bc5eb5007998" + +[[override]] +name="github.com/golang/groupcache" +revision="66deaeb636dff1ac7d938ce666d090556056a4b0" + +[[override]] +name="github.com/golang/protobuf" +version="v1.1.0" + +[[override]] +name="github.com/google/gofuzz" +revision="24818f796faf91cd76ec7bddd72458fbced7a6c1" + +[[override]] +name="github.com/googleapis/gnostic" +version="v0.1.0" + +[[override]] +name="github.com/hashicorp/golang-lru" +revision="0fb14efe8c47ae851c0034ed7a448854d3d34cf3" + +[[override]] +name="github.com/howeyc/gopass" +revision="bf9dde6d0d2c004a008c27aaee91170c786f6db8" + +[[override]] +name="github.com/imdario/mergo" +version="v0.3.4" + +[[override]] +name="github.com/json-iterator/go" +version="1.1.3" + +[[override]] +name="github.com/mailru/easyjson" +revision="8b799c424f57fa123fc63a99d6383bc6e4c02578" + +[[override]] +name="github.com/modern-go/concurrent" +version="1.0.3" + +[[override]] +name="github.com/modern-go/reflect2" +version="1.0.0" + +[[override]] +name="github.com/onsi/ginkgo" +version="v1.4.0" + +[[override]] +name="github.com/onsi/gomega" +version="v1.3.0" + +[[override]] +name="github.com/spf13/pflag" +version="v1.0.1" + +[[override]] +name="golang.org/x/crypto" +revision="4ec37c66abab2c7e02ae775328b2ff001c3f025a" + +[[override]] +name="golang.org/x/net" +revision="640f4622ab692b87c2f3a94265e6f579fe38263d" + +[[override]] +name="golang.org/x/oauth2" +revision="cdc340f7c179dbbfa4afd43b7614e8fcadde4269" + +[[override]] +name="golang.org/x/sys" +revision="7db1c3b1a98089d0071c84f646ff5c96aad43682" + +[[override]] +name="golang.org/x/text" +version="v0.3.0" + +[[override]] +name="golang.org/x/time" +revision="fbb02b2291d28baffd63558aa44b4b56f178d650" + +[[override]] +name="google.golang.org/appengine" +version="v1.0.0" + +[[override]] +name="gopkg.in/inf.v0" +version="v0.9.1" + +[[override]] +name="gopkg.in/yaml.v2" +version="v2.2.1" + +[[override]] +name="k8s.io/api" +version="kubernetes-1.10.0" + +[[override]] +name="k8s.io/apiextensions-apiserver" +version="kubernetes-1.10.1" + +[[override]] +name="k8s.io/apimachinery" +version="kubernetes-1.10.0" + +[[override]] +name="k8s.io/client-go" +version="kubernetes-1.10.1" + +[[override]] +name="k8s.io/kube-aggregator" +version="kubernetes-1.10.1" + +[[override]] +name="k8s.io/kube-openapi" +revision="f08db293d3ef80052d6513ece19792642a289fea" + +[[override]] +name="sigs.k8s.io/testing_frameworks" +revision="f53464b8b84b4507805a0b033a8377b225163fea" + +[[override]] +name = "github.com/thockin/logr" +source = "https://github.com/directxman12/logr.git" +branch = "features/structed" +` diff --git a/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/project/makefile.go b/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/project/makefile.go new file mode 100644 index 0000000000..ebeeb7d840 --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/project/makefile.go @@ -0,0 +1,70 @@ +/* +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 project + +import ( + "sigs.k8s.io/controller-tools/pkg/scaffold/input" +) + +var _ input.File = &Makefile{} + +// Makefile scaffolds the Makefile +type Makefile struct { + input.Input +} + +// GetInput implements input.File +func (c *Makefile) GetInput() (input.Input, error) { + if c.Path == "" { + c.Path = "Makefile" + } + c.TemplateBody = makefileTemplate + c.Input.IfExistsAction = input.Error + return c.Input, nil +} + +var makefileTemplate = ` +all: test manager + +# Run tests +test: generate fmt vet + go test ./pkg/... ./cmd/... -coverprofile cover.out + +# Build manager binary +manager: generate fmt vet + go build -o bin/manager {{ .Repo }}/cmd/manager + +# Run against the configured Kubernetes cluster in ~/.kube/config +run: generate fmt vet + go run ./cmd/manager/main.go + +# Install CRDs into a cluster +install: + kubectl apply -f config/crds + +# Run go fmt against code +fmt: + go fmt ./pkg/... ./cmd/... + +# Run go vet against code +vet: + go vet ./pkg/... ./cmd/... + +# Generate code +generate: + go generate ./pkg/... ./cmd/... +` diff --git a/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/project/project.go b/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/project/project.go new file mode 100644 index 0000000000..2299c5ba29 --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/project/project.go @@ -0,0 +1,95 @@ +/* +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 project + +import ( + "fmt" + "go/build" + "os" + "path/filepath" + "strings" + + "gopkg.in/yaml.v2" + "sigs.k8s.io/controller-tools/pkg/scaffold/input" +) + +var _ input.File = &Project{} + +// Project scaffolds the PROJECT file with project metadata +type Project struct { + // Path is the output file location - defaults to PROJECT + Path string + + input.ProjectFile +} + +// GetInput implements input.File +func (c *Project) GetInput() (input.Input, error) { + if c.Path == "" { + c.Path = "PROJECT" + } + if c.Repo == "" { + r, err := c.repoFromGopathAndWd(os.Getenv("GOPATH"), os.Getwd) + if err != nil { + return input.Input{}, err + } + c.Repo = r + } + + out, err := yaml.Marshal(c.ProjectFile) + if err != nil { + return input.Input{}, err + } + + return input.Input{ + Path: c.Path, + TemplateBody: string(out), + Repo: c.Repo, + Version: c.Version, + Domain: c.Domain, + IfExistsAction: input.Error, + }, nil +} + +func (Project) repoFromGopathAndWd(gopath string, getwd func() (string, error)) (string, error) { + // Assume the working dir is the root of the repo + wd, err := getwd() + if err != nil { + return "", err + } + + // Strip the GOPATH from the working dir to get the go package of the repo + if len(gopath) == 0 { + gopath = build.Default.GOPATH + } + goSrc := filepath.Join(gopath, "src") + + // Make sure the GOPATH is set and the working dir is under the GOPATH + if !strings.HasPrefix(filepath.Dir(wd), goSrc) { + return "", fmt.Errorf("working directory must be a project directory under "+ + "$GOPATH/src/\n- GOPATH=%s\n- WD=%s", gopath, wd) + } + + // Figure out the repo name by removing $GOPATH/src from the working directory - e.g. + // '$GOPATH/src/kubernetes-sigs/controller-tools' becomes 'kubernetes-sigs/controller-tools' + repo := "" + for wd != goSrc { + repo = filepath.Join(filepath.Base(wd), repo) + wd = filepath.Dir(wd) + } + return repo, nil +} diff --git a/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/project/projectutil/projectutil.go b/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/project/projectutil/projectutil.go new file mode 100644 index 0000000000..921377d7b2 --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/project/projectutil/projectutil.go @@ -0,0 +1,48 @@ +/* +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 projectutil + +import ( + "fmt" + "io/ioutil" + "os" + "path/filepath" + "strings" +) + +// GetProjectDir walks up the tree until it finds a directory with a PROJECT file +func GetProjectDir() (string, error) { + gopath := os.Getenv("GOPATH") + dir, err := filepath.Abs(".") + if err != nil { + return "", err + } + // Walk up until we find PROJECT or are outside the GOPATH + for strings.Contains(dir, gopath) { + files, err := ioutil.ReadDir(dir) + if err != nil { + return "", err + } + for _, f := range files { + if f.Name() == "PROJECT" { + return dir, nil + } + } + dir = filepath.Dir(dir) + } + return "", fmt.Errorf("unable to locate PROJECT file") +} diff --git a/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/resource/addtoscheme.go b/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/resource/addtoscheme.go new file mode 100644 index 0000000000..ecb4cd90e4 --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/resource/addtoscheme.go @@ -0,0 +1,58 @@ +/* +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 resource + +import ( + "fmt" + "path/filepath" + + "sigs.k8s.io/controller-tools/pkg/scaffold/input" +) + +var _ input.File = &AddToScheme{} + +// AddToScheme scaffolds the code to add the resource to a SchemeBuilder. +type AddToScheme struct { + input.Input + + // Resource is a resource in the API group + Resource *Resource +} + +// GetInput implements input.File +func (a *AddToScheme) GetInput() (input.Input, error) { + if a.Path == "" { + a.Path = filepath.Join("pkg", "apis", fmt.Sprintf( + "addtoscheme_%s_%s.go", a.Resource.Group, a.Resource.Version)) + } + a.TemplateBody = addResourceTemplate + return a.Input, nil +} + +var addResourceTemplate = `{{ .Boilerplate }} + +package apis + +import ( + "{{ .Repo }}/pkg/apis/{{ .Resource.Group }}/{{ .Resource.Version }}" +) + +func init() { + // Register the types with the Scheme so the components can map objects to GroupVersionKinds and back + AddToSchemes = append(AddToSchemes, {{ .Resource.Version }}.SchemeBuilder.AddToScheme) +} +` diff --git a/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/resource/crd.go b/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/resource/crd.go new file mode 100644 index 0000000000..cac02f9e31 --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/resource/crd.go @@ -0,0 +1,77 @@ +/* +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 resource + +import ( + "fmt" + "path/filepath" + + "strings" + + "github.com/markbates/inflect" + "sigs.k8s.io/controller-tools/pkg/scaffold/input" +) + +var _ input.File = &CRD{} + +// CRD scaffolds a CRD yaml file. +type CRD struct { + input.Input + + // Scope is Namespaced or Cluster + Scope string + + // Plural is the plural lowercase of kind + Plural string + + // Resource is a resource in the API group + Resource *Resource +} + +// GetInput implements input.File +func (c *CRD) GetInput() (input.Input, error) { + if c.Path == "" { + c.Path = filepath.Join("config", "crds", fmt.Sprintf( + "%s_%s_%s.yaml", c.Resource.Group, c.Resource.Version, strings.ToLower(c.Resource.Kind))) + } + c.Scope = "Namespaced" + if !c.Resource.Namespaced { + c.Scope = "Cluster" + } + if c.Plural == "" { + c.Plural = strings.ToLower(inflect.Pluralize(c.Resource.Kind)) + } + + c.IfExistsAction = input.Error + c.TemplateBody = crdTemplate + return c.Input, nil +} + +var crdTemplate = `apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + labels: + controller-tools.k8s.io: "1.0" + name: {{ .Plural }}.{{ .Resource.Group }}.{{ .Domain }} +spec: + group: {{ .Resource.Group }}.{{ .Domain }} + version: "{{ .Resource.Version }}" + names: + kind: {{ .Resource.Kind }} + plural: {{ .Plural }} + scope: {{ .Scope }} +` diff --git a/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/resource/doc.go b/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/resource/doc.go new file mode 100644 index 0000000000..b35dd47d4d --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/resource/doc.go @@ -0,0 +1,56 @@ +/* +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 resource + +import ( + "path/filepath" + + "sigs.k8s.io/controller-tools/pkg/scaffold/input" +) + +var _ input.File = &Doc{} + +// Doc scaffolds the pkg/apis/group/version/doc.go directory +type Doc struct { + input.Input + + // Resource is a resource for the API version + Resource *Resource + + // Comments are additional lines to write to the doc.go file + Comments []string +} + +// GetInput implements input.File +func (a *Doc) GetInput() (input.Input, error) { + if a.Path == "" { + a.Path = filepath.Join("pkg", "apis", a.Resource.Group, a.Resource.Version, "doc.go") + } + a.TemplateBody = docGoTemplate + return a.Input, nil +} + +var docGoTemplate = `{{ .Boilerplate }} + +// Package {{.Resource.Version}} contains API Schema definitions for the {{ .Resource.Group }} {{.Resource.Version}} API group +// +k8s:openapi-gen=true +// +k8s:deepcopy-gen=package,register +// +k8s:conversion-gen={{ .Repo }}/pkg/apis/{{ .Resource.Group }} +// +k8s:defaulter-gen=TypeMeta +// +groupName={{ .Resource.Group }}.{{ .Domain }} +package {{.Resource.Version}} +` diff --git a/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/resource/group.go b/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/resource/group.go new file mode 100644 index 0000000000..7c39d78043 --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/resource/group.go @@ -0,0 +1,48 @@ +/* +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 resource + +import ( + "path/filepath" + + "sigs.k8s.io/controller-tools/pkg/scaffold/input" +) + +var _ input.File = &Group{} + +// Group scaffolds the pkg/apis/group/group.go +type Group struct { + input.Input + + // Resource is a resource in the API group + Resource *Resource +} + +// GetInput implements input.File +func (g *Group) GetInput() (input.Input, error) { + if g.Path == "" { + g.Path = filepath.Join("pkg", "apis", g.Resource.Group, "group.go") + } + g.TemplateBody = groupTemplate + return g.Input, nil +} + +var groupTemplate = `{{ .Boilerplate }} + +// Package {{ .Resource.Group }} contains {{ .Resource.Group }} API versions +package {{ .Resource.Group }} +` diff --git a/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/resource/register.go b/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/resource/register.go new file mode 100644 index 0000000000..c7be30ae1a --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/resource/register.go @@ -0,0 +1,68 @@ +/* +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 resource + +import ( + "path/filepath" + + "sigs.k8s.io/controller-tools/pkg/scaffold/input" +) + +var _ input.File = &Register{} + +// Register scaffolds the pkg/apis/group/version/register.go file +type Register struct { + input.Input + + // Resource is the resource to scaffold the types_test.go file for + Resource *Resource +} + +// GetInput implements input.File +func (r *Register) GetInput() (input.Input, error) { + if r.Path == "" { + r.Path = filepath.Join("pkg", "apis", r.Resource.Group, r.Resource.Version, "register.go") + } + r.TemplateBody = registerTemplate + return r.Input, nil +} + +var registerTemplate = `{{ .Boilerplate }} + +// NOTE: Boilerplate only. Ignore this file. + +// Package {{.Resource.Version}} contains API Schema definitions for the {{ .Resource.Group }} {{.Resource.Version}} API group +// +k8s:openapi-gen=true +// +k8s:deepcopy-gen=package,register +// +k8s:conversion-gen={{ .Repo }}/pkg/apis/{{ .Resource.Group }} +// +k8s:defaulter-gen=TypeMeta +// +groupName={{ .Resource.Group }}.{{ .Domain }} +package {{.Resource.Version}} + +import ( + "k8s.io/apimachinery/pkg/runtime/schema" + "sigs.k8s.io/controller-runtime/pkg/runtime/scheme" +) + +var ( + // SchemeGroupVersion is group version used to register these objects + SchemeGroupVersion = schema.GroupVersion{Group: "{{ .Resource.Group }}.{{ .Domain }}", Version: "{{ .Resource.Version }}"} + + // SchemeBuilder is used to add go types to the GroupVersionKind scheme + SchemeBuilder = &scheme.Builder{GroupVersion: SchemeGroupVersion} +) +` diff --git a/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/resource/resource.go b/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/resource/resource.go new file mode 100644 index 0000000000..6d1b7deda1 --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/resource/resource.go @@ -0,0 +1,84 @@ +/* +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 resource + +import ( + "fmt" + "regexp" + "strings" + + "github.com/markbates/inflect" +) + +// Resource contains the information required to scaffold files for a resource. +type Resource struct { + // Namespaced is true if the resource is namespaced + Namespaced bool + + // Group is the API Group. Does not contain the domain. + Group string + + // Version is the API version - e.g. v1beta1 + Version string + + // Kind is the API Kind. + Kind string + + // Resource is the API Resource. + Resource string + + // ShortNames is the list of resource shortnames. + ShortNames []string + + // CreateExampleReconcileBody will create a Deployment in the Reconcile example + CreateExampleReconcileBody bool +} + +// Validate checks the Resource values to make sure they are valid. +func (r *Resource) Validate() error { + if len(r.Group) == 0 { + return fmt.Errorf("group cannot be empty") + } + if len(r.Version) == 0 { + return fmt.Errorf("version cannot be empty") + } + if len(r.Kind) == 0 { + return fmt.Errorf("kind cannot be empty") + } + + rs := inflect.NewDefaultRuleset() + if len(r.Resource) == 0 { + r.Resource = rs.Pluralize(strings.ToLower(r.Kind)) + } + + groupMatch := regexp.MustCompile("^[a-z]+$") + if !groupMatch.MatchString(r.Group) { + return fmt.Errorf("group must match ^[a-z]+$ (was %s)", r.Group) + } + + versionMatch := regexp.MustCompile("^v\\d+(alpha\\d+|beta\\d+)?$") + if !versionMatch.MatchString(r.Version) { + return fmt.Errorf( + "version must match ^v\\d+(alpha\\d+|beta\\d+)?$ (was %s)", r.Version) + } + + if r.Kind != inflect.Camelize(r.Kind) { + return fmt.Errorf("Kind must be camelcase (expected %s was %s)", inflect.Camelize(r.Kind), r.Kind) + } + + return nil +} diff --git a/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/resource/role.go b/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/resource/role.go new file mode 100644 index 0000000000..a015ee0c3f --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/resource/role.go @@ -0,0 +1,60 @@ +/* +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 resource + +import ( + "fmt" + "path/filepath" + + "sigs.k8s.io/controller-tools/pkg/scaffold/input" +) + +var _ input.File = &RoleBinding{} + +// Role scaffolds the config/manager/group_role_rbac.yaml file +type Role struct { + input.Input + + // Resource is a resource in the API group + Resource *Resource +} + +// GetInput implements input.File +func (r *Role) GetInput() (input.Input, error) { + if r.Path == "" { + r.Path = filepath.Join("config", "manager", fmt.Sprintf( + "%s_role_rbac.yaml", r.Resource.Group)) + } + r.TemplateBody = roleTemplate + return r.Input, nil +} + +var roleTemplate = `apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + controller-tools.k8s.io: "1.0" + name: {{.Resource.Group}}-role +rules: +- apiGroups: + - {{ .Resource.Group }}.{{ .Domain }} + resources: + - '*' + verbs: + - '*' + +` diff --git a/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/resource/rolebinding.go b/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/resource/rolebinding.go new file mode 100644 index 0000000000..f27a898a57 --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/resource/rolebinding.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 resource + +import ( + "fmt" + "path/filepath" + + "sigs.k8s.io/controller-tools/pkg/scaffold/input" +) + +var _ input.File = &RoleBinding{} + +// RoleBinding scaffolds the config/manager/group_rolebinding_rbac.yaml file +type RoleBinding struct { + input.Input + + // Resource is a resource in the API group + Resource *Resource +} + +// GetInput implements input.File +func (r *RoleBinding) GetInput() (input.Input, error) { + if r.Path == "" { + r.Path = filepath.Join("config", "manager", fmt.Sprintf( + "%s_rolebinding_rbac.yaml", r.Resource.Group)) + } + r.TemplateBody = roleBindingTemplate + return r.Input, nil +} + +var roleBindingTemplate = `apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + labels: + controller-tools.k8s.io: "1.0" + name: {{ .Resource.Group }}-rolebinding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ .Resource.Group }}-role +subjects: +- kind: ServiceAccount + name: default +` diff --git a/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/resource/types.go b/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/resource/types.go new file mode 100644 index 0000000000..033e3dc69c --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/resource/types.go @@ -0,0 +1,107 @@ +/* +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 resource + +import ( + "fmt" + "path/filepath" + "strings" + + "sigs.k8s.io/controller-tools/pkg/scaffold/input" +) + +var _ input.File = &Types{} + +// Types scaffolds the pkg/apis/group/version/kind_types.go file to define the schema for an API +type Types struct { + input.Input + + // Resource is the resource to scaffold the types_test.go file for + Resource *Resource +} + +// GetInput implements input.File +func (t *Types) GetInput() (input.Input, error) { + if t.Path == "" { + t.Path = filepath.Join("pkg", "apis", t.Resource.Group, t.Resource.Version, + fmt.Sprintf("%s_types.go", strings.ToLower(t.Resource.Kind))) + } + t.TemplateBody = typesTemplate + t.IfExistsAction = input.Error + return t.Input, nil +} + +// Validate validates the values +func (t *Types) Validate() error { + return t.Resource.Validate() +} + +var typesTemplate = `{{ .Boilerplate }} + +package {{ .Resource.Version }} + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! +// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. + +// {{.Resource.Kind}}Spec defines the desired state of {{.Resource.Kind}} +type {{.Resource.Kind}}Spec struct { + // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster + // Important: Run "kubebuilder generate" to regenerate code after modifying this file +} + +// {{.Resource.Kind}}Status defines the observed state of {{.Resource.Kind}} +type {{.Resource.Kind}}Status struct { + // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster + // Important: Run "kubebuilder generate" to regenerate code after modifying this file +} + +// +genclient +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +{{- if not .Resource.Namespaced }} +// +genclient:nonNamespaced +{{- end }} + +// {{.Resource.Kind}} is the Schema for the {{ .Resource.Resource }} API +// +k8s:openapi-gen=true +type {{.Resource.Kind}} struct { + metav1.TypeMeta ` + "`" + `json:",inline"` + "`" + ` + metav1.ObjectMeta ` + "`" + `json:"metadata,omitempty"` + "`" + ` + + Spec {{.Resource.Kind}}Spec ` + "`" + `json:"spec,omitempty"` + "`" + ` + Status {{.Resource.Kind}}Status ` + "`" + `json:"status,omitempty"` + "`" + ` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +{{- if not .Resource.Namespaced }} +// +genclient:nonNamespaced +{{- end }} + +// {{.Resource.Kind}}List contains a list of {{.Resource.Kind}} +type {{.Resource.Kind}}List struct { + metav1.TypeMeta ` + "`" + `json:",inline"` + "`" + ` + metav1.ListMeta ` + "`" + `json:"metadata,omitempty"` + "`" + ` + Items []{{ .Resource.Kind }} ` + "`" + `json:"items"` + "`" + ` +} + +func init() { + SchemeBuilder.Register(&{{.Resource.Kind}}{}, &{{.Resource.Kind}}List{}) +} +` diff --git a/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/resource/typestest.go b/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/resource/typestest.go new file mode 100644 index 0000000000..c2e657d66e --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/resource/typestest.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 resource + +import ( + "fmt" + "path/filepath" + "strings" + + "sigs.k8s.io/controller-tools/pkg/scaffold/input" +) + +var _ input.File = &TypesTest{} + +// TypesTest scaffolds the pkg/apis/group/version/kind_types_test.go file to test the API schema +type TypesTest struct { + input.Input + + // Resource is the resource to scaffold the types_test.go file for + Resource *Resource +} + +// GetInput implements input.File +func (t *TypesTest) GetInput() (input.Input, error) { + if t.Path == "" { + t.Path = filepath.Join("pkg", "apis", t.Resource.Group, t.Resource.Version, + fmt.Sprintf("%s_types_test.go", strings.ToLower(t.Resource.Kind))) + } + t.TemplateBody = typesTestTemplate + t.IfExistsAction = input.Error + return t.Input, nil +} + +// Validate validates the values +func (t *TypesTest) Validate() error { + return t.Resource.Validate() +} + +var typesTestTemplate = `{{ .Boilerplate }} + +package {{ .Resource.Version }} + +import ( + "testing" + + "github.com/onsi/gomega" + "golang.org/x/net/context" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" +) + +func TestStorage(t *testing.T) { + key := types.NamespacedName{Name: "foo", Namespace: "default"} + created := &{{ .Resource.Kind }}{ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "default"}} + g := gomega.NewGomegaWithT(t) + + // Test Create + fetched := &{{ .Resource.Kind }}{} + g.Expect(c.Create(context.TODO(), created)).NotTo(gomega.HaveOccurred()) + + g.Expect(c.Get(context.TODO(), key, fetched)).NotTo(gomega.HaveOccurred()) + g.Expect(fetched).To(gomega.Equal(created)) + + // Test Updating the Labels + updated := fetched.DeepCopy() + updated.Labels = map[string]string{"hello": "world"} + g.Expect(c.Update(context.TODO(), updated)).NotTo(gomega.HaveOccurred()) + + g.Expect(c.Get(context.TODO(), key, fetched)).NotTo(gomega.HaveOccurred()) + g.Expect(fetched).To(gomega.Equal(updated)) + + // Test Delete + g.Expect(c.Delete(context.TODO(), fetched)).NotTo(gomega.HaveOccurred()) + g.Expect(c.Get(context.TODO(), key, fetched)).To(gomega.HaveOccurred()) +} +` diff --git a/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/resource/version_suitetest.go b/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/resource/version_suitetest.go new file mode 100644 index 0000000000..a6cd14358a --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/resource/version_suitetest.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 resource + +import ( + "fmt" + "path/filepath" + + "sigs.k8s.io/controller-tools/pkg/scaffold/input" +) + +var _ input.File = &TypesTest{} + +// VersionSuiteTest scaffolds the version_suite_test.go file to setup the versions test +type VersionSuiteTest struct { + input.Input + + // Resource is the resource to scaffold the types_test.go file for + Resource *Resource +} + +// GetInput implements input.File +func (v *VersionSuiteTest) GetInput() (input.Input, error) { + if v.Path == "" { + v.Path = filepath.Join("pkg", "apis", v.Resource.Group, v.Resource.Version, + fmt.Sprintf("%s_suite_test.go", v.Resource.Version)) + } + v.TemplateBody = versionSuiteTestTemplate + return v.Input, nil +} + +var versionSuiteTestTemplate = `{{ .Boilerplate }} + +package {{ .Resource.Version }} + +import ( + "log" + "os" + "path/filepath" + "testing" + + "k8s.io/client-go/kubernetes/scheme" + "k8s.io/client-go/rest" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/envtest" +) + +var cfg *rest.Config +var c client.Client + +func TestMain(m *testing.M) { + t := &envtest.Environment{ + CRDDirectoryPaths: []string{filepath.Join("..", "..", "..", "..", "config", "crds")}, + } + + err := SchemeBuilder.AddToScheme(scheme.Scheme) + if err != nil { + log.Fatal(err) + } + + if cfg, err = t.Start(); err != nil { + log.Fatal(err) + } + + if c, err = client.New(cfg, client.Options{Scheme: scheme.Scheme}); err != nil { + log.Fatal(err) + } + + code := m.Run() + t.Stop() + os.Exit(code) +} +` diff --git a/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/scaffold.go b/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/scaffold.go new file mode 100644 index 0000000000..fa73708bc4 --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/scaffold.go @@ -0,0 +1,244 @@ +/* +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 scaffold + +import ( + "io" + "os" + "path/filepath" + "strings" + "text/template" + + "fmt" + + "log" + + "io/ioutil" + + "bytes" + + "golang.org/x/tools/imports" + "gopkg.in/yaml.v2" + "sigs.k8s.io/controller-tools/pkg/scaffold/input" +) + +// Scaffold writes Templates to scaffold new files +type Scaffold struct { + // BoilerplatePath is the path to the boilerplate file + BoilerplatePath string + + // Boilerplate is the contents of the boilerplate file for code generation + Boilerplate string + + BoilerplateOptional bool + + // Project is the project + Project input.ProjectFile + + ProjectOptional bool + + // ProjectPath is the relative path to the project root + ProjectPath string + + GetWriter func(path string) (io.Writer, error) +} + +func (s *Scaffold) setFieldsAndValidate(t input.File) error { + // Set boilerplate on templates + if b, ok := t.(input.BoilerplatePath); ok { + b.SetBoilerplatePath(s.BoilerplatePath) + } + if b, ok := t.(input.Boilerplate); ok { + b.SetBoilerplate(s.Boilerplate) + } + if b, ok := t.(input.Domain); ok { + b.SetDomain(s.Project.Domain) + } + if b, ok := t.(input.Version); ok { + b.SetVersion(s.Project.Version) + } + if b, ok := t.(input.Repo); ok { + b.SetRepo(s.Project.Repo) + } + if b, ok := t.(input.ProjecPath); ok { + b.SetProjectPath(s.ProjectPath) + } + + // Validate the template is ok + if v, ok := t.(input.Validate); ok { + if err := v.Validate(); err != nil { + return err + } + } + return nil +} + +// GetProject reads the project file and deserializes it into a Project +func getProject(path string) (input.ProjectFile, error) { + in, err := ioutil.ReadFile(path) + if err != nil { + return input.ProjectFile{}, err + } + p := input.ProjectFile{} + err = yaml.Unmarshal(in, &p) + if err != nil { + return input.ProjectFile{}, err + } + return p, nil +} + +// GetBoilerplate reads the boilerplate file +func getBoilerplate(path string) (string, error) { + b, err := ioutil.ReadFile(path) + return string(b), err +} + +func (s *Scaffold) defaultOptions(options *input.Options) error { + // Use the default Boilerplate path if unset + if options.BoilerplatePath == "" { + options.BoilerplatePath = filepath.Join("hack", "boilerplate.go.txt") + } + + // Use the default Project path if unset + if options.ProjectPath == "" { + options.ProjectPath = "PROJECT" + } + + s.BoilerplatePath = options.BoilerplatePath + + var err error + s.Boilerplate, err = getBoilerplate(options.BoilerplatePath) + if !s.BoilerplateOptional && err != nil { + return err + } + + s.Project, err = getProject(options.ProjectPath) + if !s.ProjectOptional && err != nil { + return err + } + return nil +} + +// Execute executes scaffolding the Files +func (s *Scaffold) Execute(options input.Options, files ...input.File) error { + if s.GetWriter == nil { + s.GetWriter = newWriteCloser + } + + if err := s.defaultOptions(&options); err != nil { + return err + } + for _, f := range files { + if err := s.doFile(f); err != nil { + return err + } + } + return nil +} + +// doFile scaffolds a single file +func (s *Scaffold) doFile(e input.File) error { + // Set common fields + err := s.setFieldsAndValidate(e) + if err != nil { + return err + } + + // Get the template input params + i, err := e.GetInput() + if err != nil { + return err + } + + // Check if the file to write already exists + if _, err := os.Stat(i.Path); err == nil { + switch i.IfExistsAction { + case input.Overwrite: + case input.Skip: + return nil + case input.Error: + return fmt.Errorf("%s already exists", i.Path) + } + } + + if err := s.doTemplate(i, e); err != nil { + return err + } + return nil +} + +// doTemplate executes the template for a file using the input +func (s *Scaffold) doTemplate(i input.Input, e input.File) error { + temp, err := newTemplate(e).Parse(i.TemplateBody) + if err != nil { + return err + } + f, err := s.GetWriter(i.Path) + if err != nil { + return err + } + if c, ok := f.(io.Closer); ok { + defer func() { + if err := c.Close(); err != nil { + log.Fatal(err) + } + }() + } + + out := &bytes.Buffer{} + err = temp.Execute(out, e) + if err != nil { + return err + } + b := out.Bytes() + + // gofmt the imports + if filepath.Ext(i.Path) == ".go" { + b, err = imports.Process(i.Path, b, nil) + if err != nil { + fmt.Printf("%s\n", out.Bytes()) + return err + } + } + + _, err = f.Write(b) + return err +} + +// newWriteCloser returns a WriteCloser to write scaffold to +func newWriteCloser(path string) (io.Writer, error) { + dir := filepath.Dir(path) + err := os.MkdirAll(dir, 0700) + if err != nil { + return nil, err + } + + fi, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600) + if err != nil { + return nil, err + } + + return fi, nil +} + +// newTemplate a new template with common functions +func newTemplate(t input.File) *template.Template { + return template.New(fmt.Sprintf("%T", t)).Funcs(template.FuncMap{ + "title": strings.Title, + "lower": strings.ToLower, + }) +} diff --git a/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/scaffoldtest/scaffoldtest.go b/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/scaffoldtest/scaffoldtest.go new file mode 100644 index 0000000000..b372c3590b --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/controller-tools/pkg/scaffold/scaffoldtest/scaffoldtest.go @@ -0,0 +1,86 @@ +/* +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 scaffoldtest + +import ( + "bytes" + "io" + "io/ioutil" + "path/filepath" + + "github.com/onsi/ginkgo" + "github.com/onsi/gomega" + "sigs.k8s.io/controller-tools/pkg/scaffold" + "sigs.k8s.io/controller-tools/pkg/scaffold/input" + "sigs.k8s.io/controller-tools/pkg/scaffold/project/projectutil" +) + +// TestResult is the result of running the scaffolding. +type TestResult struct { + // Actual is the bytes written to a scaffolded file. + Actual bytes.Buffer + + // Golden is the golden file contents read from the controller-tools/test package + Golden string +} + +// ProjectPath is the path to the controller-tools/test project file +func ProjectPath() string { + root, err := projectutil.GetProjectDir() + gomega.Expect(err).NotTo(gomega.HaveOccurred()) + return filepath.Join(root, "test", "PROJECT") +} + +// BoilerplatePath is the path to the controller-tools/test boilerplate file +func BoilerplatePath() string { + root, err := projectutil.GetProjectDir() + gomega.Expect(err).NotTo(gomega.HaveOccurred()) + return filepath.Join(root, "test", "hack", "boilerplate.go.txt") +} + +// Options are the options for scaffolding in the controller-tools/test directory +func Options() input.Options { + return input.Options{ + BoilerplatePath: BoilerplatePath(), + ProjectPath: ProjectPath(), + } +} + +// NewTestScaffold returns a new Scaffold and TestResult instance for testing +func NewTestScaffold(writeToPath, goldenPath string) (*scaffold.Scaffold, *TestResult) { + r := &TestResult{} + + root, err := projectutil.GetProjectDir() + gomega.Expect(err).NotTo(gomega.HaveOccurred()) + + // Setup scaffold + s := &scaffold.Scaffold{ + GetWriter: func(path string) (io.Writer, error) { + defer ginkgo.GinkgoRecover() + gomega.Expect(path).To(gomega.Equal(writeToPath)) + return &r.Actual, nil + }, + ProjectPath: filepath.Join(root, "test"), + } + + if len(goldenPath) > 0 { + b, err := ioutil.ReadFile(filepath.Join(root, "test", goldenPath)) + gomega.Expect(err).NotTo(gomega.HaveOccurred()) + r.Golden = string(b) + } + return s, r +} diff --git a/cmd/vendor/sigs.k8s.io/controller-tools/test/cmd/manager/main.go b/cmd/vendor/sigs.k8s.io/controller-tools/test/cmd/manager/main.go new file mode 100644 index 0000000000..c05b7462ca --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/controller-tools/test/cmd/manager/main.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 main + +import ( + "log" + + _ "k8s.io/client-go/plugin/pkg/client/auth/gcp" + "sigs.k8s.io/controller-runtime/pkg/client/config" + "sigs.k8s.io/controller-runtime/pkg/manager" + "sigs.k8s.io/controller-runtime/pkg/runtime/signals" + "sigs.k8s.io/controller-tools/test/pkg/apis" + "sigs.k8s.io/controller-tools/test/pkg/controller" +) + +func main() { + // Get a config to talk to the apiserver + cfg, err := config.GetConfig() + if err != nil { + log.Fatal(err) + } + + // Create a new Cmd to provide shared dependencies and start components + mgr, err := manager.New(cfg, manager.Options{}) + if err != nil { + log.Fatal(err) + } + + log.Printf("Registering Components.") + + // Setup Scheme for all resources + if err := apis.AddToScheme(mgr.GetScheme()); err != nil { + log.Fatal(err) + } + + // Setup all Controllers + if err := controller.AddToManager(mgr); err != nil { + log.Fatal(err) + } + + log.Printf("Starting the Cmd.") + + // Start the Cmd + log.Fatal(mgr.Start(signals.SetupSignalHandler())) +} diff --git a/cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/apis/addtoscheme_creatures_v2alpha1.go b/cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/apis/addtoscheme_creatures_v2alpha1.go new file mode 100644 index 0000000000..06e25705a4 --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/apis/addtoscheme_creatures_v2alpha1.go @@ -0,0 +1,26 @@ +/* +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 apis + +import ( + "sigs.k8s.io/controller-tools/test/pkg/apis/creatures/v2alpha1" +) + +func init() { + // Register the types with the Scheme so the components can map objects to GroupVersionKinds and back + AddToSchemes = append(AddToSchemes, v2alpha1.SchemeBuilder.AddToScheme) +} diff --git a/cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/apis/addtoscheme_crew_v1.go b/cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/apis/addtoscheme_crew_v1.go new file mode 100644 index 0000000000..0e388bbc58 --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/apis/addtoscheme_crew_v1.go @@ -0,0 +1,26 @@ +/* +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 apis + +import ( + "sigs.k8s.io/controller-tools/test/pkg/apis/crew/v1" +) + +func init() { + // Register the types with the Scheme so the components can map objects to GroupVersionKinds and back + AddToSchemes = append(AddToSchemes, v1.SchemeBuilder.AddToScheme) +} diff --git a/cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/apis/addtoscheme_ship_v1beta1.go b/cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/apis/addtoscheme_ship_v1beta1.go new file mode 100644 index 0000000000..62eb7a9400 --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/apis/addtoscheme_ship_v1beta1.go @@ -0,0 +1,26 @@ +/* +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 apis + +import ( + "sigs.k8s.io/controller-tools/test/pkg/apis/ship/v1beta1" +) + +func init() { + // Register the types with the Scheme so the components can map objects to GroupVersionKinds and back + AddToSchemes = append(AddToSchemes, v1beta1.SchemeBuilder.AddToScheme) +} diff --git a/cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/apis/apis.go b/cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/apis/apis.go new file mode 100644 index 0000000000..ddd4d73ab0 --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/apis/apis.go @@ -0,0 +1,33 @@ +/* +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. +*/ + +// Generate deepcopy for apis +//go:generate go run ../../vendor/k8s.io/code-generator/cmd/deepcopy-gen/main.go -O zz_generated.deepcopy -i ./... -h ../../hack/boilerplate.go.txt + +// Package apis contains Kubernetes API groups. +package apis + +import ( + "k8s.io/apimachinery/pkg/runtime" +) + +// AddToSchemes may be used to add all resources defined in the project to a Scheme +var AddToSchemes runtime.SchemeBuilder + +// AddToScheme adds all Resources to the Scheme +func AddToScheme(s *runtime.Scheme) error { + return AddToSchemes.AddToScheme(s) +} diff --git a/cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/apis/creatures/group.go b/cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/apis/creatures/group.go new file mode 100644 index 0000000000..7220f7c32c --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/apis/creatures/group.go @@ -0,0 +1,18 @@ +/* +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 creatures contains creatures API versions +package creatures diff --git a/cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/apis/creatures/v2alpha1/doc.go b/cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/apis/creatures/v2alpha1/doc.go new file mode 100644 index 0000000000..1bb98d32b7 --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/apis/creatures/v2alpha1/doc.go @@ -0,0 +1,23 @@ +/* +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 v2alpha1 contains API Schema definitions for the creatures v2alpha1 API group +// +k8s:openapi-gen=true +// +k8s:deepcopy-gen=package,register +// +k8s:conversion-gen=sigs.k8s.io/controller-tools/test/pkg/apis/creatures +// +k8s:defaulter-gen=TypeMeta +// +groupName=creatures.k8s.io +package v2alpha1 diff --git a/cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/apis/creatures/v2alpha1/kraken_types.go b/cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/apis/creatures/v2alpha1/kraken_types.go new file mode 100644 index 0000000000..bc28feac2e --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/apis/creatures/v2alpha1/kraken_types.go @@ -0,0 +1,64 @@ +/* +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 v2alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! +// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. + +// KrakenSpec defines the desired state of Kraken +type KrakenSpec struct { + // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster + // Important: Run "kubebuilder generate" to regenerate code after modifying this file +} + +// KrakenStatus defines the observed state of Kraken +type KrakenStatus struct { + // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster + // Important: Run "kubebuilder generate" to regenerate code after modifying this file +} + +// +genclient +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +genclient:nonNamespaced + +// Kraken is the Schema for the krakens API +// +k8s:openapi-gen=true +type Kraken struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec KrakenSpec `json:"spec,omitempty"` + Status KrakenStatus `json:"status,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +genclient:nonNamespaced + +// KrakenList contains a list of Kraken +type KrakenList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []Kraken `json:"items"` +} + +func init() { + SchemeBuilder.Register(&Kraken{}, &KrakenList{}) +} diff --git a/cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/apis/creatures/v2alpha1/register.go b/cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/apis/creatures/v2alpha1/register.go new file mode 100644 index 0000000000..ae0dde124f --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/apis/creatures/v2alpha1/register.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. +*/ + +// NOTE: Boilerplate only. Ignore this file. + +// Package v2alpha1 contains API Schema definitions for the creatures v2alpha1 API group +// +k8s:openapi-gen=true +// +k8s:deepcopy-gen=package,register +// +k8s:conversion-gen=sigs.k8s.io/controller-tools/test/pkg/apis/creatures +// +k8s:defaulter-gen=TypeMeta +// +groupName=creatures.k8s.io +package v2alpha1 + +import ( + "k8s.io/apimachinery/pkg/runtime/schema" + "sigs.k8s.io/controller-runtime/pkg/runtime/scheme" +) + +var ( + // SchemeGroupVersion is group version used to register these objects + SchemeGroupVersion = schema.GroupVersion{Group: "creatures.k8s.io", Version: "v2alpha1"} + + // SchemeBuilder is used to add go types to the GroupVersionKind scheme + SchemeBuilder = &scheme.Builder{GroupVersion: SchemeGroupVersion} +) diff --git a/cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/apis/crew/group.go b/cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/apis/crew/group.go new file mode 100644 index 0000000000..b21d49df43 --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/apis/crew/group.go @@ -0,0 +1,18 @@ +/* +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 crew contains crew API versions +package crew diff --git a/cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/apis/crew/v1/doc.go b/cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/apis/crew/v1/doc.go new file mode 100644 index 0000000000..c3a5aaffa9 --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/apis/crew/v1/doc.go @@ -0,0 +1,23 @@ +/* +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 v1 contains API Schema definitions for the crew v1 API group +// +k8s:openapi-gen=true +// +k8s:deepcopy-gen=package,register +// +k8s:conversion-gen=sigs.k8s.io/controller-tools/test/pkg/apis/crew +// +k8s:defaulter-gen=TypeMeta +// +groupName=crew.k8s.io +package v1 diff --git a/cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/apis/crew/v1/firstmate_types.go b/cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/apis/crew/v1/firstmate_types.go new file mode 100644 index 0000000000..8342a76b27 --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/apis/crew/v1/firstmate_types.go @@ -0,0 +1,62 @@ +/* +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 v1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! +// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. + +// FirstMateSpec defines the desired state of FirstMate +type FirstMateSpec struct { + // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster + // Important: Run "kubebuilder generate" to regenerate code after modifying this file +} + +// FirstMateStatus defines the observed state of FirstMate +type FirstMateStatus struct { + // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster + // Important: Run "kubebuilder generate" to regenerate code after modifying this file +} + +// +genclient +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// FirstMate is the Schema for the firstmates API +// +k8s:openapi-gen=true +type FirstMate struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec FirstMateSpec `json:"spec,omitempty"` + Status FirstMateStatus `json:"status,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// FirstMateList contains a list of FirstMate +type FirstMateList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []FirstMate `json:"items"` +} + +func init() { + SchemeBuilder.Register(&FirstMate{}, &FirstMateList{}) +} diff --git a/cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/apis/crew/v1/register.go b/cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/apis/crew/v1/register.go new file mode 100644 index 0000000000..dca99b02ff --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/apis/crew/v1/register.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. +*/ + +// NOTE: Boilerplate only. Ignore this file. + +// Package v1 contains API Schema definitions for the crew v1 API group +// +k8s:openapi-gen=true +// +k8s:deepcopy-gen=package,register +// +k8s:conversion-gen=sigs.k8s.io/controller-tools/test/pkg/apis/crew +// +k8s:defaulter-gen=TypeMeta +// +groupName=crew.k8s.io +package v1 + +import ( + "k8s.io/apimachinery/pkg/runtime/schema" + "sigs.k8s.io/controller-runtime/pkg/runtime/scheme" +) + +var ( + // SchemeGroupVersion is group version used to register these objects + SchemeGroupVersion = schema.GroupVersion{Group: "crew.k8s.io", Version: "v1"} + + // SchemeBuilder is used to add go types to the GroupVersionKind scheme + SchemeBuilder = &scheme.Builder{GroupVersion: SchemeGroupVersion} +) diff --git a/cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/apis/ship/group.go b/cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/apis/ship/group.go new file mode 100644 index 0000000000..9b058ab24c --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/apis/ship/group.go @@ -0,0 +1,18 @@ +/* +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 ship contains ship API versions +package ship diff --git a/cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/apis/ship/v1beta1/doc.go b/cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/apis/ship/v1beta1/doc.go new file mode 100644 index 0000000000..8a42f5698d --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/apis/ship/v1beta1/doc.go @@ -0,0 +1,23 @@ +/* +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 v1beta1 contains API Schema definitions for the ship v1beta1 API group +// +k8s:openapi-gen=true +// +k8s:deepcopy-gen=package,register +// +k8s:conversion-gen=sigs.k8s.io/controller-tools/test/pkg/apis/ship +// +k8s:defaulter-gen=TypeMeta +// +groupName=ship.k8s.io +package v1beta1 diff --git a/cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/apis/ship/v1beta1/frigate_types.go b/cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/apis/ship/v1beta1/frigate_types.go new file mode 100644 index 0000000000..4c4f72f169 --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/apis/ship/v1beta1/frigate_types.go @@ -0,0 +1,62 @@ +/* +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 v1beta1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! +// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. + +// FrigateSpec defines the desired state of Frigate +type FrigateSpec struct { + // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster + // Important: Run "kubebuilder generate" to regenerate code after modifying this file +} + +// FrigateStatus defines the observed state of Frigate +type FrigateStatus struct { + // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster + // Important: Run "kubebuilder generate" to regenerate code after modifying this file +} + +// +genclient +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// Frigate is the Schema for the frigates API +// +k8s:openapi-gen=true +type Frigate struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec FrigateSpec `json:"spec,omitempty"` + Status FrigateStatus `json:"status,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// FrigateList contains a list of Frigate +type FrigateList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []Frigate `json:"items"` +} + +func init() { + SchemeBuilder.Register(&Frigate{}, &FrigateList{}) +} diff --git a/cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/apis/ship/v1beta1/register.go b/cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/apis/ship/v1beta1/register.go new file mode 100644 index 0000000000..c8d5eb64ca --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/apis/ship/v1beta1/register.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. +*/ + +// NOTE: Boilerplate only. Ignore this file. + +// Package v1beta1 contains API Schema definitions for the ship v1beta1 API group +// +k8s:openapi-gen=true +// +k8s:deepcopy-gen=package,register +// +k8s:conversion-gen=sigs.k8s.io/controller-tools/test/pkg/apis/ship +// +k8s:defaulter-gen=TypeMeta +// +groupName=ship.k8s.io +package v1beta1 + +import ( + "k8s.io/apimachinery/pkg/runtime/schema" + "sigs.k8s.io/controller-runtime/pkg/runtime/scheme" +) + +var ( + // SchemeGroupVersion is group version used to register these objects + SchemeGroupVersion = schema.GroupVersion{Group: "ship.k8s.io", Version: "v1beta1"} + + // SchemeBuilder is used to add go types to the GroupVersionKind scheme + SchemeBuilder = &scheme.Builder{GroupVersion: SchemeGroupVersion} +) diff --git a/cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/controller/add_firstmate.go b/cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/controller/add_firstmate.go new file mode 100644 index 0000000000..bcd55295b3 --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/controller/add_firstmate.go @@ -0,0 +1,26 @@ +/* +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 ( + "sigs.k8s.io/controller-tools/test/pkg/controller/firstmate" +) + +func init() { + // AddToManagerFuncs is a list of functions to create controllers and add them to a manager. + AddToManagerFuncs = append(AddToManagerFuncs, firstmate.Add) +} diff --git a/cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/controller/add_frigate.go b/cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/controller/add_frigate.go new file mode 100644 index 0000000000..841085a067 --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/controller/add_frigate.go @@ -0,0 +1,26 @@ +/* +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 ( + "sigs.k8s.io/controller-tools/test/pkg/controller/frigate" +) + +func init() { + // AddToManagerFuncs is a list of functions to create controllers and add them to a manager. + AddToManagerFuncs = append(AddToManagerFuncs, frigate.Add) +} diff --git a/cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/controller/add_kraken.go b/cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/controller/add_kraken.go new file mode 100644 index 0000000000..98ae5c49bc --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/controller/add_kraken.go @@ -0,0 +1,26 @@ +/* +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 ( + "sigs.k8s.io/controller-tools/test/pkg/controller/kraken" +) + +func init() { + // AddToManagerFuncs is a list of functions to create controllers and add them to a manager. + AddToManagerFuncs = append(AddToManagerFuncs, kraken.Add) +} diff --git a/cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/controller/add_namespace.go b/cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/controller/add_namespace.go new file mode 100644 index 0000000000..f370b4ae10 --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/controller/add_namespace.go @@ -0,0 +1,26 @@ +/* +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 ( + "sigs.k8s.io/controller-tools/test/pkg/controller/namespace" +) + +func init() { + // AddToManagerFuncs is a list of functions to create controllers and add them to a manager. + AddToManagerFuncs = append(AddToManagerFuncs, namespace.Add) +} diff --git a/cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/controller/controller.go b/cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/controller/controller.go new file mode 100644 index 0000000000..a0de255630 --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/controller/controller.go @@ -0,0 +1,34 @@ +/* +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 ( + "sigs.k8s.io/controller-runtime/pkg/manager" +) + +// AddToManagerFuncs is a list of functions to add all Controllers to the Manager +var AddToManagerFuncs []func(manager.Manager) error + +// AddToManager adds all Controllers to the Manager +func AddToManager(m manager.Manager) error { + for _, f := range AddToManagerFuncs { + if err := f(m); err != nil { + return err + } + } + return nil +} diff --git a/cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/controller/firstmate/firstmate_controller.go b/cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/controller/firstmate/firstmate_controller.go new file mode 100644 index 0000000000..121ab63574 --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/controller/firstmate/firstmate_controller.go @@ -0,0 +1,165 @@ +/* +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 firstmate + +import ( + "context" + "log" + "reflect" + + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + "sigs.k8s.io/controller-runtime/pkg/handler" + "sigs.k8s.io/controller-runtime/pkg/manager" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + "sigs.k8s.io/controller-runtime/pkg/source" + crewv1 "sigs.k8s.io/controller-tools/test/pkg/apis/crew/v1" +) + +/** +* USER ACTION REQUIRED: This is a scaffold file intended for the user to modify with their own Controller +* business logic. Delete these comments after modifying this file.* + */ + +// Add creates a new FirstMate Controller and adds it to the Manager. The Manager will set fields on the Controller +// and Start it when the Manager is Started. +// USER ACTION REQUIRED: update cmd/manager/main.go to call this crew.Add(mgr) to install this Controller +func Add(mgr manager.Manager) error { + return add(mgr, newReconciler(mgr)) +} + +// newReconciler returns a new reconcile.Reconciler +func newReconciler(mgr manager.Manager) reconcile.Reconciler { + return &ReconcileFirstMate{Client: mgr.GetClient(), scheme: mgr.GetScheme()} +} + +// add adds a new Controller to mgr with r as the reconcile.Reconciler +func add(mgr manager.Manager, r reconcile.Reconciler) error { + // Create a new controller + c, err := controller.New("firstmate-controller", mgr, controller.Options{Reconciler: r}) + if err != nil { + return err + } + + // Watch for changes to FirstMate + err = c.Watch(&source.Kind{Type: &crewv1.FirstMate{}}, &handler.EnqueueRequestForObject{}) + if err != nil { + return err + } + + // TODO(user): Modify this to be the types you create + // Uncomment watch a Deployment created by FirstMate - change this for objects you create + err = c.Watch(&source.Kind{Type: &appsv1.Deployment{}}, &handler.EnqueueRequestForOwner{ + IsController: true, + OwnerType: &crewv1.FirstMate{}, + }) + if err != nil { + return err + } + + return nil +} + +var _ reconcile.Reconciler = &ReconcileFirstMate{} + +// ReconcileFirstMate reconciles a FirstMate object +type ReconcileFirstMate struct { + client.Client + scheme *runtime.Scheme +} + +// Reconcile reads that state of the cluster for a FirstMate object and makes changes based on the state read +// and what is in the FirstMate.Spec +// TODO(user): Modify this Reconcile function to implement your Controller logic. The scaffolding writes +// a Deployment as an example +// Automatically generate RBAC rules to allow the Controller to read and write Deployments +// +rbac:groups=apps,resources=deployments,verbs=get;list;watch;create;update;patch;delete +func (r *ReconcileFirstMate) Reconcile(request reconcile.Request) (reconcile.Result, error) { + // Fetch the FirstMate instance + instance := &crewv1.FirstMate{} + err := r.Get(context.TODO(), request.NamespacedName, instance) + if err != nil { + if errors.IsNotFound(err) { + // Object not found, return. Created objects are automatically garbage collected. + // For additional cleanup logic use finalizers. + return reconcile.Result{}, nil + } + // Error reading the object - requeue the request. + return reconcile.Result{}, err + } + + // TODO(user): Change this to be the object type created by your controller + // Define the desired Deployment object + deploy := &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: instance.Name + "-deployment", + Namespace: instance.Namespace, + }, + Spec: appsv1.DeploymentSpec{ + Selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{"deployment": instance.Name + "-deployment"}, + }, + Template: corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"deployment": instance.Name + "-deployment"}}, + Spec: corev1.PodSpec{ + Containers: []corev1.Container{ + { + Name: "nginx", + Image: "nginx", + }, + }, + }, + }, + }, + } + if err := controllerutil.SetControllerReference(instance, deploy, r.scheme); err != nil { + return reconcile.Result{}, err + } + + // TODO(user): Change this for the object type created by your controller + // Check if the Deployment already exists + found := &appsv1.Deployment{} + err = r.Get(context.TODO(), types.NamespacedName{Name: deploy.Name, Namespace: deploy.Namespace}, found) + if err != nil && errors.IsNotFound(err) { + log.Printf("Creating Deployment %s/%s\n", deploy.Namespace, deploy.Name) + err = r.Create(context.TODO(), deploy) + if err != nil { + return reconcile.Result{}, err + } + } else if err != nil { + return reconcile.Result{}, err + } + + // TODO(user): Change this for the object type created by your controller + // Update the found object and write the result back if there are any changes + if !reflect.DeepEqual(deploy.Spec, found.Spec) { + found.Spec = deploy.Spec + log.Printf("Updating Deployment %s/%s\n", deploy.Namespace, deploy.Name) + err = r.Update(context.TODO(), found) + if err != nil { + return reconcile.Result{}, err + } + } + return reconcile.Result{}, nil +} diff --git a/cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/controller/frigate/frigate_controller.go b/cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/controller/frigate/frigate_controller.go new file mode 100644 index 0000000000..b2fe88eb43 --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/controller/frigate/frigate_controller.go @@ -0,0 +1,105 @@ +/* +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 frigate + +import ( + "context" + + appsv1 "k8s.io/api/apps/v1" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "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/reconcile" + "sigs.k8s.io/controller-runtime/pkg/source" + shipv1beta1 "sigs.k8s.io/controller-tools/test/pkg/apis/ship/v1beta1" +) + +/** +* USER ACTION REQUIRED: This is a scaffold file intended for the user to modify with their own Controller +* business logic. Delete these comments after modifying this file.* + */ + +// Add creates a new Frigate Controller and adds it to the Manager. The Manager will set fields on the Controller +// and Start it when the Manager is Started. +// USER ACTION REQUIRED: update cmd/manager/main.go to call this ship.Add(mgr) to install this Controller +func Add(mgr manager.Manager) error { + return add(mgr, newReconciler(mgr)) +} + +// newReconciler returns a new reconcile.Reconciler +func newReconciler(mgr manager.Manager) reconcile.Reconciler { + return &ReconcileFrigate{Client: mgr.GetClient(), scheme: mgr.GetScheme()} +} + +// add adds a new Controller to mgr with r as the reconcile.Reconciler +func add(mgr manager.Manager, r reconcile.Reconciler) error { + // Create a new controller + c, err := controller.New("frigate-controller", mgr, controller.Options{Reconciler: r}) + if err != nil { + return err + } + + // Watch for changes to Frigate + err = c.Watch(&source.Kind{Type: &shipv1beta1.Frigate{}}, &handler.EnqueueRequestForObject{}) + if err != nil { + return err + } + + // TODO(user): Modify this to be the types you create + // Uncomment watch a Deployment created by Frigate - change this for objects you create + err = c.Watch(&source.Kind{Type: &appsv1.Deployment{}}, &handler.EnqueueRequestForOwner{ + IsController: true, + OwnerType: &shipv1beta1.Frigate{}, + }) + if err != nil { + return err + } + + return nil +} + +var _ reconcile.Reconciler = &ReconcileFrigate{} + +// ReconcileFrigate reconciles a Frigate object +type ReconcileFrigate struct { + client.Client + scheme *runtime.Scheme +} + +// Reconcile reads that state of the cluster for a Frigate object and makes changes based on the state read +// and what is in the Frigate.Spec +// TODO(user): Modify this Reconcile function to implement your Controller logic. The scaffolding writes +// a Deployment as an example +func (r *ReconcileFrigate) Reconcile(request reconcile.Request) (reconcile.Result, error) { + // Fetch the Frigate instance + instance := &shipv1beta1.Frigate{} + err := r.Get(context.TODO(), request.NamespacedName, instance) + if err != nil { + if errors.IsNotFound(err) { + // Object not found, return. Created objects are automatically garbage collected. + // For additional cleanup logic use finalizers. + return reconcile.Result{}, nil + } + // Error reading the object - requeue the request. + return reconcile.Result{}, err + } + + return reconcile.Result{}, nil +} diff --git a/cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/controller/kraken/kraken_controller.go b/cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/controller/kraken/kraken_controller.go new file mode 100644 index 0000000000..a06eb51dad --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/controller/kraken/kraken_controller.go @@ -0,0 +1,105 @@ +/* +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 kraken + +import ( + "context" + + appsv1 "k8s.io/api/apps/v1" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "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/reconcile" + "sigs.k8s.io/controller-runtime/pkg/source" + creaturesv2alpha1 "sigs.k8s.io/controller-tools/test/pkg/apis/creatures/v2alpha1" +) + +/** +* USER ACTION REQUIRED: This is a scaffold file intended for the user to modify with their own Controller +* business logic. Delete these comments after modifying this file.* + */ + +// Add creates a new Kraken Controller and adds it to the Manager. The Manager will set fields on the Controller +// and Start it when the Manager is Started. +// USER ACTION REQUIRED: update cmd/manager/main.go to call this creatures.Add(mgr) to install this Controller +func Add(mgr manager.Manager) error { + return add(mgr, newReconciler(mgr)) +} + +// newReconciler returns a new reconcile.Reconciler +func newReconciler(mgr manager.Manager) reconcile.Reconciler { + return &ReconcileKraken{Client: mgr.GetClient(), scheme: mgr.GetScheme()} +} + +// add adds a new Controller to mgr with r as the reconcile.Reconciler +func add(mgr manager.Manager, r reconcile.Reconciler) error { + // Create a new controller + c, err := controller.New("kraken-controller", mgr, controller.Options{Reconciler: r}) + if err != nil { + return err + } + + // Watch for changes to Kraken + err = c.Watch(&source.Kind{Type: &creaturesv2alpha1.Kraken{}}, &handler.EnqueueRequestForObject{}) + if err != nil { + return err + } + + // TODO(user): Modify this to be the types you create + // Uncomment watch a Deployment created by Kraken - change this for objects you create + err = c.Watch(&source.Kind{Type: &appsv1.Deployment{}}, &handler.EnqueueRequestForOwner{ + IsController: true, + OwnerType: &creaturesv2alpha1.Kraken{}, + }) + if err != nil { + return err + } + + return nil +} + +var _ reconcile.Reconciler = &ReconcileKraken{} + +// ReconcileKraken reconciles a Kraken object +type ReconcileKraken struct { + client.Client + scheme *runtime.Scheme +} + +// Reconcile reads that state of the cluster for a Kraken object and makes changes based on the state read +// and what is in the Kraken.Spec +// TODO(user): Modify this Reconcile function to implement your Controller logic. The scaffolding writes +// a Deployment as an example +func (r *ReconcileKraken) Reconcile(request reconcile.Request) (reconcile.Result, error) { + // Fetch the Kraken instance + instance := &creaturesv2alpha1.Kraken{} + err := r.Get(context.TODO(), request.NamespacedName, instance) + if err != nil { + if errors.IsNotFound(err) { + // Object not found, return. Created objects are automatically garbage collected. + // For additional cleanup logic use finalizers. + return reconcile.Result{}, nil + } + // Error reading the object - requeue the request. + return reconcile.Result{}, err + } + + return reconcile.Result{}, nil +} diff --git a/cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/controller/namespace/namespace_controller.go b/cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/controller/namespace/namespace_controller.go new file mode 100644 index 0000000000..e56198d5ef --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/controller-tools/test/pkg/controller/namespace/namespace_controller.go @@ -0,0 +1,105 @@ +/* +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 namespace + +import ( + "context" + + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "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/reconcile" + "sigs.k8s.io/controller-runtime/pkg/source" +) + +/** +* USER ACTION REQUIRED: This is a scaffold file intended for the user to modify with their own Controller +* business logic. Delete these comments after modifying this file.* + */ + +// Add creates a new Namespace Controller and adds it to the Manager. The Manager will set fields on the Controller +// and Start it when the Manager is Started. +// USER ACTION REQUIRED: update cmd/manager/main.go to call this core.Add(mgr) to install this Controller +func Add(mgr manager.Manager) error { + return add(mgr, newReconciler(mgr)) +} + +// newReconciler returns a new reconcile.Reconciler +func newReconciler(mgr manager.Manager) reconcile.Reconciler { + return &ReconcileNamespace{Client: mgr.GetClient(), scheme: mgr.GetScheme()} +} + +// add adds a new Controller to mgr with r as the reconcile.Reconciler +func add(mgr manager.Manager, r reconcile.Reconciler) error { + // Create a new controller + c, err := controller.New("namespace-controller", mgr, controller.Options{Reconciler: r}) + if err != nil { + return err + } + + // Watch for changes to Namespace + err = c.Watch(&source.Kind{Type: &corev1.Namespace{}}, &handler.EnqueueRequestForObject{}) + if err != nil { + return err + } + + // TODO(user): Modify this to be the types you create + // Uncomment watch a Deployment created by Namespace - change this for objects you create + err = c.Watch(&source.Kind{Type: &appsv1.Deployment{}}, &handler.EnqueueRequestForOwner{ + IsController: true, + OwnerType: &corev1.Namespace{}, + }) + if err != nil { + return err + } + + return nil +} + +var _ reconcile.Reconciler = &ReconcileNamespace{} + +// ReconcileNamespace reconciles a Namespace object +type ReconcileNamespace struct { + client.Client + scheme *runtime.Scheme +} + +// Reconcile reads that state of the cluster for a Namespace object and makes changes based on the state read +// and what is in the Namespace.Spec +// TODO(user): Modify this Reconcile function to implement your Controller logic. The scaffolding writes +// a Deployment as an example +func (r *ReconcileNamespace) Reconcile(request reconcile.Request) (reconcile.Result, error) { + // Fetch the Namespace instance + instance := &corev1.Namespace{} + err := r.Get(context.TODO(), request.NamespacedName, instance) + if err != nil { + if errors.IsNotFound(err) { + // Object not found, return. Created objects are automatically garbage collected. + // For additional cleanup logic use finalizers. + return reconcile.Result{}, nil + } + // Error reading the object - requeue the request. + return reconcile.Result{}, err + } + + return reconcile.Result{}, nil +}